opper-node-agents

Use the Opper TypeScript Agent SDK (@opperai/agents) to build AI agents with think-act reasoning loops, tool use via createFunctionTool or @tool decorator, Zod schema validation, multi-agent composition, MCP integration, streaming, and hooks for observability. Activate when building TypeScript AI agents, autonomous systems, or tool-using reasoning loops with the Opper platform.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "opper-node-agents" with this command: npx skills add opper-ai/opper-skills/opper-ai-opper-skills-opper-node-agents

Opper Node Agents

Build type-safe AI agents in TypeScript with think-act reasoning loops, Zod-validated tools, multi-agent composition, streaming, and full observability.

Installation

npm install @opperai/agents
# or: pnpm add @opperai/agents / yarn add @opperai/agents

Prerequisites: Node.js 20+

Set your API key:

export OPPER_API_KEY="your-api-key"

Get your API key from platform.opper.ai.

Core Pattern: Agent with Tools

Define tools with createFunctionTool, create an agent, and run it:

import { Agent, createFunctionTool } from "@opperai/agents";
import { z } from "zod";

const getWeather = createFunctionTool(
  (input: { city: string }) => `The weather in ${input.city} is 22°C and sunny`,
  { name: "get_weather", schema: z.object({ city: z.string() }) },
);

const getPopulation = createFunctionTool(
  (input: { city: string }) => {
    const pops: Record<string, number> = { Paris: 2_161_000, London: 8_982_000 };
    return pops[input.city] ?? 0;
  },
  { name: "get_population", schema: z.object({ city: z.string() }) },
);

const agent = new Agent<string, { answer: string }>({
  name: "CityBot",
  instructions: "Help users with city information using available tools.",
  tools: [getWeather, getPopulation],
  outputSchema: z.object({ answer: z.string() }),
});

const { result, usage } = await agent.run("What's the weather and population of Paris?");
console.log(result.answer);
console.log(usage); // { requests, inputTokens, outputTokens, totalTokens }

How the Agent Loop Works

The agent follows a Think-Act-Observe loop:

  1. Think: The LLM analyzes the goal and available tools
  2. Act: It selects and executes a tool with validated input
  3. Observe: Results are added to the execution history
  4. Loop/Return: Repeat until the goal is met, then return validated output

The loop runs up to maxIterations times (default: 25).

Structured Output with Zod

Use Zod schemas for compile-time and runtime type safety:

import { z } from "zod";

const CityReport = z.object({
  city: z.string(),
  temperature_c: z.number(),
  population: z.number(),
  summary: z.string().describe("One-sentence summary"),
});

type CityReportType = z.infer<typeof CityReport>;

const agent = new Agent<string, CityReportType>({
  name: "CityReporter",
  instructions: "Generate a city report using available tools.",
  tools: [getWeather, getPopulation],
  outputSchema: CityReport,
});

const { result } = await agent.run("Report on London");
// result is fully typed as CityReportType
console.log(result.city);          // "London"
console.log(result.temperature_c); // 18.0

Model Selection

Specify which LLM the agent uses for reasoning:

const agent = new Agent({
  name: "SmartAgent",
  instructions: "You are a helpful assistant.",
  tools: [myTool],
  model: "anthropic/claude-4-sonnet",
});

// With fallback chain
const agent = new Agent({
  name: "ResilientAgent",
  instructions: "You are a helpful assistant.",
  tools: [myTool],
  model: ["anthropic/claude-4-sonnet", "openai/gpt-4o"],
});

Decorator-Based Tools

Use the class-based @tool decorator pattern:

import { tool, extractTools } from "@opperai/agents";
import { z } from "zod";

class MathTools {
  @tool({ schema: z.object({ a: z.number(), b: z.number() }) })
  add({ a, b }: { a: number; b: number }) {
    return a + b;
  }

  @tool({ schema: z.object({ a: z.number(), b: z.number() }) })
  multiply({ a, b }: { a: number; b: number }) {
    return a * b;
  }
}

