@cuylabs/agent-core 0.9.0 → 0.10.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.
Files changed (116) hide show
  1. package/README.md +33 -17
  2. package/dist/chunk-2O4MCSQS.js +780 -0
  3. package/dist/chunk-2TTOLHBT.js +198 -0
  4. package/dist/chunk-5FMSGQVX.js +281 -0
  5. package/dist/chunk-5NVVNXPQ.js +288 -0
  6. package/dist/{chunk-EKR6PKXU.js → chunk-6HZBHFOL.js} +3 -3
  7. package/dist/chunk-CJI7PVS2.js +58 -0
  8. package/dist/{chunk-WKHDSSXG.js → chunk-CMYN2RCB.js} +146 -46
  9. package/dist/chunk-FII65CN7.js +117 -0
  10. package/dist/{chunk-UHCJEM2E.js → chunk-ICZ66572.js} +13 -6
  11. package/dist/chunk-KYLPMBHD.js +316 -0
  12. package/dist/chunk-MXAP4UG6.js +2956 -0
  13. package/dist/{chunk-4QFNWPIF.js → chunk-N3VX7FEE.js} +35 -2
  14. package/dist/{chunk-MAZ5DY5B.js → chunk-NDZWXCBZ.js} +213 -78
  15. package/dist/{chunk-MHKK374K.js → chunk-Q742PSH3.js} +11 -27
  16. package/dist/{chunk-WGZAPU6N.js → chunk-QAL3OMI3.js} +15 -1
  17. package/dist/{chunk-UDCZ673N.js → chunk-RN6WZEUF.js} +27 -23
  18. package/dist/{chunk-ZXAKHMWH.js → chunk-ROTGCYDW.js} +22 -84
  19. package/dist/chunk-SPBFQXOT.js +0 -0
  20. package/dist/chunk-SSFBF3US.js +602 -0
  21. package/dist/chunk-SZ2XBPTW.js +8 -0
  22. package/dist/chunk-T4UIX5D7.js +115 -0
  23. package/dist/{chunk-IYWQOJMQ.js → chunk-TIHPYVAJ.js} +34 -34
  24. package/dist/{chunk-RKEW5WXI.js → chunk-TOTDGK3P.js} +1 -1
  25. package/dist/chunk-V4RFNEET.js +563 -0
  26. package/dist/chunk-VOUEJSW6.js +0 -0
  27. package/dist/{chunk-J4QDGZIA.js → chunk-WBPOZ7CL.js} +659 -275
  28. package/dist/chunk-X4VN4GIJ.js +185 -0
  29. package/dist/dispatch/index.d.ts +93 -0
  30. package/dist/dispatch/index.js +37 -0
  31. package/dist/events/index.d.ts +93 -0
  32. package/dist/events/index.js +6 -0
  33. package/dist/{runtime → execution}/index.d.ts +120 -35
  34. package/dist/{runtime → execution}/index.js +17 -11
  35. package/dist/index.d.ts +489 -115
  36. package/dist/index.js +1665 -462
  37. package/dist/inference/errors/index.js +1 -1
  38. package/dist/inference/index.d.ts +13 -21
  39. package/dist/inference/index.js +15 -12
  40. package/dist/instance-BqV2D5pc.d.ts +5723 -0
  41. package/dist/logger/index.d.ts +50 -0
  42. package/dist/logger/index.js +11 -0
  43. package/dist/mcp/index.d.ts +5 -9
  44. package/dist/mcp/index.js +2 -3
  45. package/dist/middleware/index.d.ts +10 -150
  46. package/dist/middleware/index.js +10 -2
  47. package/dist/model-messages-B4nK9D1-.d.ts +13 -0
  48. package/dist/models/index.d.ts +5 -2
  49. package/dist/models/index.js +2 -1
  50. package/dist/models/reasoning/index.js +2 -1
  51. package/dist/plugin/index.d.ts +55 -11
  52. package/dist/plugin/index.js +1 -1
  53. package/dist/profiles/index.d.ts +55 -0
  54. package/dist/{presets → profiles}/index.js +10 -10
  55. package/dist/prompt/index.d.ts +8 -13
  56. package/dist/safety/index.d.ts +109 -14
  57. package/dist/safety/index.js +59 -3
  58. package/dist/sandbox/index.d.ts +81 -0
  59. package/dist/sandbox/index.js +1 -0
  60. package/dist/skill/index.d.ts +10 -8
  61. package/dist/skill/index.js +2 -2
  62. package/dist/storage/index.d.ts +12 -4
  63. package/dist/storage/index.js +1 -1
  64. package/dist/subagents/index.d.ts +177 -0
  65. package/dist/subagents/index.js +78 -0
  66. package/dist/team/index.d.ts +544 -0
  67. package/dist/team/index.js +41 -0
  68. package/dist/tool/host/index.d.ts +41 -0
  69. package/dist/tool/host/index.js +10 -0
  70. package/dist/tool/index.d.ts +111 -21
  71. package/dist/tool/index.js +20 -13
  72. package/dist/{types-VQgymC1N.d.ts → types-Bj_J8u_W.d.ts} +44 -64
  73. package/dist/{types-CHiPh8U2.d.ts → types-C_LCeYNg.d.ts} +7 -7
  74. package/dist/types-RSCv7nQ4.d.ts +59 -0
  75. package/package.json +46 -47
  76. package/dist/builder-BgZ_j4Vs.d.ts +0 -35
  77. package/dist/chunk-5ARZJWD2.js +0 -259
  78. package/dist/chunk-DXFBQMXP.js +0 -53
  79. package/dist/chunk-H3FUYU52.js +0 -81
  80. package/dist/chunk-JLXG2SH7.js +0 -905
  81. package/dist/chunk-N7P4PN3O.js +0 -84
  82. package/dist/chunk-OFDKHNCX.js +0 -727
  83. package/dist/chunk-SDSBEQXG.js +0 -157
  84. package/dist/chunk-VEKUXUVF.js +0 -41
  85. package/dist/chunk-VNQBHPCT.js +0 -398
  86. package/dist/chunk-WWYYNWEW.js +0 -259
  87. package/dist/context/index.d.ts +0 -259
  88. package/dist/context/index.js +0 -26
  89. package/dist/events-CE72w8W4.d.ts +0 -149
  90. package/dist/host/index.d.ts +0 -45
  91. package/dist/host/index.js +0 -8
  92. package/dist/index-DQuTZ8xL.d.ts +0 -1335
  93. package/dist/messages-BYWGn8TY.d.ts +0 -110
  94. package/dist/presets/index.d.ts +0 -53
  95. package/dist/registry-DwYqsQkX.d.ts +0 -164
  96. package/dist/runner-CI-XeR16.d.ts +0 -91
  97. package/dist/scope/index.d.ts +0 -10
  98. package/dist/scope/index.js +0 -14
  99. package/dist/session-manager-KbYt2WUh.d.ts +0 -282
  100. package/dist/signal/index.d.ts +0 -28
  101. package/dist/signal/index.js +0 -6
  102. package/dist/sub-agent/index.d.ts +0 -24
  103. package/dist/sub-agent/index.js +0 -32
  104. package/dist/tool-CZWN3KbO.d.ts +0 -141
  105. package/dist/tool-DkhSCV2Y.d.ts +0 -145
  106. package/dist/tracker-DClqYqTj.d.ts +0 -96
  107. package/dist/tracking/index.d.ts +0 -111
  108. package/dist/tracking/index.js +0 -20
  109. package/dist/types-BfNpU8NS.d.ts +0 -270
  110. package/dist/types-BlOKk-Bb.d.ts +0 -330
  111. package/dist/types-BlZwmnuW.d.ts +0 -50
  112. package/dist/types-CQL-SvTn.d.ts +0 -29
  113. package/dist/types-CWm-7rvB.d.ts +0 -55
  114. package/dist/types-DTSkxakL.d.ts +0 -651
  115. package/dist/types-DmDwi2zI.d.ts +0 -339
  116. package/dist/types-YuWV4ag7.d.ts +0 -72
