@opperai/agents 0.3.0-beta.1 → 0.4.0

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
  *
@@ -1443,6 +1466,11 @@ var BaseAgent = class {
1443
1466
 
1444
1467
  // src/index.ts
1445
1468
  init_context();
1469
+
1470
+ // src/base/events.ts
1471
+ var AgentEvents = HookEvents;
1472
+
1473
+ // src/index.ts
1446
1474
  init_result();
1447
1475
  init_tool();
1448
1476
  var ThoughtSchema = zod.z.object({
@@ -1611,7 +1639,7 @@ var mergeSchemaDefaults = (schema, value) => {
1611
1639
 
1612
1640
  // package.json
1613
1641
  var package_default = {
1614
- version: "0.3.0-beta.1"};
1642
+ version: "0.4.0"};
1615
1643
 
1616
1644
  // src/utils/version.ts
1617
1645
  var SDK_NAME = "@opperai/agents";
@@ -2281,7 +2309,7 @@ var Agent = class extends BaseAgent {
2281
2309
  model: this.model,
2282
2310
  ...context.parentSpanId && { parentSpanId: context.parentSpanId }
2283
2311
  });
2284
- context.updateUsage({
2312
+ context.updateUsageWithSource(this.name, {
2285
2313
  requests: 1,
2286
2314
  inputTokens: response.usage.inputTokens,
2287
2315
  outputTokens: response.usage.outputTokens,
@@ -2333,10 +2361,6 @@ var Agent = class extends BaseAgent {
2333
2361
  context,
2334
2362
  callType: "think"
2335
2363
  });
2336
- this.emitAgentEvent(HookEvents.StreamStart, {
2337
- context,
2338
- callType: "think"
2339
- });
2340
2364
  try {
2341
2365
  const streamResponse = await this.opperClient.stream({
2342
2366
  name: spanName,
@@ -2373,7 +2397,6 @@ var Agent = class extends BaseAgent {
2373
2397
  fieldBuffers: feedResult.snapshot
2374
2398
  };
2375
2399
  await this.triggerHook(HookEvents.StreamChunk, chunkPayload);
2376
- this.emitAgentEvent(HookEvents.StreamChunk, chunkPayload);
2377
2400
  }
2378
2401
  const fieldBuffers = assembler.snapshot();
2379
2402
  const endPayload = {
@@ -2382,7 +2405,6 @@ var Agent = class extends BaseAgent {
2382
2405
  fieldBuffers
2383
2406
  };
2384
2407
  await this.triggerHook(HookEvents.StreamEnd, endPayload);
2385
- this.emitAgentEvent(HookEvents.StreamEnd, endPayload);
2386
2408
  const finalize = assembler.finalize();
2387
2409
  let decision;
2388
2410
  if (finalize.type === "structured" && finalize.structured) {
@@ -2399,7 +2421,7 @@ var Agent = class extends BaseAgent {
2399
2421
  streamSpanId
2400
2422
  );
2401
2423
  if (!usageTracked) {
2402
- context.updateUsage({
2424
+ context.updateUsageWithSource(this.name, {
2403
2425
  requests: 1,
2404
2426
  inputTokens: 0,
2405
2427
  outputTokens: 0,
@@ -2444,11 +2466,6 @@ var Agent = class extends BaseAgent {
2444
2466
  callType: "think",
2445
2467
  error
2446
2468
  });
2447
- this.emitAgentEvent(HookEvents.StreamError, {
2448
- context,
2449
- callType: "think",
2450
- error
2451
- });
2452
2469
  this.logger.error("Think step failed", error);
2453
2470
  throw new Error(
2454
2471
  `Think step failed: ${error instanceof Error ? error.message : String(error)}`
@@ -2506,12 +2523,30 @@ The memory you write persists across all process() calls on this agent.`;
2506
2523
  * Build dynamic context for the think step
2507
2524
  */
2508
2525
  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
- }));
2526
+ const availableTools = Array.from(this.tools.values()).map((tool2) => {
2527
+ let parameters = {};
2528
+ if (tool2.schema) {
2529
+ parameters = schemaToJson(tool2.schema);
2530
+ } else if (tool2.metadata?.["parameters"] && typeof tool2.metadata["parameters"] === "object") {
2531
+ parameters = tool2.metadata["parameters"];
2532
+ }
2533
+ let returns = void 0;
2534
+ if (tool2.outputSchema) {
2535
+ returns = schemaToJson(tool2.outputSchema);
2536
+ } else if (tool2.metadata?.["outputSchema"] && typeof tool2.metadata["outputSchema"] === "object") {
2537
+ returns = tool2.metadata["outputSchema"];
2538
+ }
2539
+ return {
2540
+ name: tool2.name,
2541
+ description: tool2.description || "",
2542
+ // Include parameters (from Zod schema or MCP metadata)
2543
+ parameters,
2544
+ // Include output schema if defined (helps LLM understand what tool returns)
2545
+ ...returns !== void 0 ? { returns } : {},
2546
+ // Include examples if defined (helps LLM understand expected behavior)
2547
+ ...tool2.examples ? { examples: tool2.examples } : {}
2548
+ };
2549
+ });
2515
2550
  const executionHistory = context.getLastNCycles(3).map((cycle) => {
2516
2551
  const thought = typeof cycle.thought === "object" && cycle.thought !== null ? cycle.thought["reasoning"] || "" : String(cycle.thought || "");
2517
2552
  const results = Array.isArray(cycle.results) ? cycle.results.map((r) => {
@@ -2581,6 +2616,9 @@ The memory you write persists across all process() calls on this agent.`;
2581
2616
  context,
2582
2617
  { spanId: toolSpan.id }
2583
2618
  );
2619
+ if (result.usage) {
2620
+ context.updateUsageWithSource(toolCall.toolName, result.usage);
2621
+ }
2584
2622
  const endTime = /* @__PURE__ */ new Date();
2585
2623
  const durationMs = endTime.getTime() - startTime.getTime();
2586
2624
  if (result.success) {
@@ -2839,7 +2877,7 @@ Follow any instructions provided for formatting and style.`;
2839
2877
  callOptions.outputSchema = this.outputSchema;
2840
2878
  }
2841
2879
  const response = await this.opperClient.call(callOptions);
2842
- context.updateUsage({
2880
+ context.updateUsageWithSource(this.name, {
2843
2881
  requests: 1,
2844
2882
  inputTokens: response.usage.inputTokens,
2845
2883
  outputTokens: response.usage.outputTokens,
@@ -2869,10 +2907,6 @@ Follow any instructions provided for formatting and style.`;
2869
2907
  context,
2870
2908
  callType: "final_result"
2871
2909
  });
2872
- this.emitAgentEvent(HookEvents.StreamStart, {
2873
- context,
2874
- callType: "final_result"
2875
- });
2876
2910
  try {
2877
2911
  const sanitizedName = this.name.toLowerCase().replace(/[\s-]/g, "_");
2878
2912
  const functionName = `generate_final_result_${sanitizedName}`;
@@ -2911,7 +2945,6 @@ Follow any instructions provided for formatting and style.`;
2911
2945
  fieldBuffers: feedResult.snapshot
2912
2946
  };
2913
2947
  await this.triggerHook(HookEvents.StreamChunk, chunkPayload);
2914
- this.emitAgentEvent(HookEvents.StreamChunk, chunkPayload);
2915
2948
  }
2916
2949
  const fieldBuffers = assembler.snapshot();
2917
2950
  const endPayload = {
@@ -2920,7 +2953,6 @@ Follow any instructions provided for formatting and style.`;
2920
2953
  fieldBuffers
2921
2954
  };
2922
2955
  await this.triggerHook(HookEvents.StreamEnd, endPayload);
2923
- this.emitAgentEvent(HookEvents.StreamEnd, endPayload);
2924
2956
  const finalize = assembler.finalize();
2925
2957
  let result;
2926
2958
  if (this.outputSchema) {
@@ -2944,7 +2976,7 @@ Follow any instructions provided for formatting and style.`;
2944
2976
  streamSpanId
2945
2977
  );
2946
2978
  if (!usageTracked) {
2947
- context.updateUsage({
2979
+ context.updateUsageWithSource(this.name, {
2948
2980
  requests: 1,
2949
2981
  inputTokens: 0,
2950
2982
  outputTokens: 0,
@@ -2968,11 +3000,6 @@ Follow any instructions provided for formatting and style.`;
2968
3000
  callType: "final_result",
2969
3001
  error
2970
3002
  });
2971
- this.emitAgentEvent(HookEvents.StreamError, {
2972
- context,
2973
- callType: "final_result",
2974
- error
2975
- });
2976
3003
  this.logger.error("Failed to generate final result", error);
2977
3004
  throw new Error(
2978
3005
  `Failed to generate final result: ${error instanceof Error ? error.message : String(error)}`
@@ -3008,7 +3035,7 @@ Follow any instructions provided for formatting and style.`;
3008
3035
  const fallbackTotal = record["total_tokens"];
3009
3036
  const totalTokensRaw = typeof primaryTotal === "number" && Number.isFinite(primaryTotal) ? primaryTotal : typeof fallbackTotal === "number" && Number.isFinite(fallbackTotal) ? fallbackTotal : void 0;
3010
3037
  if (totalTokensRaw !== void 0) {
3011
- context.updateUsage({
3038
+ context.updateUsageWithSource(this.name, {
3012
3039
  requests: 1,
3013
3040
  inputTokens: 0,
3014
3041
  outputTokens: 0,
@@ -3460,6 +3487,8 @@ function createToolDefinition(options, methodName, propertyKey, method, callTarg
3460
3487
  name,
3461
3488
  description,
3462
3489
  ...options.schema && { schema: options.schema },
3490
+ ...options.outputSchema && { outputSchema: options.outputSchema },
3491
+ ...options.examples && { examples: options.examples },
3463
3492
  ...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
3464
3493
  metadata: {
3465
3494
  ...options.metadata,
@@ -3476,6 +3505,8 @@ function createFunctionTool(fn, options = {}) {
3476
3505
  name,
3477
3506
  description,
3478
3507
  ...options.schema && { schema: options.schema },
3508
+ ...options.outputSchema && { outputSchema: options.outputSchema },
3509
+ ...options.examples && { examples: options.examples },
3479
3510
  ...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
3480
3511
  metadata: {
3481
3512
  ...options.metadata,
@@ -3793,7 +3824,6 @@ var ToolRunner = class {
3793
3824
 
3794
3825
  exports.Agent = Agent;
3795
3826
  exports.AgentDecisionSchema = AgentDecisionSchema;
3796
- exports.AgentEventEmitter = AgentEventEmitter;
3797
3827
  exports.AgentEvents = AgentEvents;
3798
3828
  exports.BaseAgent = BaseAgent;
3799
3829
  exports.ConsoleLogger = ConsoleLogger;
@@ -3819,7 +3849,9 @@ exports.ThoughtSchema = ThoughtSchema;
3819
3849
  exports.ToolCallSchema = ToolCallSchema;
3820
3850
  exports.ToolExecutionSummarySchema = ToolExecutionSummarySchema;
3821
3851
  exports.ToolRunner = ToolRunner;
3852
+ exports.addUsage = addUsage;
3822
3853
  exports.createAgentDecisionWithOutputSchema = createAgentDecisionWithOutputSchema;
3854
+ exports.createEmptyUsage = createEmptyUsage;
3823
3855
  exports.createFunctionTool = createFunctionTool;
3824
3856
  exports.createHookManager = createHookManager;
3825
3857
  exports.createInMemoryStore = createInMemoryStore;