const tools = extractTools(new MathTools());
const agent = new Agent({
  name: "Calculator",
  instructions: "Use math tools to compute.",
  tools,
  outputSchema: z.object({ answer: z.number() }),
});

Multi-Agent Composition

Use agents as tools within other agents:

const mathAgent = new Agent<string, { answer: number }>({
  name: "MathAgent",
  instructions: "Solve math problems step by step.",
  tools: [add, multiply],
  outputSchema: z.object({ answer: z.number() }),
});

const researchAgent = new Agent<string, { answer: string }>({
  name: "ResearchAgent",
  instructions: "Answer factual questions.",
  tools: [searchWeb],
  outputSchema: z.object({ answer: z.string() }),
});

const coordinator = new Agent<string, string>({
  name: "Coordinator",
  instructions: "Delegate tasks to specialist agents.",
  tools: [mathAgent.asTool("math"), researchAgent.asTool("research")],
});

const { result, usage } = await coordinator.run("What is 15 * 23?");
// usage includes aggregated stats from child agents

Streaming

Enable real-time token streaming:

const agent = new Agent({
  name: "StreamingAgent",
  instructions: "Answer questions.",
  enableStreaming: true,
  outputSchema: z.object({ answer: z.string() }),
  onStreamStart: ({ callType }) => console.log(`[start] ${callType}`),
  onStreamChunk: ({ callType, accumulated }) => {
    if (callType === "final_result") {
      process.stdout.write(accumulated);
    }
  },
});

const { result } = await agent.run("Explain quantum computing");

MCP Integration

Connect to MCP servers for external tools:

import { mcp, MCPconfig, Agent } from "@opperai/agents";

const fsServer = MCPconfig({
  name: "filesystem",
  transport: "stdio",
  command: "npx",
  args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
});

const agent = new Agent<string, string>({
  name: "FileAgent",
  instructions: "Use filesystem tools to manage files.",
  tools: [mcp(fsServer)],
});

Hooks

Monitor agent lifecycle events:

import { HookEvents } from "@opperai/agents";

agent.registerHook(HookEvents.AgentStart, ({ context }) => {
  console.log(`Starting with goal: ${context.goal}`);
});

agent.registerHook(HookEvents.BeforeTool, ({ tool, input, toolCallId }) => {
  console.log(`[${toolCallId}] Calling ${tool.name}`);
});

agent.registerHook(HookEvents.AfterTool, ({ tool, result, record }) => {
  console.log(`[${record.id}] ${tool.name} returned: ${result.success}`);
});

agent.registerHook(HookEvents.AgentEnd, ({ context }) => {
  console.log(`Done. Tokens used: ${context.usage.totalTokens}`);
});

Tool hooks include a toolCallId to correlate tool:before with tool:after/tool:error events. See references/HOOKS.md for all events and payloads.

Common Mistakes

  • Forgetting await: agent.run() and agent.process() are async. Always use await.
  • Missing tool descriptions: Tools need clear names and Zod schemas so the LLM knows when/how to use them.
  • No outputSchema: Without it, the agent returns unstructured strings. Use Zod schemas for reliable typed output.
  • Too many tools: Keep tools focused (5-10 per agent). Use composition for more capabilities.

Additional Resources

Related Skills

  • opper-node-sdk: Use for single-shot task completion without agent loops — simpler when you don't need multi-step reasoning.
  • opper-python-agents: Use when building agents in Python instead of TypeScript.

Upstream Sources

When this skill's content may be outdated, resolve using this priority:

  1. Installed package source — check the user's project first, as it reflects the exact version in use: node_modules/@opperai/agents/
  2. Source code: https://github.com/opper-ai/opperai-agent-sdk-node
  3. Documentation: https://docs.opper.ai

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

opper-cli

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

opper-python-sdk

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

opper-python-agents

No summary provided by upstream source.

Repository SourceNeeds Review