@@ -112,6 +112,30 @@ function extractFromAISDKError(error) {
112
112
  }
113
113
 
114
114
  // src/inference/errors/llm-error.ts
115
+ function extractMessage(error) {
116
+ if (typeof error === "string") return error;
117
+ if (error && typeof error === "object") {
118
+ if ("message" in error && typeof error.message === "string") {
119
+ return error.message;
120
+ }
121
+ try {
122
+ return JSON.stringify(error);
123
+ } catch {
124
+ }
125
+ }
126
+ return String(error);
127
+ }
128
+ function sanitizeErrorMessage(message) {
129
+ const trimmed = message.trim();
130
+ const stackIndex = trimmed.indexOf("\n at ");
131
+ if (stackIndex >= 0) {
132
+ return trimmed.slice(0, stackIndex).trim();
133
+ }
134
+ return trimmed.split("\n").map((line) => line.trim()).find(Boolean) ?? trimmed;
135
+ }
136
+ function isNoOutputGeneratedError(error) {
137
+ return error.name === "AI_NoOutputGeneratedError" || error.name === "NoOutputGeneratedError" || error.message.includes("No output generated. Check the stream for errors.");
138
+ }
115
139
  var LLMError = class _LLMError extends Error {
116
140
  category;
117
141
  status;
@@ -147,15 +171,24 @@ var LLMError = class _LLMError extends Error {
147
171
  ...context
148
172
  });
