@opperai/agents 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -48,10 +48,13 @@ const agent = new Agent<string, OutputType>({
48
48
  outputSchema: Output,
49
49
  });
50
50
 
51
- const result = await agent.process("Say hi to Ada");
52
- // => { message: "Hi Ada!" }
51
+ const { result, usage } = await agent.run("Say hi to Ada");
52
+ // result => { message: "Hi Ada!" }
53
+ // usage => { requests, inputTokens, outputTokens, totalTokens }
53
54
  ```
54
55
 
56
+ > **Note:** `agent.process(input)` also works if you only need the result without usage stats.
57
+
55
58
  ## Tools
56
59
 
57
60
  Define tools with Zod schemas. Results are discriminated unions that never throw.
@@ -72,7 +75,7 @@ const agent = new Agent<string, { answer: number }>({
72
75
  outputSchema: z.object({ answer: z.number() }),
73
76
  });
74
77
 
75
- const res = await agent.process("What is (5 + 3)? Return JSON with answer.");
78
+ const { result } = await agent.run("What is (5 + 3)? Return JSON with answer.");
76
79
  ```
77
80
 
78
81
  Decorator tools and extraction:
@@ -111,9 +114,10 @@ const Coordinator = new Agent<string, string>({
111
114
  tools: [Summarize.asTool("summarize")],
112
115
  });
113
116
 
