opper-node-agents

📁 opper-ai/opper-skills 📅 11 days ago
8
总安装量
5
周安装量
#35192
全站排名
安装命令
npx skills add https://github.com/opper-ai/opper-skills --skill opper-node-agents

Agent 安装分布

codex 4
opencode 4
pi 3
claude-code 3
qwen-code 2
crush 2

Skill 文档

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