149
173
  }
174
+ if (isNoOutputGeneratedError(error)) {
175
+ return new _LLMError({
176
+ message: "No output generated. Check the underlying provider error.",
177
+ cause: error,
178
+ category: "unknown",
179
+ ...extractFromAISDKError(error),
180
+ ...context
181
+ });
182
+ }
150
183
  return new _LLMError({
151
- message: error.message,
184
+ message: sanitizeErrorMessage(error.message),
152
185
  cause: error,
153
186
  ...extractFromAISDKError(error),
154
187
  ...context
155
188
  });
156
189
  }
157
190
  return new _LLMError({
158
- message: String(error),
191
+ message: extractMessage(error),
159
192
  category: "unknown",
160
193
  ...context
161
194
  });
@@ -1,25 +1,28 @@
1
1
  import {
2
- createApprovalHandler
3
- } from "./chunk-5ARZJWD2.js";
2
+ DEFAULT_AGENT_NAME,
3
+ isBlockedModelCall
4
+ } from "./chunk-CJI7PVS2.js";
4
5
  import {
5
6
  extractModelId,
6
7
  extractProvider
7
8
  } from "./chunk-I6PKJ7XQ.js";
9
+ import {
10
+ ApprovalDeniedError,
11
+ createApprovalCorrection,
12
+ createApprovalHandler,
13
+ formatApprovalDeniedReason
14
+ } from "./chunk-V4RFNEET.js";
15
+ import {
16
+ silentLogger
17
+ } from "./chunk-T4UIX5D7.js";
8
18
 
9
19
  // src/middleware/runner.ts
10
- function isBlockedModelCall(value) {
11
- return "block" in value && value.block === true;
12
- }
13
- function logMiddlewareWarning(middlewareName, hook, error) {
14
- console.warn(
15
- `[middleware] "${middlewareName}" ${hook} error:`,
16
- error instanceof Error ? error.message : String(error)
17
- );
18
- }
19
20
  var MiddlewareRunner = class {
20
21
  stack;
21
- constructor(middleware = []) {
22
+ log;
23
+ constructor(middleware = [], logger) {
22
24
  this.stack = Object.freeze([...middleware]);
25
+ this.log = logger?.child("middleware") ?? silentLogger;
23
26
  }
24
27
  /** Number of registered middleware */
25
28
  get count() {
@@ -73,7 +76,7 @@ var MiddlewareRunner = class {
73
76
  current = next;
74
77
  }
75
78
  } catch (err) {
76
- logMiddlewareWarning(mw.name, "model.chunk", err);
79
+ this.log.warn(`"${mw.name}" model.chunk error: ${err instanceof Error ? err.message : String(err)}`);
77
80
  }
78
81
  }
79
82
  return current ?? void 0;
@@ -92,7 +95,7 @@ var MiddlewareRunner = class {
92
95
  current = next;
93
96
  }
94
97
  } catch (err) {
95
- logMiddlewareWarning(mw.name, "model.output", err);
98
+ this.log.warn(`"${mw.name}" model.output error: ${err instanceof Error ? err.message : String(err)}`);
96
99
  }
97
100
  }
98
101
  return current;
