Skip to content

Commit b8ff3d5

Browse files
authored
fix(ai-sdk): nest agent spans attribution (#844)
1 parent 5986ea1 commit b8ff3d5

File tree

7 files changed

+683
-58
lines changed

7 files changed

+683
-58
lines changed

packages/sample-app/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"run:vercel_tools": "npm run build && node dist/src/sample_vercel_ai_tools.js",
2323
"run:vercel_agent": "npm run build && node dist/src/sample_vercel_ai_agent.js",
2424
"run:vercel_agent_simple": "npm run build && node dist/src/sample_vercel_ai_agent_simple.js",
25+
"run:nested_agents": "npm run build && node dist/src/sample_nested_agents.js",
2526
"run:sample_vision": "npm run build && node dist/src/sample_vision_prompt.js",
2627
"run:sample_azure": "npm run build && node dist/src/sample_azure.js",
2728
"run:openai_streaming": "npm run build && node dist/src/sample_openai_streaming.js",
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import * as traceloop from "@traceloop/node-server-sdk";
2+
import { openai } from "@ai-sdk/openai";
3+
import { generateText, tool } from "ai";
4+
import { z } from "zod";
5+
6+
import "dotenv/config";
7+
8+
traceloop.initialize({
9+
appName: "sample_nested_agents",
10+
disableBatch: true,
11+
});
12+
13+
const searchTool = tool({
14+
description: "Search for information on a topic",
15+
parameters: z.object({
16+
query: z.string().describe("Search query"),
17+
}),
18+
execute: async ({ query }) => {
19+
console.log(` [search_agent] Searching: ${query}`);
20+
await new Promise((r) => setTimeout(r, 100));
21+
return {
22+
results: [
23+
`Result 1 for "${query}": Found relevant information`,
24+
`Result 2 for "${query}": Additional context discovered`,
25+
],
26+
};
27+
},
28+
});
29+
30+
const searchAgentTool = tool({
31+
description: "Delegate search tasks to the search agent",
32+
parameters: z.object({
33+
searchQuery: z.string().describe("What to search for"),
34+
}),
35+
execute: async ({ searchQuery }) => {
36+
console.log(
37+
` [research_agent] Delegating to search_agent: ${searchQuery}`,
38+
);
39+
40+
const result = await generateText({
41+
model: openai("gpt-4o-mini"),
42+
prompt: `Search for: ${searchQuery}. Use the search tool and return results.`,
43+
tools: { searchTool },
44+
maxSteps: 3,
45+
experimental_telemetry: {
46+
isEnabled: true,
47+
metadata: { agent: "search_agent" },
48+
},
49+
});
50+
51+
return { searchResults: result.text };
52+
},
53+
});
54+
55+
const analyzeTool = tool({
56+
description: "Analyze data and extract insights",
57+
parameters: z.object({
58+
data: z.string().describe("Data to analyze"),
59+
}),
60+
execute: async ({ data }) => {
61+
console.log(` [analysis_agent] Analyzing data...`);
62+
await new Promise((r) => setTimeout(r, 100));
63+
return {
64+
insights: [`Key insight from analysis`, `Pattern detected in data`],
65+
confidence: 0.85,
66+
};
67+
},
68+
});
69+
70+
const analysisAgentTool = tool({
71+
description: "Delegate analysis tasks to the analysis agent",
72+
parameters: z.object({
73+
dataToAnalyze: z.string().describe("Data to analyze"),
74+
}),
75+
execute: async ({ dataToAnalyze }) => {
76+
console.log(
77+
` [research_agent] Delegating to analysis_agent: ${dataToAnalyze.substring(0, 50)}...`,
78+
);
79+
80+
const result = await generateText({
81+
model: openai("gpt-4o-mini"),
82+
prompt: `Analyze this data: ${dataToAnalyze}. Use the analyze tool.`,
83+
tools: { analyzeTool },
84+
maxSteps: 3,
85+
experimental_telemetry: {
86+
isEnabled: true,
87+
metadata: { agent: "analysis_agent" },
88+
},
89+
});
90+
91+
return { analysis: result.text };
92+
},
93+
});
94+
95+
const researchAgentTool = tool({
96+
description: "Delegate research tasks to the research agent",
97+
parameters: z.object({
98+
topic: z.string().describe("Research topic"),
99+
}),
100+
execute: async ({ topic }) => {
101+
console.log(`[orchestrator] Delegating to research_agent: ${topic}`);
102+
103+
const result = await generateText({
104+
model: openai("gpt-4o-mini"),
105+
prompt: `Research the topic: "${topic}".
106+
1. First use the search agent to find information
107+
2. Then use the analysis agent to analyze findings
108+
Return a research summary.`,
109+
tools: { searchAgentTool, analysisAgentTool },
110+
maxSteps: 5,
111+
experimental_telemetry: {
112+
isEnabled: true,
113+
metadata: { agent: "research_agent" },
114+
},
115+
});
116+
117+
return { research: result.text };
118+
},
119+
});
120+
121+
const formatTool = tool({
122+
description: "Format text into a summary",
123+
parameters: z.object({
124+
content: z.string().describe("Content to format"),
125+
}),
126+
execute: async ({ content }) => {
127+
console.log(` [summary_agent] Formatting summary...`);
128+
await new Promise((r) => setTimeout(r, 100));
129+
return { formatted: `=== SUMMARY ===\n${content}\n===============` };
130+
},
131+
});
132+
133+
const summaryAgentTool = tool({
134+
description: "Delegate summarization to the summary agent",
135+
parameters: z.object({
136+
contentToSummarize: z.string().describe("Content to summarize"),
137+
}),
138+
execute: async ({ contentToSummarize }) => {
139+
console.log(`[orchestrator] Delegating to summary_agent`);
140+
141+
const result = await generateText({
142+
model: openai("gpt-4o-mini"),
143+
prompt: `Summarize this content concisely: ${contentToSummarize}. Use the format tool.`,
144+
tools: { formatTool },
145+
maxSteps: 3,
146+
experimental_telemetry: {
147+
isEnabled: true,
148+
metadata: { agent: "summary_agent" },
149+
},
150+
});
151+
152+
return { summary: result.text };
153+
},
154+
});
155+
156+
async function runNestedAgents() {
157+
console.log("\n" + "=".repeat(60));
158+
console.log("NESTED AGENTS DEMO");
159+
console.log("=".repeat(60));
160+
console.log("Agent hierarchy:");
161+
console.log(" orchestrator_agent");
162+
console.log(" -> research_agent");
163+
console.log(" -> search_agent");
164+
console.log(" -> analysis_agent");
165+
console.log(" -> summary_agent");
166+
console.log("=".repeat(60) + "\n");
167+
168+
const result = await traceloop.withWorkflow(
169+
{ name: "nested_agents_demo" },
170+
async () => {
171+
return await generateText({
172+
model: openai("gpt-4o-mini"),
173+
prompt: `You are an orchestrator agent. Your task:
174+
1. Use the research agent to research "AI observability best practices"
175+
2. Use the summary agent to create a final summary
176+
Be brief in your responses.`,
177+
tools: { researchAgentTool, summaryAgentTool },
178+
maxSteps: 5,
179+
experimental_telemetry: {
180+
isEnabled: true,
181+
metadata: { agent: "orchestrator_agent" },
182+
},
183+
});
184+
},
185+
);
186+
187+
console.log("\n" + "=".repeat(60));
188+
console.log("RESULT");
189+
console.log("=".repeat(60));
190+
console.log(result.text);
191+
console.log("=".repeat(60) + "\n");
192+
}
193+
194+
runNestedAgents().catch(console.error);

0 commit comments

Comments
 (0)