@cuylabs/agent-core 0.8.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 (127) 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-CAA7FHIH.js → chunk-6HZBHFOL.js} +3 -103
  7. package/dist/chunk-CJI7PVS2.js +58 -0
  8. package/dist/{chunk-N6HWIEEA.js → chunk-CMYN2RCB.js} +278 -61
  9. package/dist/chunk-FII65CN7.js +117 -0
  10. package/dist/{chunk-IVUJDISU.js → chunk-GFTW23FV.js} +5 -14
  11. package/dist/chunk-I6PKJ7XQ.js +292 -0
  12. package/dist/{chunk-BDBZ3SLK.js → chunk-ICZ66572.js} +48 -4
  13. package/dist/chunk-KYLPMBHD.js +316 -0
  14. package/dist/chunk-MXAP4UG6.js +2956 -0
  15. package/dist/{chunk-RZITT45F.js → chunk-N3VX7FEE.js} +39 -6
  16. package/dist/{chunk-YSLSEQ6B.js → chunk-NDZWXCBZ.js} +218 -95
  17. package/dist/{chunk-P6YF7USR.js → chunk-Q742PSH3.js} +23 -38
  18. package/dist/chunk-QAL3OMI3.js +943 -0
  19. package/dist/{chunk-RFEKJKTO.js → chunk-RN6WZEUF.js} +330 -280
  20. package/dist/{chunk-ZXAKHMWH.js → chunk-ROTGCYDW.js} +22 -84
  21. package/dist/chunk-SPBFQXOT.js +0 -0
  22. package/dist/{chunk-LRHOS4ZN.js → chunk-SPILYYDF.js} +3 -2
  23. package/dist/chunk-SSFBF3US.js +602 -0
  24. package/dist/chunk-SZ2XBPTW.js +8 -0
  25. package/dist/chunk-T4UIX5D7.js +115 -0
  26. package/dist/chunk-TIHPYVAJ.js +102 -0
  27. package/dist/{chunk-YUUJK53A.js → chunk-TOTDGK3P.js} +1 -1
  28. package/dist/chunk-V4RFNEET.js +563 -0
  29. package/dist/chunk-VOUEJSW6.js +0 -0
  30. package/dist/{chunk-4BDA7DQY.js → chunk-WBPOZ7CL.js} +673 -273
  31. package/dist/chunk-X4VN4GIJ.js +185 -0
  32. package/dist/dispatch/index.d.ts +93 -0
  33. package/dist/dispatch/index.js +37 -0
  34. package/dist/events/index.d.ts +93 -0
  35. package/dist/events/index.js +6 -0
  36. package/dist/{runtime → execution}/index.d.ts +120 -34
  37. package/dist/{runtime → execution}/index.js +18 -13
  38. package/dist/index-BCqEGzBj.d.ts +251 -0
  39. package/dist/index.d.ts +490 -122
  40. package/dist/index.js +2104 -615
  41. package/dist/{errors → inference/errors}/index.d.ts +2 -2
  42. package/dist/{errors → inference/errors}/index.js +1 -1
  43. package/dist/inference/index.d.ts +16 -23
  44. package/dist/inference/index.js +45 -16
  45. package/dist/instance-BqV2D5pc.d.ts +5723 -0
  46. package/dist/logger/index.d.ts +50 -0
  47. package/dist/logger/index.js +11 -0
  48. package/dist/mcp/index.d.ts +5 -9
  49. package/dist/mcp/index.js +2 -3
  50. package/dist/middleware/index.d.ts +10 -149
  51. package/dist/middleware/index.js +11 -3
  52. package/dist/model-messages-B4nK9D1-.d.ts +13 -0
  53. package/dist/models/index.d.ts +23 -18
  54. package/dist/models/index.js +48 -11
  55. package/dist/models/reasoning/index.d.ts +4 -0
  56. package/dist/{reasoning → models/reasoning}/index.js +3 -3
  57. package/dist/plugin/index.d.ts +458 -0
  58. package/dist/plugin/index.js +32 -0
  59. package/dist/profiles/index.d.ts +55 -0
  60. package/dist/profiles/index.js +30 -0
  61. package/dist/prompt/index.d.ts +8 -12
  62. package/dist/prompt/index.js +3 -2
  63. package/dist/safety/index.d.ts +109 -14
  64. package/dist/safety/index.js +59 -3
  65. package/dist/sandbox/index.d.ts +81 -0
  66. package/dist/sandbox/index.js +1 -0
  67. package/dist/skill/index.d.ts +10 -8
  68. package/dist/skill/index.js +3 -3
  69. package/dist/storage/index.d.ts +12 -4
  70. package/dist/storage/index.js +1 -1
  71. package/dist/subagents/index.d.ts +177 -0
  72. package/dist/subagents/index.js +78 -0
  73. package/dist/team/index.d.ts +544 -0
  74. package/dist/team/index.js +41 -0
  75. package/dist/tool/host/index.d.ts +41 -0
  76. package/dist/tool/host/index.js +10 -0
  77. package/dist/tool/index.d.ts +125 -21
  78. package/dist/tool/index.js +20 -13
  79. package/dist/{types-VQgymC1N.d.ts → types-Bj_J8u_W.d.ts} +44 -64
  80. package/dist/{types-CHiPh8U2.d.ts → types-C_LCeYNg.d.ts} +7 -7
  81. package/dist/types-RSCv7nQ4.d.ts +59 -0
  82. package/package.json +58 -53
  83. package/dist/builder-UpOWQMW3.d.ts +0 -34
  84. package/dist/chunk-7MUFEN4K.js +0 -559
  85. package/dist/chunk-7VKQ4WPB.js +0 -73
  86. package/dist/chunk-BFM2YHNM.js +0 -222
  87. package/dist/chunk-DWYX7ASF.js +0 -26
  88. package/dist/chunk-KUVSERLJ.js +0 -50
  89. package/dist/chunk-N7P4PN3O.js +0 -84
  90. package/dist/chunk-SDSBEQXG.js +0 -157
  91. package/dist/chunk-SQU2AJHO.js +0 -305
  92. package/dist/chunk-VBWWUHWI.js +0 -724
  93. package/dist/chunk-VEKUXUVF.js +0 -41
  94. package/dist/chunk-VNQBHPCT.js +0 -398
  95. package/dist/chunk-WWYYNWEW.js +0 -259
  96. package/dist/context/index.d.ts +0 -259
  97. package/dist/context/index.js +0 -26
  98. package/dist/events-CE72w8W4.d.ts +0 -149
  99. package/dist/host/index.d.ts +0 -45
  100. package/dist/host/index.js +0 -8
  101. package/dist/index-CWSchSql.d.ts +0 -1058
  102. package/dist/messages-BYWGn8TY.d.ts +0 -110
  103. package/dist/presets/index.d.ts +0 -53
  104. package/dist/presets/index.js +0 -28
  105. package/dist/reasoning/index.d.ts +0 -116
  106. package/dist/registry-DwYqsQkX.d.ts +0 -164
  107. package/dist/runner-e2YRcUoX.d.ts +0 -786
  108. package/dist/scope/index.d.ts +0 -10
  109. package/dist/scope/index.js +0 -14
  110. package/dist/session-manager-B_CWGTsl.d.ts +0 -274
  111. package/dist/signal/index.d.ts +0 -28
  112. package/dist/signal/index.js +0 -6
  113. package/dist/sub-agent/index.d.ts +0 -23
  114. package/dist/sub-agent/index.js +0 -15
  115. package/dist/tool-BHbyUAy3.d.ts +0 -150
  116. package/dist/tool-DLXAR9Ce.d.ts +0 -145
  117. package/dist/tracker-DClqYqTj.d.ts +0 -96
  118. package/dist/tracking/index.d.ts +0 -111
  119. package/dist/tracking/index.js +0 -20
  120. package/dist/types-BfNpU8NS.d.ts +0 -270
  121. package/dist/types-BnpEOYV-.d.ts +0 -50
  122. package/dist/types-CQL-SvTn.d.ts +0 -29
  123. package/dist/types-CWm-7rvB.d.ts +0 -55
  124. package/dist/types-KKDrdU9Y.d.ts +0 -325
  125. package/dist/types-QA4WhEfz.d.ts +0 -138
  126. package/dist/types-QKHHQLLq.d.ts +0 -336
  127. package/dist/types-YuWV4ag7.d.ts +0 -72