@@ -106,15 +109,24 @@ var MiddlewareRunner = class {
106
109
  * Returns `{ action: "allow" }` if all middleware allow (or have no hook).
107
110
  * Returns `{ action: "deny", reason }` on first denial — remaining
108
111
  * middleware are skipped.
112
+ *
113
+ * When a middleware rewrites args via `decision.args`, subsequent
114
+ * middleware in the chain receive the rewritten args.
109
115
  */
110
116
  async runBeforeToolCall(tool, args, ctx) {
117
+ let currentArgs = args;
118
+ let rewritten = false;
111
119
  for (const mw of this.stack) {
112
120
  if (!mw.beforeToolCall) continue;
113
121
  try {
114
- const decision = await mw.beforeToolCall(tool, args, ctx);
122
+ const decision = await mw.beforeToolCall(tool, currentArgs, ctx);
115
123
  if (decision.action === "deny") {
116
124
  return decision;
117
125
  }
126
+ if (decision.args !== void 0) {
127
+ currentArgs = decision.args;
128
+ rewritten = true;
129
+ }
118
130
  } catch (err) {
119
131
  return {
120
132
  action: "deny",
@@ -122,7 +134,7 @@ var MiddlewareRunner = class {
122
134
  };
123
135
  }
124
136
  }
125
- return { action: "allow" };
137
+ return rewritten ? { action: "allow", args: currentArgs } : { action: "allow" };
126
138
  }
127
139
  // --------------------------------------------------------------------------
128
140
  // afterToolCall — reverse order (innermost first)
@@ -133,6 +145,10 @@ var MiddlewareRunner = class {
133
145
  * Each hook receives the result from the previous hook (or the
134
146
  * original tool result for the first hook). Errors are caught
135
147
  * and logged — the original result passes through.
148
+ *
149
+ * Middleware can add a `supplement` to inject extra text the model
150
+ * sees alongside the tool output. Supplements chain naturally —
151
+ * each middleware receives any supplement added by earlier hooks.
136
152
  */
137
153
  async runAfterToolCall(tool, args, result, ctx) {
138
154
  let current = result;
@@ -142,7 +158,7 @@ var MiddlewareRunner = class {
142
158
  try {
143
159
  current = await mw.afterToolCall(tool, args, current, ctx);
144
160
  } catch (err) {
145
- logMiddlewareWarning(mw.name, "afterToolCall", err);
161
+ this.log.warn(`"${mw.name}" afterToolCall error: ${err instanceof Error ? err.message : String(err)}`);
146
162
  }
147
163
  }
148
164
  return current;
@@ -169,7 +185,7 @@ var MiddlewareRunner = class {
169
185
  sections.push(result);
170
186
  }
171
187
  } catch (err) {
172
- logMiddlewareWarning(mw.name, "promptSections", err);
188
+ this.log.warn(`"${mw.name}" promptSections error: ${err instanceof Error ? err.message : String(err)}`);
173
189
  }
174
190
  }
175
191
  return sections;
@@ -196,11 +212,11 @@ var MiddlewareRunner = class {
196
212
  * Get the OTel context for a session from the telemetry middleware.
197
213
  * Returns undefined if no telemetry middleware is registered.
198
214
  */
199
- getOtelContext(sessionId) {
215
+ getOtelContext(sessionId, ctx) {
200
216
  for (const mw of this.stack) {
201
217
  if (mw.getOtelContext) {
202
- const ctx = mw.getOtelContext(sessionId);
203
- if (ctx) return ctx;
218
+ const otelCtx = mw.getOtelContext(sessionId, ctx);
219
+ if (otelCtx) return otelCtx;
204
220
  }
205
221
  }
206
222
  return void 0;
@@ -214,13 +230,13 @@ var MiddlewareRunner = class {
214
230
  * Errors are caught and logged — a broken logger should not
215
231
  * prevent the chat from starting.
216
232
  */
217
- async runChatStart(sessionId, message) {
233
+ async runChatStart(sessionId, message, ctx) {
218
234
  for (const mw of this.stack) {
219
235
  if (!mw.onChatStart) continue;
220
236
  try {
221
- await mw.onChatStart(sessionId, message);
237
+ await mw.onChatStart(sessionId, message, ctx);
222
238
  } catch (err) {
223
- logMiddlewareWarning(mw.name, "onChatStart", err);
239
+ this.log.warn(`"${mw.name}" onChatStart error: ${err instanceof Error ? err.message : String(err)}`);
224
240
  }
225
241
  }
226
242
  }
@@ -233,30 +249,49 @@ var MiddlewareRunner = class {
233
249
  * Always called, even when the stream errored. Errors in handlers
234
250
  * are caught and logged.
235
251
  */
236
- async runChatEnd(sessionId, result) {
252
+ async runChatEnd(sessionId, result, ctx) {
237
253
  for (const mw of this.stack) {
238
254
  if (!mw.onChatEnd) continue;
239
255
  try {
240
- await mw.onChatEnd(sessionId, result);
256
+ await mw.onChatEnd(sessionId, result, ctx);
241
257
  } catch (err) {
242
- logMiddlewareWarning(mw.name, "onChatEnd", err);
258
+ this.log.warn(`"${mw.name}" onChatEnd error: ${err instanceof Error ? err.message : String(err)}`);
243
259
  }
244
260
  }
245
261
  }
246
262
  };
247
263
 
248
264
  // src/middleware/approval.ts
265
+ function isApprovalMiddleware(value) {
266
+ return value.name === "approval" && "approvalHandler" in value && typeof value.approvalHandler === "object" && value.approvalHandler !== null;
267
+ }
249
268
  function approvalMiddleware(config = {}) {
250
269
  const handler = createApprovalHandler(config);
251
270
  return {
252
271
  name: "approval",
272
+ approvalHandler: handler,
273
+ ...config.customRisks ? { approvalCustomRisks: config.customRisks } : {},
253
274
  async beforeToolCall(tool, args, ctx) {
254
275
  try {
255
- await handler.request(ctx.sessionID, tool, args, config.customRisks);
276
+ await handler.request(
277
+ ctx.sessionID,
278
+ tool,
279
+ args,
280
+ config.customRisks,
281
+ ctx.toolCapabilities,
282
+ ctx.permissionPatterns
283
+ );
256
284
  return { action: "allow" };
257
285
  } catch (err) {
258
- const reason = err instanceof Error ? err.message : `Approval denied: ${tool}`;
259
- return { action: "deny", reason };
286
+ const reason = err instanceof Error ? err.message : formatApprovalDeniedReason(tool);
287
+ return {
288
+ action: "deny",
289
+ reason,
290
+ correction: createApprovalCorrection(
291
+ tool,
292
+ err instanceof ApprovalDeniedError ? err.feedback : void 0
293
+ )
294
+ };
260
295
  }
261
296
  }
262
297
  };
@@ -264,6 +299,56 @@ function approvalMiddleware(config = {}) {
264
299
 
265
300
  // src/middleware/telemetry/otel.ts
266
301
  var otelModulePromise;
302
+ function resolveToolCallId(args, ctx) {
303
+ const extraToolCallId = ctx?.extra?.toolCallId;
304
+ if (typeof extraToolCallId === "string" && extraToolCallId.length > 0) {
305
+ return extraToolCallId;
306
+ }
307
+ if (ctx?.messageID) {
308
+ return ctx.messageID;
309
+ }
310
+ try {
311
+ return JSON.stringify(args);
312
+ } catch {
313
+ return String(args);
314
+ }
315
+ }
316
+ function makeToolSpanKey(toolName, toolCallId) {
317
+ return `${toolName}:${toolCallId}`;
318
+ }
319
+ function makeChatSpanKey(sessionId, turnId) {
320
+ return turnId ? `${sessionId}:${turnId}` : sessionId;
321
+ }
322
+ function findChatSpanKey(spans, sessionId, ctx) {
323
+ const exactKey = makeChatSpanKey(sessionId, ctx?.turnId);
324
+ if (spans.has(exactKey)) {
325
+ return exactKey;
326
+ }
327
+ if (!ctx?.turnId && spans.has(sessionId)) {
328
+ return sessionId;
329
+ }
330
+ for (const key of spans.keys()) {
331
+ if (key === sessionId || key.startsWith(`${sessionId}:`)) {
332
+ return key;
333
+ }
334
+ }
335
+ return void 0;
336
+ }
337
+ function removeSpanEntry(spans, key) {
338
+ const entry = spans.get(key);
339
+ if (entry) {
340
+ spans.delete(key);
341
+ }
342
+ return entry;
343
+ }
344
+ function findSpanEntryByTool(spans, toolName) {
345
+ for (const [key, entry] of spans) {
346
+ if (key.startsWith(`${toolName}:`)) {
347
+ return [key, entry];
348
+ }
349
+ }
350
+ return void 0;
351
+ }
267
352
  function getInputMimeType(value) {
268
353
  const trimmed = value.trimStart();
269
354
  return trimmed.startsWith("{") || trimmed.startsWith("[") ? "application/json" : "text/plain";
@@ -292,7 +377,7 @@ function scheduleSpanTimeout(options) {
292
377
  function otelMiddleware(config = {}) {
293
378
  const recordInputs = config.recordInputs ?? true;
294
379
  const recordOutputs = config.recordOutputs ?? true;
295
- const agentName = config.agentName ?? "agent";
380
+ const agentName = config.agentName ?? DEFAULT_AGENT_NAME;
296
381
  const emitToolSpans = config.emitToolSpans ?? true;
297
382
  const spanTimeoutMs = config.spanTimeoutMs ?? 5 * 60 * 1e3;
298
383
  const chatSpans = /* @__PURE__ */ new Map();
@@ -303,6 +388,9 @@ function otelMiddleware(config = {}) {
303
388
  if (tracer) {
304
389
  return tracer;
305
390
  }
391
+ if (config.providerReady) {
392
+ await config.providerReady;
393
+ }
306
394
  otel = await getOtelModule();
307
395
  if (!otel) {
308
396
  return null;
@@ -312,20 +400,25 @@ function otelMiddleware(config = {}) {
312
400
  }
313
401
  return {
314
402
  name: "opentelemetry",
315
- getOtelContext(sessionId) {
316
- return chatSpans.get(sessionId)?.ctx;
403
+ getOtelContext(sessionId, ctx) {
404
+ const key = findChatSpanKey(chatSpans, sessionId, ctx);
405
+ return key ? chatSpans.get(key)?.ctx : void 0;
317
406
  },
318
- async onChatStart(sessionId, message) {
407
+ async onChatStart(sessionId, message, chatCtx) {
319
408
  const activeTracer = await ensureTracer();
320
409
  if (!activeTracer || !otel) {
321
410
  return;
322
411
  }
412
+ const key = makeChatSpanKey(sessionId, chatCtx?.turnId);
323
413
  const attributes = {
324
414
  "openinference.span.kind": "AGENT",
325
415
  "gen_ai.operation.name": "invoke_agent",
326
416
  "gen_ai.agent.name": agentName,
327
417
  "gen_ai.agent.session_id": sessionId
328
418
  };
419
+ if (chatCtx?.turnId) {
420
+ attributes["gen_ai.agent.turn_id"] = chatCtx.turnId;
421
+ }
329
422
  if (config.agentDescription) {
330
423
  attributes["gen_ai.agent.description"] = config.agentDescription;
331
424
  }
@@ -337,13 +430,13 @@ function otelMiddleware(config = {}) {
337
430
  const span = activeTracer.startSpan(`invoke_agent ${agentName}`, {
338
431
  attributes
339
432
  });
340
- const ctx = otel.trace.setSpan(otel.context.active(), span);
341
- chatSpans.set(sessionId, {
433
+ const spanCtx = otel.trace.setSpan(otel.context.active(), span);
434
+ chatSpans.set(key, {
342
435
  span,
343
- ctx,
436
+ ctx: spanCtx,
344
437
  timer: scheduleSpanTimeout({
345
438
  spans: chatSpans,
346
- key: sessionId,
439
+ key,
347
440
  otel,
348
441
  timeoutMs: spanTimeoutMs
349
442
  })
@@ -358,7 +451,10 @@ function otelMiddleware(config = {}) {
358
451
  return { action: "allow" };
359
452
  }
360
453
  const sessionId = ctx?.sessionID;
361
- const parent = sessionId ? chatSpans.get(sessionId) : void 0;
454
+ const parentKey = sessionId ? findChatSpanKey(chatSpans, sessionId, {
455
+ turnId: ctx?.turnID
456
+ }) : void 0;
457
+ const parent = parentKey ? chatSpans.get(parentKey) : void 0;
362
458
  const parentCtx = parent?.ctx ?? otel.context.active();
363
459
  const span = activeTracer.startSpan(
364
460
  `execute_tool ${tool}`,
@@ -380,8 +476,8 @@ function otelMiddleware(config = {}) {
380
476
  },
381
477
  parentCtx
382
478
  );
383
- const callId = ctx?.messageID ?? JSON.stringify(args);
384
- const key = `${tool}:${callId}`;
479
+ const callId = resolveToolCallId(args, ctx);
480
+ const key = makeToolSpanKey(tool, callId);
385
481
  const toolCtx = otel.trace.setSpan(parentCtx, span);
386
482
  toolSpans.set(key, {
387
483
  span,
@@ -396,12 +492,13 @@ function otelMiddleware(config = {}) {
396
492
  return { action: "allow" };
397
493
  },
398
494
  async afterToolCall(tool, args, result, ctx) {
399
- const callId = ctx?.messageID ?? JSON.stringify(args);
400
- const keyPrefix = `${tool}:`;
401
- const key = `${tool}:${callId}`;
402
- const entry = toolSpans.get(key) ?? Array.from(toolSpans.entries()).find(
403
- ([candidate]) => candidate.startsWith(keyPrefix)
404
- )?.[1];
495
+ const callId = resolveToolCallId(args, ctx);
496
+ const key = makeToolSpanKey(tool, callId);
497
+ const fallback = findSpanEntryByTool(toolSpans, tool);
498
+ const entry = removeSpanEntry(toolSpans, key) ?? (fallback ? (() => {
499
+ toolSpans.delete(fallback[0]);
500
+ return fallback[1];
501
+ })() : void 0);
405
502
  if (entry) {
406
503
  if (entry.timer) {
407
504
  clearTimeout(entry.timer);
@@ -414,12 +511,6 @@ function otelMiddleware(config = {}) {
414
511
  }
415
512
  entry.span.setStatus({ code: otel?.SpanStatusCode.OK ?? 1 });
416
513
  entry.span.end();
417
- for (const [candidateKey, candidateEntry] of toolSpans) {
418
- if (candidateEntry === entry) {
419
- toolSpans.delete(candidateKey);
420
- break;
421
- }
422
- }
423
514
  }
424
515
  return result;
425
516
  },
@@ -427,10 +518,13 @@ function otelMiddleware(config = {}) {
427
518
  if (event.type !== "tool-error") {
428
519
  return;
429
520
  }
430
- for (const [key, entry] of toolSpans) {
431
- if (!key.startsWith(`${event.toolName}:`)) {
432
- continue;
433
- }
521
+ const key = makeToolSpanKey(event.toolName, event.toolCallId);
522
+ const fallback = findSpanEntryByTool(toolSpans, event.toolName);
523
+ const entry = removeSpanEntry(toolSpans, key) ?? (fallback ? (() => {
524
+ toolSpans.delete(fallback[0]);
525
+ return fallback[1];
526
+ })() : void 0);
527
+ if (entry) {
434
528
  if (entry.timer) {
435
529
  clearTimeout(entry.timer);
436
530
  }
@@ -443,12 +537,14 @@ function otelMiddleware(config = {}) {
443
537
  message: event.error
444
538
  });
445
539
  entry.span.end();
446
- toolSpans.delete(key);
447
- break;
448
540
  }
449
541
  },
450
- async onChatEnd(sessionId, result) {
451
- const entry = chatSpans.get(sessionId);
542
+ async onChatEnd(sessionId, result, ctx) {
543
+ const key = findChatSpanKey(chatSpans, sessionId, ctx);
544
+ if (!key) {
545
+ return;
546
+ }
547
+ const entry = chatSpans.get(key);
452
548
  if (!entry) {
453
549
  return;
454
550
  }
@@ -477,34 +573,38 @@ function otelMiddleware(config = {}) {
477
573
  entry.span.setStatus({ code: otel?.SpanStatusCode.OK ?? 1 });
478
574
  }
479
575
  entry.span.end();
480
- chatSpans.delete(sessionId);
576
+ chatSpans.delete(key);
481
577
  }
482
578
  };
483
579
  }
484
580
 
485
581
  // src/middleware/telemetry/provider.ts
582
+ var sharedProviderState;
486
583
  function createTelemetryConfig(config) {
584
+ const recordInputs = config.recordInputs ?? true;
585
+ const recordOutputs = config.recordOutputs ?? true;
586
+ let providerPromise;
587
+ if (config.spanProcessor) {
588
+ providerPromise = acquireSharedProvider(
589
+ config.spanProcessor,
590
+ config.serviceName ?? config.agentName
591
+ );
592
+ }
487
593
  const middleware = otelMiddleware({
488
594
  agentName: config.agentName,
489
595
  agentDescription: config.agentDescription,
490
- recordInputs: config.recordInputs,
491
- recordOutputs: config.recordOutputs,
596
+ recordInputs,
597
+ recordOutputs,
492
598
  emitToolSpans: config.emitToolSpans,
493
- spanTimeoutMs: config.spanTimeoutMs
599
+ spanTimeoutMs: config.spanTimeoutMs,
600
+ providerReady: providerPromise
494
601
  });
495
602
  const telemetry = {
496
603
  isEnabled: true,
497
604
  functionId: config.agentName,
498
- recordInputs: config.recordInputs,
499
- recordOutputs: config.recordOutputs
605
+ recordInputs,
606
+ recordOutputs
500
607
  };
501
- let providerPromise;
502
- if (config.spanProcessor) {
503
- providerPromise = createAndRegisterProvider(
504
- config.spanProcessor,
505
- config.serviceName ?? config.agentName
506
- );
507
- }
508
608
  return {
509
609
  middleware,
510
610
  telemetry,
@@ -512,12 +612,46 @@ function createTelemetryConfig(config) {
512
612
  if (!providerPromise) {
513
613
  return;
514
614
  }
515
- const provider = await providerPromise;
516
- await provider.forceFlush();
517
- await provider.shutdown();
615
+ await releaseSharedProvider(providerPromise);
518
616
  }
519
617
  };
520
618
  }
619
+ function acquireSharedProvider(spanProcessor, serviceName) {
620
+ if (!sharedProviderState) {
621
+ const promise = createAndRegisterProvider(spanProcessor, serviceName).catch(
622
+ (error) => {
623
+ if (sharedProviderState?.promise === promise) {
624
+ sharedProviderState = void 0;
625
+ }
626
+ throw error;
627
+ }
628
+ );
629
+ sharedProviderState = {
630
+ promise,
631
+ refCount: 0
632
+ };
633
+ }
634
+ sharedProviderState.refCount += 1;
635
+ return sharedProviderState.promise;
636
+ }
637
+ async function releaseSharedProvider(providerPromise) {
638
+ if (!sharedProviderState || sharedProviderState.promise !== providerPromise) {
639
+ return;
640
+ }
641
+ sharedProviderState.refCount -= 1;
642
+ if (sharedProviderState.refCount > 0) {
643
+ return;
644
+ }
645
+ const provider = await providerPromise;
646
+ try {
647
+ await provider.forceFlush();
648
+ await provider.shutdown();
649
+ } finally {
650
+ if (sharedProviderState?.promise === providerPromise) {
651
+ sharedProviderState = void 0;
652
+ }
653
+ }
654
+ }
521
655
  async function createAndRegisterProvider(spanProcessor, serviceName) {
522
656
  const [{ NodeTracerProvider }, { resourceFromAttributes }, { ATTR_SERVICE_NAME }] = await Promise.all([
523
657
  import("@opentelemetry/sdk-trace-node"),
@@ -630,8 +764,9 @@ function promptCacheMiddleware(config) {
630
764
 
631
765
  export {
632
766
  MiddlewareRunner,
767
+ isApprovalMiddleware,
768
+ approvalMiddleware,
633
769
  otelMiddleware,
634
770
  createTelemetryConfig,
635
- approvalMiddleware,
636
771
  promptCacheMiddleware
637
772
  };
@@ -89,11 +89,6 @@ ${end}`;
89
89
  outputPath
90
90
  };
91
91
  }
92
- function formatSize(bytes) {
93
- if (bytes < 1024) return `${bytes} B`;
94
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
95
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
96
- }
97
92
 
98
93
  // src/tool/tool.ts
99
94
  import { z } from "zod";
@@ -106,13 +101,17 @@ var Tool;
106
101
  );
107
102
  return {
108
103
  id,
104
+ capabilitiesHint: options.capabilitiesHint,
109
105
  replayPolicy: staticReplayPolicy,
106
+ deferred: options.deferred,
107
+ searchKeywords: options.searchKeywords,
110
108
  init: async (initCtx) => {
111
109
  const toolInfo = typeof init === "function" ? await init(initCtx) : init;
112
110
  const replayPolicy = normalizeToolReplayPolicy(
113
111
  toolInfo.replayPolicy ?? staticReplayPolicy,
114
112
  toolInfo.fileOps
115
113
  );
114
+ const perToolMaxBytes = toolInfo.capabilities?.maxOutputChars;
116
115
  const originalExecute = toolInfo.execute;
117
116
  const execute = async (params, ctx) => {
118
117
  let validated;
@@ -131,15 +130,18 @@ Please rewrite the input so it satisfies the expected schema.`,
131
130
  );
132
131
  }
133
132
  const result = await originalExecute(validated, ctx);
134
- if (result.metadata.truncated !== void 0) {
133
+ const meta = result.metadata ?? {};
134
+ if (meta.truncated !== void 0) {
135
135
  return result;
136
136
  }
137
- const truncated = truncateOutput(result.output);
137
+ const truncated = truncateOutput(result.output, {
138
+ ...perToolMaxBytes !== void 0 ? { maxBytes: perToolMaxBytes } : {}
139
+ });
138
140
  return {
139
141
  ...result,
140
142
  output: truncated.content,
141
143
  metadata: {
142
- ...result.metadata,
144
+ ...meta,
143
145
  truncated: truncated.truncated,
144
146
  ...truncated.truncated && { outputPath: truncated.outputPath }
145
147
  }
@@ -155,29 +157,11 @@ Please rewrite the input so it satisfies the expected schema.`,
155
157
  }
156
158
  Tool2.define = define;
157
159
  })(Tool || (Tool = {}));
158
- function defineTool(definition) {
159
- return Tool.define(definition.id, {
160
- description: definition.description,
161
- parameters: definition.parameters,
162
- execute: async (params, ctx) => {
163
- const result = await definition.execute(params, ctx);
164
- return {
165
- title: result.title,
166
- output: result.output,
167
- metadata: result.metadata ?? {}
168
- };
169
- }
170
- });
171
- }
172
160
 
173
161
  export {
174
162
  normalizeToolReplayPolicy,
175
163
  MAX_LINES,
176
164
  MAX_BYTES,
177
- TRUNCATE_DIR,
178
- TRUNCATE_GLOB,
179
165
  truncateOutput,
180
- formatSize,
181
- Tool,
182
- defineTool
166
+ Tool
183
167
  };