opper-node-agents
npx skills add https://github.com/opper-ai/opper-skills --skill opper-node-agents
Agent 安装分布
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:
- Think: The LLM analyzes the goal and available tools
- Act: It selects and executes a tool with validated input
- Observe: Results are added to the execution history
- 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()andagent.process()are async. Always useawait. - 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
- For hook events and payloads, see references/HOOKS.md
- For advanced tool patterns, see references/TOOLS.md
- For MCP server configuration, see references/MCP.md
- For multi-agent composition patterns, see references/COMPOSITION.md
- For streaming events and patterns, see references/STREAMING.md
- For migrating from OpenRouter, see references/MIGRATION.md
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:
- Installed package source â check the user’s project first, as it reflects the exact version in use:
node_modules/@opperai/agents/ - Source code: https://github.com/opper-ai/opperai-agent-sdk-node
- Documentation: https://docs.opper.ai