@@ -1,4 +1,4 @@
1
- // src/errors/classify.ts
1
+ // src/inference/errors/classify.ts
2
2
  function isRetryableCategory(category) {
3
3
  switch (category) {
4
4
  case "rate_limit":
@@ -80,7 +80,7 @@ function parseRetryDelay(headers) {
80
80
  return void 0;
81
81
  }
82
82
 
83
- // src/errors/extract.ts
83
+ // src/inference/errors/extract.ts
84
84
  function extractFromAISDKError(error) {
85
85
  const result = {};
86
86
  const anyError = error;
@@ -111,7 +111,31 @@ function extractFromAISDKError(error) {
111
111
  return result;
112
112
  }
113
113
 
114
- // src/errors/llm-error.ts
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
  });
@@ -171,7 +204,7 @@ var LLMError = class _LLMError extends Error {
171
204
  }
172
205
  };
173
206
 
174
- // src/errors/utils.ts
207
+ // src/inference/errors/utils.ts
175
208
  function isRetryable(error) {
176
209
  if (error instanceof LLMError) {
177
210
  return error.isRetryable;
@@ -1,19 +1,28 @@
1
1
  import {
2
- createApprovalHandler
3
- } from "./chunk-BFM2YHNM.js";
2
+ DEFAULT_AGENT_NAME,
3
+ isBlockedModelCall
4
+ } from "./chunk-CJI7PVS2.js";
4
5
  import {
5
- getModelId,
6
- getProviderId
7
- } from "./chunk-DWYX7ASF.js";
6
+ extractModelId,
7
+ extractProvider
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
20
  var MiddlewareRunner = class {
14
21
  stack;
15
- constructor(middleware = []) {
22
+ log;
23
+ constructor(middleware = [], logger) {
16
24
  this.stack = Object.freeze([...middleware]);
25
+ this.log = logger?.child("middleware") ?? silentLogger;
17
26
  }
18
27
  /** Number of registered middleware */
19
28
  get count() {
@@ -67,10 +76,7 @@ var MiddlewareRunner = class {
67
76
  current = next;
68
77
  }
69
78
  } catch (err) {
70
- console.warn(
71
- `[middleware] "${mw.name}" model.chunk error:`,
72
- err instanceof Error ? err.message : String(err)
73
- );
79
+ this.log.warn(`"${mw.name}" model.chunk error: ${err instanceof Error ? err.message : String(err)}`);
74
80
  }
75
81
  }
76
82
  return current ?? void 0;
@@ -89,10 +95,7 @@ var MiddlewareRunner = class {
89
95
  current = next;
90
96
  }
91
97
  } catch (err) {
92
- console.warn(
93
- `[middleware] "${mw.name}" model.output error:`,
94
- err instanceof Error ? err.message : String(err)
95
- );
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,10 +158,7 @@ var MiddlewareRunner = class {
142
158
  try {
143
159
  current = await mw.afterToolCall(tool, args, current, ctx);
144
160
  } catch (err) {
145
- console.warn(
146
- `[middleware] "${mw.name}" afterToolCall error:`,
147
- err instanceof Error ? err.message : String(err)
148
- );
161
+ this.log.warn(`"${mw.name}" afterToolCall error: ${err instanceof Error ? err.message : String(err)}`);
149
162
  }
150
163
  }
151
164
  return current;
@@ -172,10 +185,7 @@ var MiddlewareRunner = class {
172
185
  sections.push(result);
173
186
  }
174
187
  } catch (err) {
175
- console.warn(
176
- `[middleware] "${mw.name}" promptSections error:`,
177
- err instanceof Error ? err.message : String(err)
178
- );
188
+ this.log.warn(`"${mw.name}" promptSections error: ${err instanceof Error ? err.message : String(err)}`);
179
189
  }
180
190
  }