114
- const answer = await Coordinator.process(
117
+ const { result, usage } = await Coordinator.run(
115
118
  "Summarize: Opper helps you build agents.",
116
119
  );
120
+ // usage includes aggregated stats from nested Summarize agent
117
121
  ```
118
122
 
119
123
  ## MCP Integration
@@ -131,7 +135,7 @@ const agent = new Agent<string, string>({
131
135
  tools: [mcp(fsServer)],
132
136
  });
133
137
 
134
- const out = await agent.process("Read README.md and summarize it.");
138
+ const { result } = await agent.run("Read README.md and summarize it.");
135
139
  ```
136
140
 
137
141
  ## Hooks & Context
package/dist/index.cjs CHANGED
@@ -121,7 +121,8 @@ var init_tool = __esm({
121
121
  output,
122
122
  ...init.startedAt !== void 0 && { startedAt: init.startedAt },
123
123
  finishedAt: init.finishedAt ?? Date.now(),
124
- metadata: init.metadata ?? {}
124
+ metadata: init.metadata ?? {},
125
+ ...init.usage !== void 0 && { usage: init.usage }
125
126
  };
126
127
  exports.ToolResultSuccessSchema.parse(result);
127
128
  return result;
@@ -133,7 +134,8 @@ var init_tool = __esm({
133
134
  error,
134
135
  ...init.startedAt !== void 0 && { startedAt: init.startedAt },
135
136
  finishedAt: init.finishedAt ?? Date.now(),
136
- metadata: init.metadata ?? {}
137
+ metadata: init.metadata ?? {},
138
+ ...init.usage !== void 0 && { usage: init.usage }
137
139
  };
138
140
  exports.ToolResultFailureSchema.parse(result);
139
141
  return result;
@@ -188,14 +190,43 @@ var init_tool = __esm({
188
190
  var context_exports = {};
189
191
  __export(context_exports, {
190
192
  AgentContext: () => exports.AgentContext,
193
+ BaseUsageSchema: () => exports.BaseUsageSchema,
191
194
  ExecutionCycleSchema: () => exports.ExecutionCycleSchema,
192
- UsageSchema: () => exports.UsageSchema
195
+ UsageSchema: () => exports.UsageSchema,
196
+ addUsage: () => addUsage,
197
+ createEmptyUsage: () => createEmptyUsage
193
198
  });
194
- exports.UsageSchema = void 0; exports.ExecutionCycleSchema = void 0; exports.AgentContext = void 0;
199
+ function createEmptyUsage() {
200
+ return {
201
+ requests: 0,
202
+ inputTokens: 0,
203
+ outputTokens: 0,
204
+ totalTokens: 0,
205
+ cost: {
206
+ generation: 0,
207
+ platform: 0,
208
+ total: 0
209
+ }
210
+ };
211
+ }
212
+ function addUsage(a, b) {
213
+ return {
214
+ requests: a.requests + b.requests,
215
+ inputTokens: a.inputTokens + b.inputTokens,
216
+ outputTokens: a.outputTokens + b.outputTokens,
217
+ totalTokens: a.totalTokens + b.totalTokens,
218
+ cost: {
219
+ generation: a.cost.generation + b.cost.generation,
220
+ platform: a.cost.platform + b.cost.platform,
221
+ total: a.cost.total + b.cost.total
222
+ }
223
+ };
224
+ }
225
+ exports.BaseUsageSchema = void 0; exports.UsageSchema = void 0; exports.ExecutionCycleSchema = void 0; exports.AgentContext = void 0;
195
226
  var init_context = __esm({
196
227
  "src/base/context.ts"() {
197
228
  init_tool();
198
- exports.UsageSchema = zod.z.object({
229
+ exports.BaseUsageSchema = zod.z.object({
199
230
  requests: zod.z.number().int().nonnegative().default(0),
200
231
  inputTokens: zod.z.number().int().nonnegative().default(0),
201
232
  outputTokens: zod.z.number().int().nonnegative().default(0),
@@ -206,6 +237,13 @@ var init_context = __esm({
206
237
  total: zod.z.number().nonnegative().default(0)
207
238
  }).default({ generation: 0, platform: 0, total: 0 })
208
239
  });
240
+ exports.UsageSchema = exports.BaseUsageSchema.extend({
241
+ /**
242
+ * Optional breakdown of usage by source (agent name).
243
+ * Only present when nested agents are used.
244
+ */
245
+ breakdown: zod.z.record(zod.z.string(), zod.z.lazy(() => exports.BaseUsageSchema)).optional()
246
+ });
209
247
  exports.ExecutionCycleSchema = zod.z.object({
210
248
  iteration: zod.z.number().int().nonnegative(),
211
249
  thought: zod.z.unknown().nullable().optional(),
@@ -247,10 +285,42 @@ var init_context = __esm({
247
285
  generation: this.usage.cost.generation + next.cost.generation,
248
286
  platform: this.usage.cost.platform + next.cost.platform,
249
287
  total: this.usage.cost.total + next.cost.total
250
- }
288
+ },
289
+ // Preserve existing breakdown
290
+ ...this.usage.breakdown && { breakdown: this.usage.breakdown }
251
291
  };
252
292
  this.touch();
253
293
  }
294
+ /**
295
+ * Update usage with source tracking for nested agent aggregation.
296
+ * This method updates the total usage AND tracks it by source in the breakdown.
297
+ *
298
+ * @param source - The source name (typically the agent/tool name)
299
+ * @param delta - The usage to add
300
+ */
301
+ updateUsageWithSource(source, delta) {
302
+ this.updateUsage(delta);
303
+ if (!this.usage.breakdown) {
304
+ this.usage.breakdown = {};
305
+ }
306
+ const existing = this.usage.breakdown[source] ?? createEmptyUsage();
307
+ this.usage.breakdown[source] = addUsage(existing, delta);
308
+ }
309
+ /**
310
+ * Clean up the usage breakdown if it only contains the parent agent.
311
+ * This ensures breakdown is only present when there are nested agents.
312
+ *
313
+ * @param parentAgentName - The name of the parent agent to check for
314
+ */
315
+ cleanupBreakdownIfOnlyParent(parentAgentName) {
316
+ if (!this.usage.breakdown) {
317
+ return;
318
+ }
319
+ const sources = Object.keys(this.usage.breakdown);
320
+ if (sources.length === 1 && sources[0] === parentAgentName) {
321
+ delete this.usage.breakdown;
322
+ }
323
+ }
254
324
  addCycle(cycle) {
255
325
  const parsed = exports.ExecutionCycleSchema.parse(cycle);
256
326
  this.executionHistory.push(parsed);
@@ -296,6 +366,18 @@ var init_context = __esm({
296
366
  this.touch();
297
367
  }
298
368
  snapshot() {
369
+ const usageCopy = {
370
+ ...this.usage,
371
+ cost: { ...this.usage.cost },
372
+ ...this.usage.breakdown && {
373
+ breakdown: Object.fromEntries(
374
+ Object.entries(this.usage.breakdown).map(([key, value]) => [
375
+ key,
376
+ { ...value, cost: { ...value.cost } }
377
+ ])
378
+ )
379
+ }
380
+ };
299
381
  return {
300
382
  agentName: this.agentName,
301
383
  sessionId: this.sessionId,
@@ -303,7 +385,7 @@ var init_context = __esm({
303
385
  iteration: this.iteration,
304
386
  goal: this.goal,
305
387
  executionHistory: [...this.executionHistory],
306
- usage: { ...this.usage },
388
+ usage: usageCopy,
307
389
  toolCalls: [...this.toolCalls],
308
390
  metadata: { ...this.metadata },
309
391
  startedAt: this.startedAt,
@@ -490,82 +572,6 @@ var HookManager = class {
490
572
  };
491
573
  var createHookManager = (logger) => new HookManager(logger);
492
574
 
493
- // src/base/events.ts
494
- var AgentEvents = {
495
- StreamStart: HookEvents.StreamStart,
496
- StreamChunk: HookEvents.StreamChunk,
497
- StreamEnd: HookEvents.StreamEnd,
498
- StreamError: HookEvents.StreamError
499
- };
500
- var AgentEventEmitter = class {
501
- registry = /* @__PURE__ */ new Map();
502
- logger;
503
- constructor(logger) {
504
- this.logger = logger ?? getDefaultLogger();
505
- }
506
- on(event, listener) {
507
- const listeners = this.registry.get(event) ?? /* @__PURE__ */ new Set();
508
- listeners.add(listener);
509
- this.registry.set(event, listeners);
510
- return () => this.off(event, listener);
511
- }
512
- once(event, listener) {
513
- const wrapper = (payload) => {
514
- try {
515
- listener(payload);
516
- } finally {
517
- this.off(event, wrapper);
518
- }
519
- };
520
- return this.on(event, wrapper);
521
- }
522
- off(event, listener) {
523
- const listeners = this.registry.get(event);
524
- if (!listeners) {
525
- return;
526
- }
527
- listeners.delete(listener);
528
- if (listeners.size === 0) {
529
- this.registry.delete(event);
530
- }
531
- }
532
- emit(event, payload) {
533
- const listeners = Array.from(
534
- this.registry.get(event) ?? /* @__PURE__ */ new Set()
535
- );
536
- if (listeners.length === 0) {
537
- return;
538
- }
539
- for (const listener of listeners) {
540
- try {
541
- listener(payload);
542
- } catch (error) {
543
- this.logger.warn(`Agent event listener failed for "${event}"`, {
544
- event,
545
- error: error instanceof Error ? error.message : String(error)
546
- });
547
- }
548
- }
549
- }
550
- removeAllListeners(event) {
551
- if (event) {
552
- this.registry.delete(event);
553
- return;
554
- }
555
- this.registry.clear();
556
- }
557
- listenerCount(event) {
558
- if (event) {
559
- return this.registry.get(event)?.size ?? 0;
560
- }
561
- let total = 0;
562
- for (const listeners of this.registry.values()) {
563
- total += listeners.size;
564
- }
565
- return total;
566
- }
567
- };
568
-
569
575
  // src/base/agent.ts
570
576
  init_tool();
571
577
  function sanitizeId(name) {
@@ -950,10 +956,6 @@ var BaseAgent = class {
950
956
  * Hook manager for lifecycle events
951
957
  */
952
958
  hooks;
953
- /**
954
- * Event dispatcher for runtime events (notably streaming)
955
- */
956
- events;
957
959
  /**
958
960
  * Registry of available tools
959
961
  */
@@ -1008,7 +1010,6 @@ var BaseAgent = class {
1008
1010
  this.enableStreaming = config.enableStreaming ?? false;
1009
1011
  this.metadata = { ...config.metadata ?? {} };
1010
1012
  this.hooks = new HookManager();
1011
- this.events = new AgentEventEmitter();
1012
1013
  this.tools = /* @__PURE__ */ new Map();
1013
1014
  this.baseTools = /* @__PURE__ */ new Map();
1014
1015
  this.toolProviders = /* @__PURE__ */ new Set();
@@ -1059,11 +1060,37 @@ var BaseAgent = class {
1059
1060
  * Main entry point for agent execution.
1060
1061
  * Orchestrates lifecycle: context initialization, hook triggering, loop execution, teardown.
1061
1062
  *
1063
+ * **Note:** This method will be removed in a future update.
1064
+ * Consider using {@link run} instead, which returns both result and usage statistics.
1065
+ *
1062
1066
  * @param input - Input to process
1063
1067
  * @param parentSpanId - Optional parent span ID for tracing
1064
1068
  * @returns Processed output
1065
1069
  */
1066
1070
  async process(input, parentSpanId) {
1071
+ const { result } = await this.executeProcess(input, parentSpanId);
1072
+ return result;
1073
+ }
1074
+ /**
1075
+ * Process input and return both result and usage statistics.
1076
+ * This is the recommended method for agent execution.
1077
+ *
1078
+ * @param input - Input to process
1079
+ * @param parentSpanId - Optional parent span ID for tracing
1080
+ * @returns Object containing the result and usage statistics
1081
+ */
1082
+ async run(input, parentSpanId) {
1083
+ return this.executeProcess(input, parentSpanId);
1084
+ }
1085
+ /**
1086
+ * Internal method that executes the process and returns both result and usage.
1087
+ * This is the core implementation shared by process() and run().
1088
+ *
1089
+ * @param input - Input to process
1090
+ * @param parentSpanId - Optional parent span ID for tracing
1091
+ * @returns Object containing the result and usage statistics
1092
+ */
1093
+ async executeProcess(input, parentSpanId) {
1067
1094
  const validatedInput = this.inputSchema ? this.inputSchema.parse(input) : input;
1068
1095
  const context = await this.initializeContext(validatedInput, parentSpanId);
1069
1096
  try {
@@ -1075,7 +1102,8 @@ var BaseAgent = class {
1075
1102
  context,
1076
1103
  result: validatedOutput
1077
1104
  });
1078
- return validatedOutput;
1105
+ context.cleanupBreakdownIfOnlyParent(this.name);
1106
+ return { result: validatedOutput, usage: context.usage };
1079
1107
  } catch (error) {
1080
1108
  await this.triggerHook(HookEvents.AgentEnd, {
1081
1109
  context,
@@ -1165,6 +1193,8 @@ var BaseAgent = class {
1165
1193
  }
1166
1194
  /**
1167
1195
  * Convert this agent into a tool that can be used by other agents.
1196
+ * When used as a tool, the nested agent's usage statistics are propagated
1197
+ * back to the parent agent for aggregation.
1168
1198
  *
1169
1199
  * @param toolName - Optional custom name for the tool (defaults to agent name)
1170
1200
  * @param toolDescription - Optional custom description (defaults to agent description)
@@ -1184,8 +1214,8 @@ var BaseAgent = class {
1184
1214
  execute: async (input, executionContext) => {
1185
1215
  try {
1186
1216
  const parentSpanId = executionContext.spanId ?? executionContext.agentContext.parentSpanId ?? void 0;
1187
- const result = await this.process(input, parentSpanId);
1188
- return exports.ToolResultFactory.success(tool2.name, result);
1217
+ const { result, usage } = await this.run(input, parentSpanId);
1218
+ return exports.ToolResultFactory.success(tool2.name, result, { usage });
1189
1219
  } catch (error) {
1190
1220
  return exports.ToolResultFactory.failure(
1191
1221
  tool2.name,
@@ -1208,32 +1238,34 @@ var BaseAgent = class {
1208
1238
  }
1209
1239
  /**
1210
1240
  * Register an event listener.
1241
+ * This is equivalent to registerHook() - both methods use the unified hook system.
1211
1242
  *
1212
- * @param event - Event name
1243
+ * @param event - Event name (any HookEvents value)
1213
1244
  * @param listener - Listener callback
1214
1245
  * @returns Cleanup function to unregister the listener
1215
1246
  */
1216
1247
  on(event, listener) {
1217
- return this.events.on(event, listener);
1248
+ return this.hooks.on(event, listener);
1218
1249
  }
1219
1250
  /**
1220
1251
  * Register a one-time event listener that removes itself after the first call.
1252
+ * This is equivalent to calling registerHook() with a self-removing handler.
1221
1253
  *
1222
- * @param event - Event name
1254
+ * @param event - Event name (any HookEvents value)
1223
1255
  * @param listener - Listener callback
1224
1256
  * @returns Cleanup function (no-op once listener fires)
1225
1257
  */
1226
1258
  once(event, listener) {
1227
- return this.events.once(event, listener);
1259
+ return this.hooks.once(event, listener);
1228
1260
  }
1229
1261
  /**
1230
1262
  * Remove a previously registered event listener.
1231
1263
  *
1232
- * @param event - Event name
1264
+ * @param event - Event name (any HookEvents value)
1233
1265
  * @param listener - Listener callback to remove
1234
1266
  */
1235
1267
  off(event, listener) {
1236
- this.events.off(event, listener);
1268
+ this.hooks.off(event, listener);
1237
1269
  }
1238
1270
  /**
1239
1271
  * Trigger a hook event with a payload.
@@ -1249,15 +1281,6 @@ var BaseAgent = class {
1249
1281
  console.warn(`Hook error for event ${event}:`, error);
1250
1282
  }
1251
1283
  }
1252
- /**
1253
- * Emit a runtime event to listeners.
1254
- *
1255
- * @param event - Event name
1256
- * @param payload - Event payload
1257
- */
1258
- emitAgentEvent(event, payload) {
1259
- this.events.emit(event, payload);
1260
- }
1261
1284
  /**
1262
1285
  * Execute a tool with proper context, hooks, and error handling.
1263
1286
  *
@@ -1318,6 +1341,14 @@ var BaseAgent = class {
1318
1341
  finishedAt,
1319
1342
  metadata: {}
1320
1343
  });
1344
+ if (!result.success) {
1345
+ await this.triggerHook(HookEvents.ToolError, {
1346
+ context,
1347
+ tool: tool2,
1348
+ toolName: tool2.name,
1349
+ error: result.error
1350
+ });
1351
+ }
1321
1352
  await this.triggerHook(HookEvents.AfterTool, {
1322
1353
  context,
1323
1354
  tool: tool2,
@@ -1443,6 +1474,11 @@ var BaseAgent = class {
1443
1474
 
1444
1475
  // src/index.ts
1445
1476
  init_context();
1477
+
1478
+ // src/base/events.ts
1479
+ var AgentEvents = HookEvents;
1480
+
1481
+ // src/index.ts
1446
1482
  init_result();
1447
1483
  init_tool();
1448
1484
  var ThoughtSchema = zod.z.object({
@@ -1611,7 +1647,7 @@ var mergeSchemaDefaults = (schema, value) => {
1611
1647
 
1612
1648
  // package.json
1613
1649
  var package_default = {
1614
- version: "0.3.0"};
1650
+ version: "0.4.1"};
1615
1651
 
1616
1652
  // src/utils/version.ts
1617
1653
  var SDK_NAME = "@opperai/agents";
@@ -2281,7 +2317,7 @@ var Agent = class extends BaseAgent {
2281
2317
  model: this.model,
2282
2318
  ...context.parentSpanId && { parentSpanId: context.parentSpanId }
2283
2319
  });
2284
- context.updateUsage({
2320
+ context.updateUsageWithSource(this.name, {
2285
2321
  requests: 1,
2286
2322
  inputTokens: response.usage.inputTokens,
2287
2323
  outputTokens: response.usage.outputTokens,
@@ -2333,10 +2369,6 @@ var Agent = class extends BaseAgent {
2333
2369
  context,
2334
2370
  callType: "think"
2335
2371
  });
2336
- this.emitAgentEvent(HookEvents.StreamStart, {
2337
- context,
2338
- callType: "think"
2339
- });
2340
2372
  try {
2341
2373
  const streamResponse = await this.opperClient.stream({
2342
2374
  name: spanName,
@@ -2373,7 +2405,6 @@ var Agent = class extends BaseAgent {
2373
2405
  fieldBuffers: feedResult.snapshot
2374
2406
  };
2375
2407
  await this.triggerHook(HookEvents.StreamChunk, chunkPayload);
2376
- this.emitAgentEvent(HookEvents.StreamChunk, chunkPayload);
2377
2408
  }
2378
2409
  const fieldBuffers = assembler.snapshot();
2379
2410
  const endPayload = {
@@ -2382,7 +2413,6 @@ var Agent = class extends BaseAgent {
2382
2413
  fieldBuffers
2383
2414
  };
2384
2415
  await this.triggerHook(HookEvents.StreamEnd, endPayload);
2385
- this.emitAgentEvent(HookEvents.StreamEnd, endPayload);
2386
2416
  const finalize = assembler.finalize();
2387
2417
  let decision;
2388
2418
  if (finalize.type === "structured" && finalize.structured) {
@@ -2399,7 +2429,7 @@ var Agent = class extends BaseAgent {
2399
2429
  streamSpanId
2400
2430
  );
2401
2431
  if (!usageTracked) {
2402
- context.updateUsage({
2432
+ context.updateUsageWithSource(this.name, {
2403
2433
  requests: 1,
2404
2434
  inputTokens: 0,
2405
2435
  outputTokens: 0,
@@ -2444,11 +2474,6 @@ var Agent = class extends BaseAgent {
2444
2474
  callType: "think",
2445
2475
  error
2446
2476
  });
2447
- this.emitAgentEvent(HookEvents.StreamError, {
2448
- context,
2449
- callType: "think",
2450
- error
2451
- });
2452
2477
  this.logger.error("Think step failed", error);
2453
2478
  throw new Error(
2454
2479
  `Think step failed: ${error instanceof Error ? error.message : String(error)}`
@@ -2506,12 +2531,30 @@ The memory you write persists across all process() calls on this agent.`;
2506
2531
  * Build dynamic context for the think step
2507
2532
  */
2508
2533
  async buildThinkContext(input, context) {
2509
- const availableTools = Array.from(this.tools.values()).map((tool2) => ({
2510
- name: tool2.name,
2511
- description: tool2.description || "",
2512
- // Convert Zod schema to JSON Schema for LLM consumption
2513
- parameters: tool2.schema ? schemaToJson(tool2.schema) : {}
2514
- }));
2534
+ const availableTools = Array.from(this.tools.values()).map((tool2) => {
2535
+ let parameters = {};
2536
+ if (tool2.schema) {
2537
+ parameters = schemaToJson(tool2.schema);
2538
+ } else if (tool2.metadata?.["parameters"] && typeof tool2.metadata["parameters"] === "object") {
2539
+ parameters = tool2.metadata["parameters"];
2540
+ }
2541
+ let returns = void 0;
2542
+ if (tool2.outputSchema) {
2543
+ returns = schemaToJson(tool2.outputSchema);
2544
+ } else if (tool2.metadata?.["outputSchema"] && typeof tool2.metadata["outputSchema"] === "object") {
2545
+ returns = tool2.metadata["outputSchema"];
2546
+ }
2547
+ return {
2548
+ name: tool2.name,
2549
+ description: tool2.description || "",
2550
+ // Include parameters (from Zod schema or MCP metadata)
2551
+ parameters,
2552
+ // Include output schema if defined (helps LLM understand what tool returns)
2553
+ ...returns !== void 0 ? { returns } : {},
2554
+ // Include examples if defined (helps LLM understand expected behavior)
2555
+ ...tool2.examples ? { examples: tool2.examples } : {}
2556
+ };
2557
+ });
2515
2558
  const executionHistory = context.getLastNCycles(3).map((cycle) => {
2516
2559
  const thought = typeof cycle.thought === "object" && cycle.thought !== null ? cycle.thought["reasoning"] || "" : String(cycle.thought || "");
2517
2560
  const results = Array.isArray(cycle.results) ? cycle.results.map((r) => {
@@ -2581,6 +2624,9 @@ The memory you write persists across all process() calls on this agent.`;
2581
2624
  context,
2582
2625
  { spanId: toolSpan.id }
2583
2626
  );
2627
+ if (result.usage) {
2628
+ context.updateUsageWithSource(toolCall.toolName, result.usage);
2629
+ }
2584
2630
  const endTime = /* @__PURE__ */ new Date();
2585
2631
  const durationMs = endTime.getTime() - startTime.getTime();
2586
2632
  if (result.success) {
@@ -2839,7 +2885,7 @@ Follow any instructions provided for formatting and style.`;
2839
2885
  callOptions.outputSchema = this.outputSchema;
2840
2886
  }
2841
2887
  const response = await this.opperClient.call(callOptions);
2842
- context.updateUsage({
2888
+ context.updateUsageWithSource(this.name, {
2843
2889
  requests: 1,
2844
2890
  inputTokens: response.usage.inputTokens,
2845
2891
  outputTokens: response.usage.outputTokens,
@@ -2869,10 +2915,6 @@ Follow any instructions provided for formatting and style.`;
2869
2915
  context,
2870
2916
  callType: "final_result"
2871
2917
  });
2872
- this.emitAgentEvent(HookEvents.StreamStart, {
2873
- context,
2874
- callType: "final_result"
2875
- });
2876
2918
  try {
2877
2919
  const sanitizedName = this.name.toLowerCase().replace(/[\s-]/g, "_");
2878
2920
  const functionName = `generate_final_result_${sanitizedName}`;
@@ -2911,7 +2953,6 @@ Follow any instructions provided for formatting and style.`;
2911
2953
  fieldBuffers: feedResult.snapshot
2912
2954
  };
2913
2955
  await this.triggerHook(HookEvents.StreamChunk, chunkPayload);
2914
- this.emitAgentEvent(HookEvents.StreamChunk, chunkPayload);
2915
2956
  }
2916
2957
  const fieldBuffers = assembler.snapshot();
2917
2958
  const endPayload = {
@@ -2920,7 +2961,6 @@ Follow any instructions provided for formatting and style.`;
2920
2961
  fieldBuffers
2921
2962
  };
2922
2963
  await this.triggerHook(HookEvents.StreamEnd, endPayload);
2923
- this.emitAgentEvent(HookEvents.StreamEnd, endPayload);
2924
2964
  const finalize = assembler.finalize();
2925
2965
  let result;
2926
2966
  if (this.outputSchema) {
@@ -2944,7 +2984,7 @@ Follow any instructions provided for formatting and style.`;
2944
2984
  streamSpanId
2945
2985
  );
2946
2986
  if (!usageTracked) {
2947
- context.updateUsage({
2987
+ context.updateUsageWithSource(this.name, {
2948
2988
  requests: 1,
2949
2989
  inputTokens: 0,
2950
2990
  outputTokens: 0,
@@ -2968,11 +3008,6 @@ Follow any instructions provided for formatting and style.`;
2968
3008
  callType: "final_result",
2969
3009
  error
2970
3010
  });
2971
- this.emitAgentEvent(HookEvents.StreamError, {
2972
- context,
2973
- callType: "final_result",
2974
- error
2975
- });
2976
3011
  this.logger.error("Failed to generate final result", error);
2977
3012
  throw new Error(
2978
3013
  `Failed to generate final result: ${error instanceof Error ? error.message : String(error)}`
@@ -3008,7 +3043,7 @@ Follow any instructions provided for formatting and style.`;
3008
3043
  const fallbackTotal = record["total_tokens"];
3009
3044
  const totalTokensRaw = typeof primaryTotal === "number" && Number.isFinite(primaryTotal) ? primaryTotal : typeof fallbackTotal === "number" && Number.isFinite(fallbackTotal) ? fallbackTotal : void 0;
3010
3045
  if (totalTokensRaw !== void 0) {
3011
- context.updateUsage({
3046
+ context.updateUsageWithSource(this.name, {
3012
3047
  requests: 1,
3013
3048
  inputTokens: 0,
3014
3049
  outputTokens: 0,
@@ -3373,6 +3408,11 @@ var mcp = (...configs) => {
3373
3408
 
3374
3409
  // src/utils/tool-decorators.ts
3375
3410
  init_tool();
3411
+ var isToolResult = (value) => {
3412
+ if (typeof value !== "object" || value === null) return false;
3413
+ const obj = value;
3414
+ return typeof obj["success"] === "boolean" && typeof obj["toolName"] === "string" && ("output" in obj || "error" in obj);
3415
+ };
3376
3416
  var reflectWithMetadata = Reflect;
3377
3417
  var ReflectMetadata = {
3378
3418
  define: (metadataKey, metadataValue, target, propertyKey) => {
@@ -3460,6 +3500,8 @@ function createToolDefinition(options, methodName, propertyKey, method, callTarg
3460
3500
  name,
3461
3501
  description,
3462
3502
  ...options.schema && { schema: options.schema },
3503
+ ...options.outputSchema && { outputSchema: options.outputSchema },
3504
+ ...options.examples && { examples: options.examples },
3463
3505
  ...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
3464
3506
  metadata: {
3465
3507
  ...options.metadata,
@@ -3476,6 +3518,8 @@ function createFunctionTool(fn, options = {}) {
3476
3518
  name,
3477
3519
  description,
3478
3520
  ...options.schema && { schema: options.schema },
3521
+ ...options.outputSchema && { outputSchema: options.outputSchema },
3522
+ ...options.examples && { examples: options.examples },
3479
3523
  ...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
3480
3524
  metadata: {
3481
3525
  ...options.metadata,
@@ -3498,6 +3542,9 @@ function createFunctionTool(fn, options = {}) {
3498
3542
  } else {
3499
3543
  result = await Promise.resolve(fn(input, context));
3500
3544
  }
3545
+ if (isToolResult(result)) {
3546
+ return result;
3547
+ }
3501
3548
  return exports.ToolResultFactory.success(name, result, {
3502
3549
  startedAt,
3503
3550
  finishedAt: Date.now(),
@@ -3793,7 +3840,6 @@ var ToolRunner = class {
3793
3840
 
3794
3841
  exports.Agent = Agent;
3795
3842
  exports.AgentDecisionSchema = AgentDecisionSchema;
3796
- exports.AgentEventEmitter = AgentEventEmitter;
3797
3843
  exports.AgentEvents = AgentEvents;
3798
3844
  exports.BaseAgent = BaseAgent;
3799
3845
  exports.ConsoleLogger = ConsoleLogger;
@@ -3819,7 +3865,9 @@ exports.ThoughtSchema = ThoughtSchema;
3819
3865
  exports.ToolCallSchema = ToolCallSchema;
3820
3866
  exports.ToolExecutionSummarySchema = ToolExecutionSummarySchema;
3821
3867
  exports.ToolRunner = ToolRunner;
3868
+ exports.addUsage = addUsage;
3822
3869
  exports.createAgentDecisionWithOutputSchema = createAgentDecisionWithOutputSchema;
3870
+ exports.createEmptyUsage = createEmptyUsage;
3823
3871
  exports.createFunctionTool = createFunctionTool;
3824
3872
  exports.createHookManager = createHookManager;
3825
3873
  exports.createInMemoryStore = createInMemoryStore;