181
191
  return sections;
@@ -202,11 +212,11 @@ var MiddlewareRunner = class {
202
212
  * Get the OTel context for a session from the telemetry middleware.
203
213
  * Returns undefined if no telemetry middleware is registered.
204
214
  */
205
- getOtelContext(sessionId) {
215
+ getOtelContext(sessionId, ctx) {
206
216
  for (const mw of this.stack) {
207
217
  if (mw.getOtelContext) {
208
- const ctx = mw.getOtelContext(sessionId);
209
- if (ctx) return ctx;
218
+ const otelCtx = mw.getOtelContext(sessionId, ctx);
219
+ if (otelCtx) return otelCtx;
210
220
  }
211
221
  }
212
222
  return void 0;
@@ -220,16 +230,13 @@ var MiddlewareRunner = class {
220
230
  * Errors are caught and logged — a broken logger should not
221
231
  * prevent the chat from starting.
222
232
  */
223
- async runChatStart(sessionId, message) {
233
+ async runChatStart(sessionId, message, ctx) {
224
234
  for (const mw of this.stack) {
225
235
  if (!mw.onChatStart) continue;
226
236
  try {
227
- await mw.onChatStart(sessionId, message);
237
+ await mw.onChatStart(sessionId, message, ctx);
228
238
  } catch (err) {
229
- console.warn(
230
- `[middleware] "${mw.name}" onChatStart error:`,
231
- err instanceof Error ? err.message : String(err)
232
- );
239
+ this.log.warn(`"${mw.name}" onChatStart error: ${err instanceof Error ? err.message : String(err)}`);
233
240
  }
234
241
  }
235
242
  }
@@ -242,33 +249,49 @@ var MiddlewareRunner = class {
242
249
  * Always called, even when the stream errored. Errors in handlers
243
250
  * are caught and logged.
244
251
  */
245
- async runChatEnd(sessionId, result) {
252
+ async runChatEnd(sessionId, result, ctx) {
246
253
  for (const mw of this.stack) {
247
254
  if (!mw.onChatEnd) continue;
248
255
  try {
249
- await mw.onChatEnd(sessionId, result);
256
+ await mw.onChatEnd(sessionId, result, ctx);
250
257
  } catch (err) {
251
- console.warn(
252
- `[middleware] "${mw.name}" onChatEnd error:`,
253
- err instanceof Error ? err.message : String(err)
254
- );
258
+ this.log.warn(`"${mw.name}" onChatEnd error: ${err instanceof Error ? err.message : String(err)}`);
255
259
  }
256
260
  }
257
261
  }
258
262
  };
259
263
 
260
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
+ }
261
268
  function approvalMiddleware(config = {}) {
262
269
  const handler = createApprovalHandler(config);
263
270
  return {
264
271
  name: "approval",
272
+ approvalHandler: handler,
273
+ ...config.customRisks ? { approvalCustomRisks: config.customRisks } : {},
265
274
  async beforeToolCall(tool, args, ctx) {
266
275
  try {
267
- 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
+ );
268
284
  return { action: "allow" };
269
285
  } catch (err) {
270
- const reason = err instanceof Error ? err.message : `Approval denied: ${tool}`;
271
- 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
+ };
272
295
  }
273
296
  }
274
297
  };
@@ -276,6 +299,56 @@ function approvalMiddleware(config = {}) {
276
299
 
277
300
  // src/middleware/telemetry/otel.ts
278
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
+ }
279
352
  function getInputMimeType(value) {
280
353
  const trimmed = value.trimStart();
281
354
  return trimmed.startsWith("{") || trimmed.startsWith("[") ? "application/json" : "text/plain";
@@ -304,7 +377,7 @@ function scheduleSpanTimeout(options) {
304
377
  function otelMiddleware(config = {}) {
305
378
  const recordInputs = config.recordInputs ?? true;
306
379
  const recordOutputs = config.recordOutputs ?? true;
307
- const agentName = config.agentName ?? "agent";
380
+ const agentName = config.agentName ?? DEFAULT_AGENT_NAME;
308
381
  const emitToolSpans = config.emitToolSpans ?? true;
309
382
  const spanTimeoutMs = config.spanTimeoutMs ?? 5 * 60 * 1e3;
310
383
  const chatSpans = /* @__PURE__ */ new Map();
@@ -315,6 +388,9 @@ function otelMiddleware(config = {}) {
315
388
  if (tracer) {
316
389
  return tracer;
317
390
  }
391
+ if (config.providerReady) {
392
+ await config.providerReady;
393
+ }
318
394
  otel = await getOtelModule();
319
395
  if (!otel) {
320
396
  return null;
@@ -324,20 +400,25 @@ function otelMiddleware(config = {}) {
324
400
  }
325
401
  return {
326
402
  name: "opentelemetry",
327
- getOtelContext(sessionId) {
328
- 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;
329
406
  },
330
- async onChatStart(sessionId, message) {
407
+ async onChatStart(sessionId, message, chatCtx) {
331
408
  const activeTracer = await ensureTracer();
332
409
  if (!activeTracer || !otel) {
333
410
  return;
334
411
  }
412
+ const key = makeChatSpanKey(sessionId, chatCtx?.turnId);
335
413
  const attributes = {
336
414
  "openinference.span.kind": "AGENT",
337
415
  "gen_ai.operation.name": "invoke_agent",
338
416
  "gen_ai.agent.name": agentName,
339
417
  "gen_ai.agent.session_id": sessionId
340
418
  };
419
+ if (chatCtx?.turnId) {
420
+ attributes["gen_ai.agent.turn_id"] = chatCtx.turnId;
421
+ }
341
422
  if (config.agentDescription) {
342
423
  attributes["gen_ai.agent.description"] = config.agentDescription;
343
424
  }
@@ -349,13 +430,13 @@ function otelMiddleware(config = {}) {
349
430
  const span = activeTracer.startSpan(`invoke_agent ${agentName}`, {
350
431
  attributes
351
432
  });
352
- const ctx = otel.trace.setSpan(otel.context.active(), span);
353
- chatSpans.set(sessionId, {
433
+ const spanCtx = otel.trace.setSpan(otel.context.active(), span);
434
+ chatSpans.set(key, {
354
435
  span,
355
- ctx,
436
+ ctx: spanCtx,
356
437
  timer: scheduleSpanTimeout({
357
438
  spans: chatSpans,
358
- key: sessionId,
439
+ key,
359
440
  otel,
360
441
  timeoutMs: spanTimeoutMs
361
442
  })
@@ -370,7 +451,10 @@ function otelMiddleware(config = {}) {
370
451
  return { action: "allow" };
371
452
  }
372
453
  const sessionId = ctx?.sessionID;
373
- 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;
374
458
  const parentCtx = parent?.ctx ?? otel.context.active();
375
459
  const span = activeTracer.startSpan(
376
460
  `execute_tool ${tool}`,
@@ -392,8 +476,8 @@ function otelMiddleware(config = {}) {
392
476
  },
393
477
  parentCtx
394
478
  );
395
- const callId = ctx?.messageID ?? JSON.stringify(args);
396
- const key = `${tool}:${callId}`;
479
+ const callId = resolveToolCallId(args, ctx);
480
+ const key = makeToolSpanKey(tool, callId);
397
481
  const toolCtx = otel.trace.setSpan(parentCtx, span);
398
482
  toolSpans.set(key, {
399
483
  span,
@@ -408,12 +492,13 @@ function otelMiddleware(config = {}) {
408
492
  return { action: "allow" };
409
493
  },
410
494
  async afterToolCall(tool, args, result, ctx) {
411
- const callId = ctx?.messageID ?? JSON.stringify(args);
412
- const keyPrefix = `${tool}:`;
413
- const key = `${tool}:${callId}`;
414
- const entry = toolSpans.get(key) ?? Array.from(toolSpans.entries()).find(
415
- ([candidate]) => candidate.startsWith(keyPrefix)
416
- )?.[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);
417
502
  if (entry) {
418
503
  if (entry.timer) {
419
504
  clearTimeout(entry.timer);
@@ -426,12 +511,6 @@ function otelMiddleware(config = {}) {
426
511
  }
427
512
  entry.span.setStatus({ code: otel?.SpanStatusCode.OK ?? 1 });
428
513
  entry.span.end();
429
- for (const [candidateKey, candidateEntry] of toolSpans) {
430
- if (candidateEntry === entry) {
431
- toolSpans.delete(candidateKey);
432
- break;
433
- }
434
- }
435
514
  }
436
515
  return result;
437
516
  },
@@ -439,10 +518,13 @@ function otelMiddleware(config = {}) {
439
518
  if (event.type !== "tool-error") {
440
519
  return;
441
520
  }
442
- for (const [key, entry] of toolSpans) {
443
- if (!key.startsWith(`${event.toolName}:`)) {
444
- continue;
445
- }
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) {
446
528
  if (entry.timer) {
447
529
  clearTimeout(entry.timer);
448
530
  }
@@ -455,12 +537,14 @@ function otelMiddleware(config = {}) {
455
537
  message: event.error
456
538
  });
457
539
  entry.span.end();
458
- toolSpans.delete(key);
459
- break;
460
540
  }
461
541
  },
462
- async onChatEnd(sessionId, result) {
463
- 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);
464
548
  if (!entry) {
465
549
  return;
466
550
  }
@@ -489,34 +573,38 @@ function otelMiddleware(config = {}) {
489
573
  entry.span.setStatus({ code: otel?.SpanStatusCode.OK ?? 1 });
490
574
  }
491
575
  entry.span.end();
492
- chatSpans.delete(sessionId);
576
+ chatSpans.delete(key);
493
577
  }
494
578
  };
495
579
  }
496
580
 
497
581
  // src/middleware/telemetry/provider.ts
582
+ var sharedProviderState;
498
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
+ }
499
593
  const middleware = otelMiddleware({
500
594
  agentName: config.agentName,
501
595
  agentDescription: config.agentDescription,
502
- recordInputs: config.recordInputs,
503
- recordOutputs: config.recordOutputs,
596
+ recordInputs,
597
+ recordOutputs,
504
598
  emitToolSpans: config.emitToolSpans,
505
- spanTimeoutMs: config.spanTimeoutMs
599
+ spanTimeoutMs: config.spanTimeoutMs,
600
+ providerReady: providerPromise
506
601
  });
507
602
  const telemetry = {
508
603
  isEnabled: true,
509
604
  functionId: config.agentName,
510
- recordInputs: config.recordInputs,
511
- recordOutputs: config.recordOutputs
605
+ recordInputs,
606
+ recordOutputs
512
607
  };
513
- let providerPromise;
514
- if (config.spanProcessor) {
515
- providerPromise = createAndRegisterProvider(
516
- config.spanProcessor,
517
- config.serviceName ?? config.agentName
518
- );
519
- }
520
608
  return {
521
609
  middleware,
522
610
  telemetry,
@@ -524,12 +612,46 @@ function createTelemetryConfig(config) {
524
612
  if (!providerPromise) {
525
613
  return;
526
614
  }
527
- const provider = await providerPromise;
528
- await provider.forceFlush();
529
- await provider.shutdown();
615
+ await releaseSharedProvider(providerPromise);
530
616
  }
531
617
  };
532
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
+ }
533
655
  async function createAndRegisterProvider(spanProcessor, serviceName) {
534
656
  const [{ NodeTracerProvider }, { resourceFromAttributes }, { ATTR_SERVICE_NAME }] = await Promise.all([
535
657
  import("@opentelemetry/sdk-trace-node"),
@@ -547,14 +669,14 @@ async function createAndRegisterProvider(spanProcessor, serviceName) {
547
669
 
548
670
  // src/middleware/prompt-cache/cache.ts
549
671
  function detectCacheProvider(input) {
550
- const provider = getProviderId(input.model);
672
+ const provider = extractProvider(input.model);
551
673
  if (provider) {
552
674
  const p = provider.toLowerCase();
553
675
  if (p === "anthropic") return "anthropic";
554
676
  if (p === "openai") return "openai";
555
677
  if (p === "google") return "google";
556
678
  }
557
- const modelId = getModelId(input.model);
679
+ const modelId = extractModelId(input.model);
558
680
  if (/claude/i.test(modelId)) return "anthropic";
559
681
  return "unknown";
560
682
  }
@@ -642,8 +764,9 @@ function promptCacheMiddleware(config) {
642
764
 
643
765
  export {
644
766
  MiddlewareRunner,
767
+ isApprovalMiddleware,
768
+ approvalMiddleware,
645
769
  otelMiddleware,
646
770
  createTelemetryConfig,
647
- approvalMiddleware,
648
771
  promptCacheMiddleware
649
772
  };