@openbox-ai/openbox-mastra-sdk 0.1.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 (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +158 -0
  3. package/dist/client/index.d.ts +4 -0
  4. package/dist/client/index.js +2 -0
  5. package/dist/client/index.js.map +1 -0
  6. package/dist/client/openbox-client.d.ts +42 -0
  7. package/dist/client/openbox-client.js +405 -0
  8. package/dist/client/openbox-client.js.map +1 -0
  9. package/dist/config/index.d.ts +5 -0
  10. package/dist/config/index.js +2 -0
  11. package/dist/config/index.js.map +1 -0
  12. package/dist/config/openbox-config.d.ts +54 -0
  13. package/dist/config/openbox-config.js +162 -0
  14. package/dist/config/openbox-config.js.map +1 -0
  15. package/dist/governance/activity-runtime.d.ts +42 -0
  16. package/dist/governance/activity-runtime.js +712 -0
  17. package/dist/governance/activity-runtime.js.map +1 -0
  18. package/dist/governance/approval-registry.d.ts +17 -0
  19. package/dist/governance/approval-registry.js +32 -0
  20. package/dist/governance/approval-registry.js.map +1 -0
  21. package/dist/governance/context.d.ts +16 -0
  22. package/dist/governance/context.js +13 -0
  23. package/dist/governance/context.js.map +1 -0
  24. package/dist/governance/index.d.ts +2 -0
  25. package/dist/governance/index.js +1 -0
  26. package/dist/governance/index.js.map +1 -0
  27. package/dist/index.d.ts +18 -0
  28. package/dist/index.js +8 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/mastra/index.d.ts +16 -0
  31. package/dist/mastra/index.js +5 -0
  32. package/dist/mastra/index.js.map +1 -0
  33. package/dist/mastra/with-openbox.d.ts +30 -0
  34. package/dist/mastra/with-openbox.js +243 -0
  35. package/dist/mastra/with-openbox.js.map +1 -0
  36. package/dist/mastra/wrap-agent.d.ts +14 -0
  37. package/dist/mastra/wrap-agent.js +1744 -0
  38. package/dist/mastra/wrap-agent.js.map +1 -0
  39. package/dist/mastra/wrap-tool.d.ts +18 -0
  40. package/dist/mastra/wrap-tool.js +49 -0
  41. package/dist/mastra/wrap-tool.js.map +1 -0
  42. package/dist/mastra/wrap-workflow.d.ts +14 -0
  43. package/dist/mastra/wrap-workflow.js +386 -0
  44. package/dist/mastra/wrap-workflow.js.map +1 -0
  45. package/dist/otel/index.d.ts +11 -0
  46. package/dist/otel/index.js +2 -0
  47. package/dist/otel/index.js.map +1 -0
  48. package/dist/otel/setup-openbox-opentelemetry.d.ts +38 -0
  49. package/dist/otel/setup-openbox-opentelemetry.js +2249 -0
  50. package/dist/otel/setup-openbox-opentelemetry.js.map +1 -0
  51. package/dist/span/index.d.ts +5 -0
  52. package/dist/span/index.js +2 -0
  53. package/dist/span/index.js.map +1 -0
  54. package/dist/span/openbox-span-processor.d.ts +90 -0
  55. package/dist/span/openbox-span-processor.js +580 -0
  56. package/dist/span/openbox-span-processor.js.map +1 -0
  57. package/dist/types/errors.d.ts +25 -0
  58. package/dist/types/errors.js +40 -0
  59. package/dist/types/errors.js.map +1 -0
  60. package/dist/types/governance-verdict-response.d.ts +57 -0
  61. package/dist/types/governance-verdict-response.js +84 -0
  62. package/dist/types/governance-verdict-response.js.map +1 -0
  63. package/dist/types/guardrails.d.ts +23 -0
  64. package/dist/types/guardrails.js +27 -0
  65. package/dist/types/guardrails.js.map +1 -0
  66. package/dist/types/index.d.ts +6 -0
  67. package/dist/types/index.js +7 -0
  68. package/dist/types/index.js.map +1 -0
  69. package/dist/types/verdict.d.ts +22 -0
  70. package/dist/types/verdict.js +55 -0
  71. package/dist/types/verdict.js.map +1 -0
  72. package/dist/types/workflow-event-type.d.ts +10 -0
  73. package/dist/types/workflow-event-type.js +13 -0
  74. package/dist/types/workflow-event-type.js.map +1 -0
  75. package/dist/types/workflow-span-buffer.d.ts +31 -0
  76. package/dist/types/workflow-span-buffer.js +42 -0
  77. package/dist/types/workflow-span-buffer.js.map +1 -0
  78. package/docs/README.md +66 -0
  79. package/docs/api-reference.md +348 -0
  80. package/docs/approvals-and-guardrails.md +163 -0
  81. package/docs/architecture.md +186 -0
  82. package/docs/configuration.md +214 -0
  83. package/docs/event-model.md +215 -0
  84. package/docs/installation.md +108 -0
  85. package/docs/integration-patterns.md +214 -0
  86. package/docs/security-and-privacy.md +174 -0
  87. package/docs/telemetry.md +196 -0
  88. package/docs/troubleshooting.md +210 -0
  89. package/package.json +136 -0
@@ -0,0 +1,1744 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { trace } from "@opentelemetry/api";
3
+ import {
4
+ clearPendingApproval,
5
+ getPendingApproval,
6
+ markActivityApproved
7
+ } from "../governance/approval-registry.js";
8
+ import {
9
+ normalizeSpansForGovernance,
10
+ serializeValue
11
+ } from "../governance/activity-runtime.js";
12
+ import { runWithOpenBoxExecutionContext } from "../governance/context.js";
13
+ import {
14
+ ApprovalExpiredError,
15
+ ApprovalPendingError,
16
+ ApprovalRejectedError,
17
+ GovernanceAPIError,
18
+ GovernanceHaltError,
19
+ Verdict,
20
+ WorkflowEventType,
21
+ WorkflowSpanBuffer
22
+ } from "../types/index.js";
23
+ const OPENBOX_WRAPPED_AGENT = /* @__PURE__ */ Symbol.for("openbox.mastra.wrapAgent");
24
+ const OPENBOX_AGENT_STREAM_META = /* @__PURE__ */ Symbol.for("openbox.mastra.wrapAgent.streamMeta");
25
+ const AGENT_INPUT_SIGNAL_NAME = "user_input";
26
+ const AGENT_OUTPUT_SIGNAL_NAME = "agent_output";
27
+ const OPENBOX_AGENT_RUN_GOALS = /* @__PURE__ */ new Map();
28
+ const OPENBOX_AGENT_SIGNAL_SPAN_CURSOR = /* @__PURE__ */ new Map();
29
+ const MAX_AGENT_OUTPUT_SIGNAL_SPANS = 8;
30
+ const MAX_AGENT_SIGNAL_SPAN_BODY_CHARS = 12e3;
31
+ async function resolveAgentGoal(baseAgent, executionOptions = {}, interactionPayload) {
32
+ const configuredGoal = normalizeGoalCandidate(process.env.OPENBOX_AGENT_GOAL);
33
+ if (configuredGoal) {
34
+ return configuredGoal;
35
+ }
36
+ const runIdCandidate = executionOptions && typeof executionOptions === "object" && "runId" in executionOptions ? executionOptions.runId : void 0;
37
+ const runId = typeof runIdCandidate === "string" && runIdCandidate.trim().length > 0 ? runIdCandidate : void 0;
38
+ const persistedGoal = runId ? OPENBOX_AGENT_RUN_GOALS.get(runId) : void 0;
39
+ if (persistedGoal) {
40
+ return persistedGoal;
41
+ }
42
+ const interactionGoal = normalizeGoalCandidate(
43
+ extractGoalCandidateFromInteraction(interactionPayload)
44
+ );
45
+ if (interactionGoal) {
46
+ return interactionGoal;
47
+ }
48
+ const getInstructions = baseAgent.getInstructions;
49
+ if (typeof getInstructions !== "function") {
50
+ return void 0;
51
+ }
52
+ try {
53
+ const requestContext = executionOptions && typeof executionOptions === "object" && "requestContext" in executionOptions ? executionOptions.requestContext : void 0;
54
+ const instructions = await Promise.resolve(
55
+ requestContext !== void 0 ? getInstructions.call(baseAgent, { requestContext }) : getInstructions.call(baseAgent)
56
+ );
57
+ return normalizeGoalCandidate(instructions);
58
+ } catch {
59
+ return void 0;
60
+ }
61
+ }
62
+ function normalizeGoalCandidate(value) {
63
+ const text = extractTextFromStructuredValue(value);
64
+ if (!text) {
65
+ return void 0;
66
+ }
67
+ const normalized = text.trim();
68
+ if (normalized.length === 0) {
69
+ return void 0;
70
+ }
71
+ return truncateString(normalized, 1e3);
72
+ }
73
+ function extractGoalCandidateFromInteraction(value) {
74
+ const latestUserPrompt = extractLatestUserPrompt(value);
75
+ if (latestUserPrompt) {
76
+ return latestUserPrompt;
77
+ }
78
+ return extractTextFromStructuredValue(value);
79
+ }
80
+ function wrapAgent(agent, options) {
81
+ const baseAgent = agent;
82
+ if (baseAgent[OPENBOX_WRAPPED_AGENT]) {
83
+ return agent;
84
+ }
85
+ const workflowType = String(baseAgent.id ?? baseAgent.name ?? "agent");
86
+ const workflowId = `agent:${workflowType}`;
87
+ const originalGenerate = baseAgent.generate?.bind(baseAgent);
88
+ const originalStream = baseAgent.stream?.bind(baseAgent);
89
+ const originalResumeGenerate = baseAgent.resumeGenerate?.bind(baseAgent);
90
+ const originalResumeStream = baseAgent.resumeStream?.bind(baseAgent);
91
+ if (originalGenerate) {
92
+ baseAgent.generate = async (messages, executionOptions = {}) => {
93
+ const runId = String(executionOptions.runId ?? randomUUID());
94
+ const agentGoal = await resolveAgentGoal(
95
+ baseAgent,
96
+ executionOptions,
97
+ messages
98
+ );
99
+ const nextOptions = {
100
+ ...executionOptions,
101
+ runId
102
+ };
103
+ const invocationModelInfo = resolveInvocationModelInfo(
104
+ baseAgent,
105
+ executionOptions
106
+ );
107
+ return executeAgentLifecycle(
108
+ {
109
+ messages,
110
+ operation: () => originalGenerate(messages, nextOptions),
111
+ options,
112
+ phase: "start",
113
+ runId,
114
+ workflowId,
115
+ workflowType,
116
+ defaultModelInfo: invocationModelInfo,
117
+ ...agentGoal ? { agentGoal } : {}
118
+ }
119
+ );
120
+ };
121
+ }
122
+ if (originalStream) {
123
+ baseAgent.stream = async (messages, executionOptions = {}) => {
124
+ const runId = String(executionOptions.runId ?? randomUUID());
125
+ const agentGoal = await resolveAgentGoal(
126
+ baseAgent,
127
+ executionOptions,
128
+ messages
129
+ );
130
+ const nextOptions = {
131
+ ...executionOptions,
132
+ runId
133
+ };
134
+ const invocationModelInfo = resolveInvocationModelInfo(
135
+ baseAgent,
136
+ executionOptions
137
+ );
138
+ const output = await executeAgentLifecycle(
139
+ {
140
+ messages,
141
+ operation: () => originalStream(messages, nextOptions),
142
+ options,
143
+ phase: "start",
144
+ runId,
145
+ workflowId,
146
+ workflowType,
147
+ defaultModelInfo: invocationModelInfo,
148
+ ...agentGoal ? { agentGoal } : {}
149
+ }
150
+ );
151
+ if (output && typeof output === "object") {
152
+ const streamMeta = getAgentStreamMeta(output);
153
+ attachStreamLifecycleHandlers(output, {
154
+ onFailure: async (error) => {
155
+ await sendAgentFailure(
156
+ options,
157
+ runId,
158
+ workflowId,
159
+ workflowType,
160
+ error,
161
+ streamMeta,
162
+ agentGoal
163
+ );
164
+ },
165
+ onSuccess: async (fullOutput) => {
166
+ await finalizeAgentSuccess(
167
+ options,
168
+ runId,
169
+ workflowId,
170
+ workflowType,
171
+ fullOutput,
172
+ streamMeta,
173
+ invocationModelInfo,
174
+ agentGoal
175
+ );
176
+ }
177
+ });
178
+ }
179
+ return output;
180
+ };
181
+ }
182
+ if (originalResumeGenerate) {
183
+ baseAgent.resumeGenerate = async (resumeData, executionOptions = {}) => {
184
+ const runId = executionOptions.runId ? String(executionOptions.runId) : void 0;
185
+ const agentGoal = await resolveAgentGoal(baseAgent, executionOptions);
186
+ await handleAgentResume(
187
+ options,
188
+ runId,
189
+ workflowId,
190
+ workflowType,
191
+ resumeData,
192
+ agentGoal
193
+ );
194
+ const invocationModelInfo = resolveInvocationModelInfo(
195
+ baseAgent,
196
+ executionOptions
197
+ );
198
+ return executeAgentLifecycle({
199
+ operation: () => originalResumeGenerate(resumeData, executionOptions),
200
+ options,
201
+ phase: "resume",
202
+ runId: runId ?? randomUUID(),
203
+ workflowId,
204
+ workflowType,
205
+ defaultModelInfo: invocationModelInfo,
206
+ ...agentGoal ? { agentGoal } : {}
207
+ });
208
+ };
209
+ }
210
+ if (originalResumeStream) {
211
+ baseAgent.resumeStream = async (resumeData, executionOptions = {}) => {
212
+ const runId = executionOptions.runId ? String(executionOptions.runId) : void 0;
213
+ const resolvedRunId = runId ?? randomUUID();
214
+ const agentGoal = await resolveAgentGoal(baseAgent, executionOptions);
215
+ await handleAgentResume(
216
+ options,
217
+ runId,
218
+ workflowId,
219
+ workflowType,
220
+ resumeData,
221
+ agentGoal
222
+ );
223
+ const invocationModelInfo = resolveInvocationModelInfo(
224
+ baseAgent,
225
+ executionOptions
226
+ );
227
+ const output = await executeAgentLifecycle({
228
+ operation: () => originalResumeStream(resumeData, executionOptions),
229
+ options,
230
+ phase: "resume",
231
+ runId: resolvedRunId,
232
+ workflowId,
233
+ workflowType,
234
+ defaultModelInfo: invocationModelInfo,
235
+ ...agentGoal ? { agentGoal } : {}
236
+ });
237
+ if (output && typeof output === "object") {
238
+ const streamMeta = getAgentStreamMeta(output);
239
+ attachStreamLifecycleHandlers(output, {
240
+ onFailure: async (error) => {
241
+ await sendAgentFailure(
242
+ options,
243
+ resolvedRunId,
244
+ workflowId,
245
+ workflowType,
246
+ error,
247
+ streamMeta,
248
+ agentGoal
249
+ );
250
+ },
251
+ onSuccess: async (fullOutput) => {
252
+ await finalizeAgentSuccess(
253
+ options,
254
+ resolvedRunId,
255
+ workflowId,
256
+ workflowType,
257
+ fullOutput,
258
+ streamMeta,
259
+ invocationModelInfo,
260
+ agentGoal
261
+ );
262
+ }
263
+ });
264
+ }
265
+ return output;
266
+ };
267
+ }
268
+ Object.defineProperty(baseAgent, OPENBOX_WRAPPED_AGENT, {
269
+ enumerable: false,
270
+ value: true
271
+ });
272
+ return agent;
273
+ }
274
+ async function executeAgentLifecycle({
275
+ messages,
276
+ operation,
277
+ options,
278
+ phase,
279
+ runId,
280
+ workflowId,
281
+ workflowType,
282
+ defaultModelInfo,
283
+ agentGoal
284
+ }) {
285
+ const effectiveGoal = agentGoal ?? normalizeGoalCandidate(extractGoalCandidateFromInteraction(messages));
286
+ if (effectiveGoal) {
287
+ OPENBOX_AGENT_RUN_GOALS.set(runId, effectiveGoal);
288
+ }
289
+ if (phase === "start" && !options.config.skipWorkflowTypes.has(workflowType) && options.config.sendStartEvent) {
290
+ const verdict = await evaluateAgentEvent(options, {
291
+ event_type: WorkflowEventType.WORKFLOW_STARTED,
292
+ ...effectiveGoal ? { goal: effectiveGoal } : {},
293
+ run_id: runId,
294
+ task_queue: "mastra",
295
+ workflow_id: workflowId,
296
+ workflow_input: serializeWorkflowInputForGovernance(
297
+ messages,
298
+ effectiveGoal
299
+ ),
300
+ workflow_type: workflowType
301
+ });
302
+ if (verdict && Verdict.shouldStop(verdict.verdict)) {
303
+ throw new GovernanceHaltError(
304
+ verdict.reason ?? "Agent blocked by governance"
305
+ );
306
+ }
307
+ }
308
+ if (phase === "start" && messages !== void 0 && !options.config.skipWorkflowTypes.has(workflowType) && !options.config.skipSignals.has(AGENT_INPUT_SIGNAL_NAME)) {
309
+ const verdict = await evaluateAgentEvent(options, {
310
+ event_type: WorkflowEventType.SIGNAL_RECEIVED,
311
+ ...effectiveGoal ? { goal: effectiveGoal } : {},
312
+ run_id: runId,
313
+ signal_args: serializeAgentSignalArgs(messages, effectiveGoal),
314
+ signal_name: AGENT_INPUT_SIGNAL_NAME,
315
+ task_queue: "mastra",
316
+ workflow_id: workflowId,
317
+ workflow_type: workflowType
318
+ });
319
+ if (verdict && Verdict.shouldStop(verdict.verdict)) {
320
+ throw new GovernanceHaltError(
321
+ verdict.reason ?? "Agent blocked by governance"
322
+ );
323
+ }
324
+ }
325
+ ensureAgentSpanBuffer(options, runId, workflowId, workflowType);
326
+ const startTimeMs = Date.now();
327
+ return runWithOpenBoxExecutionContext(
328
+ {
329
+ agentId: workflowType,
330
+ ...effectiveGoal ? { goal: effectiveGoal } : {},
331
+ runId,
332
+ source: "agent",
333
+ taskQueue: "mastra",
334
+ workflowId,
335
+ workflowType
336
+ },
337
+ async () => {
338
+ try {
339
+ const result = await trace.getTracer("openbox.mastra").startActiveSpan(`agent.${phase}.${workflowType}`, async (activeSpan) => {
340
+ activeSpan.setAttribute("openbox.workflow_id", workflowId);
341
+ activeSpan.setAttribute("openbox.activity_id", `agent:${workflowType}:${phase}`);
342
+ activeSpan.setAttribute("openbox.run_id", runId);
343
+ options.spanProcessor.registerTrace(
344
+ activeSpan.spanContext().traceId,
345
+ workflowId,
346
+ `agent:${workflowType}:${phase}`,
347
+ runId
348
+ );
349
+ try {
350
+ return await operation();
351
+ } finally {
352
+ activeSpan.end();
353
+ }
354
+ });
355
+ const isStreamResult = result != null && typeof result === "object" && ("getFullOutput" in result || "fullStream" in result);
356
+ if (!isStreamResult) {
357
+ const finishReason = result != null && typeof result === "object" ? result.finishReason : void 0;
358
+ if (finishReason === "suspended") {
359
+ return result;
360
+ }
361
+ await finalizeAgentSuccess(
362
+ options,
363
+ runId,
364
+ workflowId,
365
+ workflowType,
366
+ result,
367
+ {
368
+ startTimeMs
369
+ },
370
+ defaultModelInfo,
371
+ effectiveGoal
372
+ );
373
+ }
374
+ if (isStreamResult) {
375
+ setAgentStreamMeta(result, {
376
+ startTimeMs
377
+ });
378
+ }
379
+ return result;
380
+ } catch (error) {
381
+ await sendAgentFailure(
382
+ options,
383
+ runId,
384
+ workflowId,
385
+ workflowType,
386
+ error,
387
+ {
388
+ startTimeMs
389
+ },
390
+ effectiveGoal
391
+ );
392
+ throw error;
393
+ }
394
+ }
395
+ );
396
+ }
397
+ async function handleAgentResume(options, runId, workflowId, workflowType, resumeData, agentGoal) {
398
+ if (!runId) {
399
+ return;
400
+ }
401
+ const effectiveGoal = agentGoal ?? OPENBOX_AGENT_RUN_GOALS.get(runId);
402
+ if (effectiveGoal) {
403
+ OPENBOX_AGENT_RUN_GOALS.set(runId, effectiveGoal);
404
+ }
405
+ if (!options.config.skipWorkflowTypes.has(workflowType) && !options.config.skipSignals.has("resume")) {
406
+ const verdict2 = await evaluateAgentEvent(options, {
407
+ event_type: WorkflowEventType.SIGNAL_RECEIVED,
408
+ ...effectiveGoal ? { goal: effectiveGoal } : {},
409
+ run_id: runId,
410
+ signal_args: appendGoalToSignalArgs(
411
+ serializeValue(resumeData),
412
+ effectiveGoal
413
+ ),
414
+ signal_name: "resume",
415
+ task_queue: "mastra",
416
+ workflow_id: workflowId,
417
+ workflow_type: workflowType
418
+ });
419
+ if (verdict2 && Verdict.shouldStop(verdict2.verdict)) {
420
+ throw new GovernanceHaltError(
421
+ verdict2.reason ?? "Agent blocked by governance"
422
+ );
423
+ }
424
+ }
425
+ const pending = getPendingApproval(runId);
426
+ if (!pending) {
427
+ return;
428
+ }
429
+ const approval = await options.client.pollApproval({
430
+ activityId: pending.activityId,
431
+ runId: pending.runId,
432
+ workflowId: pending.workflowId
433
+ });
434
+ if (!approval) {
435
+ throw new ApprovalPendingError("Failed to check approval status, retrying...");
436
+ }
437
+ if (approval.expired) {
438
+ clearPendingApproval(runId);
439
+ throw new ApprovalExpiredError(
440
+ `Approval expired for activity ${pending.activityType}`
441
+ );
442
+ }
443
+ const verdict = Verdict.fromString(
444
+ approval.verdict ?? approval.action
445
+ );
446
+ if (verdict === Verdict.ALLOW) {
447
+ markActivityApproved(pending.runId, pending.activityId);
448
+ clearPendingApproval(runId);
449
+ return;
450
+ }
451
+ if (Verdict.shouldStop(verdict)) {
452
+ clearPendingApproval(runId);
453
+ throw new ApprovalRejectedError(
454
+ `Activity rejected: ${String(approval.reason ?? "Activity rejected")}`
455
+ );
456
+ }
457
+ throw new ApprovalPendingError(
458
+ `Awaiting approval for activity ${pending.activityType}`
459
+ );
460
+ }
461
+ async function finalizeAgentSuccess(options, runId, workflowId, workflowType, output, streamMeta, defaultModelInfo = {}, agentGoal) {
462
+ if (options.config.skipWorkflowTypes.has(workflowType)) {
463
+ clearAgentRunState(runId);
464
+ return;
465
+ }
466
+ try {
467
+ await emitAgentOutputSignal(
468
+ options,
469
+ runId,
470
+ workflowId,
471
+ workflowType,
472
+ output,
473
+ agentGoal
474
+ );
475
+ const workflowSpans = normalizeSpansForGovernance(
476
+ options.spanProcessor.getBuffer(workflowId, runId)?.spans ?? []
477
+ );
478
+ const modelInfo = resolveWorkflowModelInfo(
479
+ output,
480
+ defaultModelInfo,
481
+ workflowSpans
482
+ );
483
+ const resolvedOutput = applyDefaultModelInfo(output, modelInfo);
484
+ const basePayload = {
485
+ event_type: WorkflowEventType.WORKFLOW_COMPLETED,
486
+ ...agentGoal ? { goal: agentGoal } : {},
487
+ run_id: runId,
488
+ workflow_id: workflowId,
489
+ workflow_type: workflowType
490
+ };
491
+ const workflowOutput = serializeWorkflowOutputForGovernance(resolvedOutput);
492
+ const telemetryPayload = buildWorkflowCompletedTelemetryPayload(
493
+ {
494
+ ...basePayload,
495
+ workflow_output: workflowOutput
496
+ },
497
+ resolvedOutput,
498
+ workflowSpans,
499
+ modelInfo,
500
+ streamMeta
501
+ );
502
+ const compactPayload = buildWorkflowCompletedCompactPayload(
503
+ basePayload,
504
+ workflowOutput,
505
+ resolvedOutput,
506
+ modelInfo,
507
+ streamMeta
508
+ );
509
+ const ultraMinimalPayload = buildWorkflowCompletedUltraMinimalPayload(
510
+ basePayload,
511
+ resolvedOutput,
512
+ modelInfo,
513
+ streamMeta
514
+ );
515
+ const verdict = await evaluateAgentEvent(
516
+ options,
517
+ telemetryPayload,
518
+ compactPayload,
519
+ ultraMinimalPayload
520
+ );
521
+ if (verdict && Verdict.shouldStop(verdict.verdict)) {
522
+ throw new GovernanceHaltError(
523
+ verdict.reason ?? "Agent blocked by governance"
524
+ );
525
+ }
526
+ } finally {
527
+ clearAgentRunState(runId);
528
+ }
529
+ }
530
+ function buildWorkflowCompletedCompactPayload(basePayload, workflowOutput, output, modelInfo, streamMeta) {
531
+ const endTimeMs = Date.now();
532
+ const startTimeMs = streamMeta?.startTimeMs;
533
+ const durationMs = typeof startTimeMs === "number" ? Math.max(0, endTimeMs - startTimeMs) : void 0;
534
+ const usage = extractUsageMetrics(output);
535
+ const telemetryModelId = toTelemetryModelId(modelInfo.modelId);
536
+ const syntheticSpans = buildWorkflowTelemetrySpans(
537
+ [],
538
+ modelInfo,
539
+ usage,
540
+ endTimeMs
541
+ );
542
+ const payload = {
543
+ event_type: basePayload.event_type,
544
+ run_id: basePayload.run_id,
545
+ workflow_id: basePayload.workflow_id,
546
+ workflow_type: basePayload.workflow_type,
547
+ ...typeof durationMs === "number" ? { duration_ms: durationMs } : {},
548
+ ...typeof startTimeMs === "number" ? { start_time: startTimeMs } : {},
549
+ end_time: endTimeMs,
550
+ ...typeof usage.inputTokens === "number" ? { input_tokens: usage.inputTokens } : {},
551
+ ...typeof usage.outputTokens === "number" ? { output_tokens: usage.outputTokens } : {},
552
+ ...typeof usage.totalTokens === "number" ? { total_tokens: usage.totalTokens } : {},
553
+ ...modelInfo.modelId ? { model_id: modelInfo.modelId } : {},
554
+ ...telemetryModelId ? { model: telemetryModelId } : {},
555
+ ...modelInfo.provider ? { model_provider: modelInfo.provider } : {},
556
+ ...modelInfo.provider ? { provider: modelInfo.provider } : {},
557
+ ...syntheticSpans.length > 0 ? {
558
+ span_count: syntheticSpans.length,
559
+ spans: syntheticSpans
560
+ } : {
561
+ span_count: 0
562
+ }
563
+ };
564
+ const compactOutput = compactWorkflowOutput(workflowOutput);
565
+ if (compactOutput !== void 0) {
566
+ payload.workflow_output = compactOutput;
567
+ }
568
+ return payload;
569
+ }
570
+ function buildWorkflowCompletedUltraMinimalPayload(basePayload, output, modelInfo, streamMeta) {
571
+ const endTimeMs = Date.now();
572
+ const startTimeMs = streamMeta?.startTimeMs;
573
+ const durationMs = typeof startTimeMs === "number" ? Math.max(0, endTimeMs - startTimeMs) : void 0;
574
+ const usage = extractUsageMetrics(output);
575
+ const telemetryModelId = toTelemetryModelId(modelInfo.modelId);
576
+ return {
577
+ ...basePayload,
578
+ ...typeof durationMs === "number" ? { duration_ms: durationMs } : {},
579
+ ...typeof startTimeMs === "number" ? { start_time: startTimeMs } : {},
580
+ end_time: endTimeMs,
581
+ ...typeof usage.inputTokens === "number" ? { input_tokens: usage.inputTokens } : {},
582
+ ...typeof usage.outputTokens === "number" ? { output_tokens: usage.outputTokens } : {},
583
+ ...typeof usage.totalTokens === "number" ? { total_tokens: usage.totalTokens } : {},
584
+ ...modelInfo.modelId ? { model_id: modelInfo.modelId } : {},
585
+ ...telemetryModelId ? { model: telemetryModelId } : {},
586
+ ...modelInfo.provider ? { model_provider: modelInfo.provider } : {},
587
+ ...modelInfo.provider ? { provider: modelInfo.provider } : {}
588
+ };
589
+ }
590
+ function buildWorkflowCompletedTelemetryPayload(basePayload, output, workflowSpans, modelInfo, streamMeta) {
591
+ const endTimeMs = Date.now();
592
+ const startTimeMs = streamMeta?.startTimeMs;
593
+ const durationMs = typeof startTimeMs === "number" ? Math.max(0, endTimeMs - startTimeMs) : void 0;
594
+ const usage = extractUsageMetrics(output);
595
+ const telemetryModelId = toTelemetryModelId(modelInfo.modelId);
596
+ const spans = buildWorkflowTelemetrySpans(
597
+ workflowSpans,
598
+ modelInfo,
599
+ usage,
600
+ endTimeMs
601
+ );
602
+ return {
603
+ ...basePayload,
604
+ ...typeof durationMs === "number" ? { duration_ms: durationMs } : {},
605
+ ...typeof startTimeMs === "number" ? { start_time: startTimeMs } : {},
606
+ end_time: endTimeMs,
607
+ ...typeof usage.inputTokens === "number" ? { input_tokens: usage.inputTokens } : {},
608
+ ...typeof usage.outputTokens === "number" ? { output_tokens: usage.outputTokens } : {},
609
+ ...typeof usage.totalTokens === "number" ? { total_tokens: usage.totalTokens } : {},
610
+ ...modelInfo.modelId ? { model_id: modelInfo.modelId } : {},
611
+ ...telemetryModelId ? { model: telemetryModelId } : {},
612
+ ...modelInfo.provider ? { model_provider: modelInfo.provider } : {},
613
+ ...modelInfo.provider ? { provider: modelInfo.provider } : {},
614
+ span_count: spans.length,
615
+ spans
616
+ };
617
+ }
618
+ function extractUsageMetrics(output) {
619
+ const outputRecord = output && typeof output === "object" ? output : void 0;
620
+ const usageCandidates = [
621
+ outputRecord?.usage,
622
+ outputRecord?.totalUsage,
623
+ outputRecord?.output,
624
+ outputRecord?.stepResult
625
+ ];
626
+ for (const candidate of usageCandidates) {
627
+ const usage = extractUsageRecord(candidate);
628
+ if (usage) {
629
+ return usage;
630
+ }
631
+ }
632
+ return {};
633
+ }
634
+ function extractUsageRecord(value) {
635
+ if (!value || typeof value !== "object") {
636
+ return void 0;
637
+ }
638
+ const record = value;
639
+ const usage = "usage" in record && record.usage && typeof record.usage === "object" ? record.usage : record;
640
+ const inputTokens = toNumber(usage.inputTokens);
641
+ const outputTokens = toNumber(usage.outputTokens);
642
+ const totalTokens = toNumber(usage.totalTokens);
643
+ if (inputTokens === void 0 && outputTokens === void 0 && totalTokens === void 0) {
644
+ return void 0;
645
+ }
646
+ return {
647
+ ...inputTokens !== void 0 ? { inputTokens } : {},
648
+ ...outputTokens !== void 0 ? { outputTokens } : {},
649
+ ...totalTokens !== void 0 ? { totalTokens } : {}
650
+ };
651
+ }
652
+ function toNumber(value) {
653
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
654
+ }
655
+ function serializeWorkflowOutputForGovernance(output) {
656
+ const serialized = serializeValue(output);
657
+ return compactWorkflowOutput(serialized) ?? {
658
+ summary: "Workflow output omitted by SDK compaction"
659
+ };
660
+ }
661
+ function serializeWorkflowInputForGovernance(input, goal) {
662
+ const serializedInput = serializeValue(input);
663
+ const prompt = extractLatestUserPrompt(input);
664
+ if (!goal && prompt === void 0) {
665
+ return serializedInput;
666
+ }
667
+ return {
668
+ ...goal ? { goal } : {},
669
+ ...prompt ? { prompt } : {},
670
+ input: serializedInput
671
+ };
672
+ }
673
+ function compactWorkflowOutput(output) {
674
+ if (output == null) {
675
+ return output;
676
+ }
677
+ if (typeof output === "string") {
678
+ return truncateString(output, 4e3);
679
+ }
680
+ if (typeof output !== "object") {
681
+ return output;
682
+ }
683
+ const record = output;
684
+ const usage = extractUsageMetrics(output);
685
+ const compact = {
686
+ ...typeof record.finishReason === "string" ? { finishReason: record.finishReason } : {},
687
+ ...typeof record.status === "string" ? { status: record.status } : {},
688
+ ...typeof record.text === "string" ? { text: truncateString(record.text, 4e3) } : {},
689
+ ...typeof record.modelId === "string" ? { modelId: record.modelId } : {},
690
+ ...typeof usage.inputTokens === "number" || typeof usage.outputTokens === "number" || typeof usage.totalTokens === "number" ? {
691
+ usage: {
692
+ ...typeof usage.inputTokens === "number" ? { inputTokens: usage.inputTokens } : {},
693
+ ...typeof usage.outputTokens === "number" ? { outputTokens: usage.outputTokens } : {},
694
+ ...typeof usage.totalTokens === "number" ? { totalTokens: usage.totalTokens } : {}
695
+ }
696
+ } : {}
697
+ };
698
+ const warnings = record.warnings;
699
+ if (Array.isArray(warnings) && warnings.length > 0) {
700
+ compact.warnings = warnings.slice(0, 3).map((warning) => serializeValue(warning));
701
+ }
702
+ if (Object.keys(compact).length > 0) {
703
+ return compact;
704
+ }
705
+ const fallback = JSON.stringify(record);
706
+ return truncateString(fallback, 4e3);
707
+ }
708
+ function truncateString(value, maxChars) {
709
+ if (value.length <= maxChars) {
710
+ return value;
711
+ }
712
+ return `${value.slice(0, Math.max(0, maxChars - 16))}...[truncated]`;
713
+ }
714
+ function serializeAgentSignalArgs(messages, goal) {
715
+ const latestUserPrompt = extractLatestUserPrompt(messages);
716
+ if (latestUserPrompt) {
717
+ return appendGoalToSignalArgs([latestUserPrompt], goal);
718
+ }
719
+ const serialized = serializeValue(messages);
720
+ if (serialized == null) {
721
+ return appendGoalToSignalArgs([], goal);
722
+ }
723
+ return appendGoalToSignalArgs(
724
+ Array.isArray(serialized) ? serialized : [serialized],
725
+ goal
726
+ );
727
+ }
728
+ function serializeAgentOutputSignalArgs(output, goal) {
729
+ const serialized = compactWorkflowOutput(serializeValue(output));
730
+ if (serialized === void 0 || serialized === null) {
731
+ return appendGoalToSignalArgs([], goal);
732
+ }
733
+ return appendGoalToSignalArgs(
734
+ Array.isArray(serialized) ? serialized : [serialized],
735
+ goal
736
+ );
737
+ }
738
+ function appendGoalToSignalArgs(signalArgs, goal) {
739
+ const normalizedArgs = Array.isArray(signalArgs) ? [...signalArgs] : signalArgs === void 0 || signalArgs === null ? [] : [signalArgs];
740
+ if (!goal || goal.trim().length === 0) {
741
+ return normalizedArgs;
742
+ }
743
+ const trimmedGoal = goal.trim();
744
+ if (trimmedGoal.length === 0) {
745
+ return normalizedArgs;
746
+ }
747
+ if (normalizedArgs.length === 0) {
748
+ return [{ goal: trimmedGoal }];
749
+ }
750
+ const hasGoalObject = normalizedArgs.some((item) => {
751
+ if (!item || typeof item !== "object" || Array.isArray(item)) {
752
+ return false;
753
+ }
754
+ const existingGoal = item.goal;
755
+ return typeof existingGoal === "string" && existingGoal.trim().length > 0;
756
+ });
757
+ if (hasGoalObject) {
758
+ return normalizedArgs;
759
+ }
760
+ const firstPrompt = typeof normalizedArgs[0] === "string" ? normalizedArgs[0].trim() : "";
761
+ if (firstPrompt.length > 0) {
762
+ return [...normalizedArgs, { goal: trimmedGoal, prompt: firstPrompt }];
763
+ }
764
+ return [...normalizedArgs, { goal: trimmedGoal }];
765
+ }
766
+ function extractLatestUserPrompt(messages) {
767
+ const candidates = normalizeMessageCandidates(messages);
768
+ for (let index = candidates.length - 1; index >= 0; index -= 1) {
769
+ const entry = candidates[index];
770
+ if (!entry || typeof entry !== "object") {
771
+ continue;
772
+ }
773
+ const record = entry;
774
+ const role = typeof record.role === "string" ? record.role.toLowerCase() : void 0;
775
+ if (role && role !== "user") {
776
+ continue;
777
+ }
778
+ const text = extractTextFromStructuredValue(record.content) ?? extractTextFromStructuredValue(record.parts) ?? extractTextFromStructuredValue(record.prompt) ?? extractTextFromStructuredValue(record.input);
779
+ if (text) {
780
+ return text;
781
+ }
782
+ }
783
+ return void 0;
784
+ }
785
+ function normalizeMessageCandidates(messages) {
786
+ if (Array.isArray(messages)) {
787
+ return messages;
788
+ }
789
+ if (!messages || typeof messages !== "object") {
790
+ return [];
791
+ }
792
+ const record = messages;
793
+ return Array.isArray(record.messages) ? record.messages : [];
794
+ }
795
+ function extractTextFromStructuredValue(value) {
796
+ if (typeof value === "string") {
797
+ const trimmed = value.trim();
798
+ if (trimmed.length === 0) {
799
+ return void 0;
800
+ }
801
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
802
+ try {
803
+ const parsed = JSON.parse(trimmed);
804
+ const extracted = extractTextFromStructuredValue(parsed);
805
+ if (extracted && extracted.trim().length > 0) {
806
+ return extracted.trim();
807
+ }
808
+ } catch {
809
+ }
810
+ }
811
+ return trimmed;
812
+ }
813
+ if (Array.isArray(value)) {
814
+ const parts = value.map((item) => extractTextFromStructuredValue(item)).filter((item) => typeof item === "string" && item.length > 0);
815
+ if (parts.length === 0) {
816
+ return void 0;
817
+ }
818
+ const combined = parts.join("\n").trim();
819
+ return combined.length > 0 ? combined : void 0;
820
+ }
821
+ if (!value || typeof value !== "object") {
822
+ return void 0;
823
+ }
824
+ const record = value;
825
+ const text = extractTextFromStructuredValue(record.text) ?? extractTextFromStructuredValue(record.content) ?? extractTextFromStructuredValue(record.parts) ?? extractTextFromStructuredValue(record.prompt) ?? extractTextFromStructuredValue(record.input) ?? extractTextFromStructuredValue(record.messages);
826
+ if (!text) {
827
+ return void 0;
828
+ }
829
+ return text.trim().length > 0 ? text.trim() : void 0;
830
+ }
831
+ function extractModelInfo(output, fallback = {}) {
832
+ if (!output || typeof output !== "object") {
833
+ return {
834
+ ...fallback.modelId ? { modelId: fallback.modelId } : {},
835
+ ...fallback.provider ? { provider: fallback.provider } : {}
836
+ };
837
+ }
838
+ const record = output;
839
+ const response = record.response && typeof record.response === "object" ? record.response : void 0;
840
+ const modelMetadata = response?.modelMetadata && typeof response.modelMetadata === "object" ? response.modelMetadata : void 0;
841
+ const parsedModelInfo = resolveModelInfoFromCandidates([
842
+ response?.modelId,
843
+ modelMetadata?.modelId,
844
+ response?.model,
845
+ record.modelId,
846
+ record.model
847
+ ]);
848
+ const providerCandidates = [
849
+ modelMetadata?.provider,
850
+ response?.provider,
851
+ record.provider,
852
+ parsedModelInfo.provider,
853
+ extractProviderHint(record)
854
+ ];
855
+ const modelId = parsedModelInfo.modelId;
856
+ let provider;
857
+ for (const candidate of providerCandidates) {
858
+ if (typeof candidate === "string" && candidate.trim().length > 0) {
859
+ provider = normalizeProvider(candidate);
860
+ break;
861
+ }
862
+ }
863
+ return {
864
+ ...modelId ? { modelId } : {},
865
+ ...!modelId && fallback.modelId ? { modelId: fallback.modelId } : {},
866
+ ...provider ? { provider } : {},
867
+ ...!provider && fallback.provider ? { provider: fallback.provider } : {}
868
+ };
869
+ }
870
+ function extractAgentModelInfo(agentRecord) {
871
+ const directModelInfo = resolveModelInfoFromCandidates([agentRecord.model]);
872
+ const model = agentRecord.model && typeof agentRecord.model === "object" ? agentRecord.model : void 0;
873
+ const config = model?.config && typeof model.config === "object" ? model.config : void 0;
874
+ const nestedModelInfo = resolveModelInfoFromCandidates([
875
+ model?.modelId,
876
+ config?.modelId,
877
+ model?.id,
878
+ model?.name,
879
+ model?.model
880
+ ]);
881
+ const providerCandidates = [
882
+ nestedModelInfo.provider,
883
+ config?.provider,
884
+ model?.provider,
885
+ directModelInfo.provider
886
+ ];
887
+ const modelId = directModelInfo.modelId ?? nestedModelInfo.modelId;
888
+ let provider;
889
+ for (const candidate of providerCandidates) {
890
+ if (typeof candidate === "string" && candidate.trim().length > 0) {
891
+ provider = normalizeProvider(candidate);
892
+ break;
893
+ }
894
+ }
895
+ return {
896
+ ...modelId ? { modelId } : {},
897
+ ...provider ? { provider } : {}
898
+ };
899
+ }
900
+ function resolveInvocationModelInfo(agentRecord, executionOptions) {
901
+ const agentModelInfo = extractAgentModelInfo(agentRecord);
902
+ const optionsModelInfo = extractModelInfo(executionOptions, {});
903
+ return {
904
+ ...optionsModelInfo.modelId ? { modelId: optionsModelInfo.modelId } : agentModelInfo.modelId ? { modelId: agentModelInfo.modelId } : {},
905
+ ...optionsModelInfo.provider ? { provider: optionsModelInfo.provider } : agentModelInfo.provider ? { provider: agentModelInfo.provider } : {}
906
+ };
907
+ }
908
+ function applyDefaultModelInfo(output, fallback) {
909
+ if (!output || typeof output !== "object") {
910
+ return output;
911
+ }
912
+ const record = output;
913
+ const hasModelId = typeof record.modelId === "string" && record.modelId.trim().length > 0;
914
+ const hasProvider = typeof record.provider === "string" && record.provider.trim().length > 0;
915
+ if ((hasModelId || !fallback.modelId) && (hasProvider || !fallback.provider)) {
916
+ return output;
917
+ }
918
+ return {
919
+ ...record,
920
+ ...!hasModelId && fallback.modelId ? { modelId: fallback.modelId } : {},
921
+ ...!hasProvider && fallback.provider ? { provider: fallback.provider } : {}
922
+ };
923
+ }
924
+ function extractProviderHint(outputRecord) {
925
+ const parsedModelInfo = resolveModelInfoFromCandidates([
926
+ outputRecord.modelId,
927
+ outputRecord.model
928
+ ]);
929
+ if (parsedModelInfo.provider) {
930
+ return parsedModelInfo.provider;
931
+ }
932
+ const directProvider = inferProviderFromMetadata(outputRecord.providerMetadata);
933
+ if (directProvider) {
934
+ return directProvider;
935
+ }
936
+ const toolCallsProvider = inferProviderFromToolCalls(outputRecord.toolCalls);
937
+ if (toolCallsProvider) {
938
+ return toolCallsProvider;
939
+ }
940
+ const steps = Array.isArray(outputRecord.steps) ? outputRecord.steps : void 0;
941
+ if (!steps) {
942
+ return void 0;
943
+ }
944
+ for (const step of steps) {
945
+ if (!step || typeof step !== "object") {
946
+ continue;
947
+ }
948
+ const stepRecord = step;
949
+ const stepProvider = inferProviderFromMetadata(stepRecord.providerMetadata);
950
+ if (stepProvider) {
951
+ return stepProvider;
952
+ }
953
+ const stepToolProvider = inferProviderFromToolCalls(stepRecord.toolCalls);
954
+ if (stepToolProvider) {
955
+ return stepToolProvider;
956
+ }
957
+ }
958
+ return void 0;
959
+ }
960
+ function inferProviderFromToolCalls(toolCalls) {
961
+ if (!Array.isArray(toolCalls)) {
962
+ return void 0;
963
+ }
964
+ for (const entry of toolCalls) {
965
+ if (!entry || typeof entry !== "object") {
966
+ continue;
967
+ }
968
+ const entryRecord = entry;
969
+ const directProvider = inferProviderFromMetadata(entryRecord.providerMetadata);
970
+ if (directProvider) {
971
+ return directProvider;
972
+ }
973
+ const payload = entryRecord.payload && typeof entryRecord.payload === "object" ? entryRecord.payload : void 0;
974
+ const payloadProvider = inferProviderFromMetadata(payload?.providerMetadata);
975
+ if (payloadProvider) {
976
+ return payloadProvider;
977
+ }
978
+ }
979
+ return void 0;
980
+ }
981
+ function inferProviderFromMetadata(metadata) {
982
+ if (!metadata || typeof metadata !== "object") {
983
+ return void 0;
984
+ }
985
+ const keys = Object.keys(metadata).map(
986
+ (key) => key.toLowerCase()
987
+ );
988
+ if (keys.includes("openai")) {
989
+ return "openai";
990
+ }
991
+ if (keys.includes("anthropic")) {
992
+ return "anthropic";
993
+ }
994
+ if (keys.includes("google") || keys.includes("gemini")) {
995
+ return "google";
996
+ }
997
+ return void 0;
998
+ }
999
+ function resolveModelInfoFromCandidates(candidates) {
1000
+ let modelId;
1001
+ let provider;
1002
+ for (const candidate of candidates) {
1003
+ if (typeof candidate !== "string" || candidate.trim().length === 0) {
1004
+ continue;
1005
+ }
1006
+ const parsed = parseModelIdentifier(candidate);
1007
+ if (!modelId && parsed.modelId) {
1008
+ modelId = parsed.modelId;
1009
+ }
1010
+ if (!provider && parsed.provider) {
1011
+ provider = parsed.provider;
1012
+ }
1013
+ if (modelId && provider) {
1014
+ break;
1015
+ }
1016
+ }
1017
+ return {
1018
+ ...modelId ? { modelId } : {},
1019
+ ...provider ? { provider } : {}
1020
+ };
1021
+ }
1022
+ function parseModelIdentifier(candidate) {
1023
+ const trimmed = candidate.trim();
1024
+ if (!trimmed) {
1025
+ return {};
1026
+ }
1027
+ const slashParts = trimmed.split("/");
1028
+ if (slashParts.length >= 2) {
1029
+ const possibleProvider = slashParts[0]?.trim();
1030
+ const modelPart = slashParts.slice(1).join("/").trim();
1031
+ if (possibleProvider && modelPart && isProviderToken(possibleProvider)) {
1032
+ return {
1033
+ modelId: modelPart,
1034
+ provider: normalizeProvider(possibleProvider)
1035
+ };
1036
+ }
1037
+ }
1038
+ return {
1039
+ modelId: trimmed
1040
+ };
1041
+ }
1042
+ function isProviderToken(candidate) {
1043
+ const normalized = candidate.trim().toLowerCase();
1044
+ return normalized.includes("openai") || normalized.includes("anthropic") || normalized.includes("google") || normalized.includes("gemini");
1045
+ }
1046
+ function normalizeProvider(candidate) {
1047
+ const normalized = candidate.trim().toLowerCase();
1048
+ if (normalized.includes("openai")) {
1049
+ return "openai";
1050
+ }
1051
+ if (normalized.includes("anthropic")) {
1052
+ return "anthropic";
1053
+ }
1054
+ if (normalized.includes("google") || normalized.includes("gemini")) {
1055
+ return "google";
1056
+ }
1057
+ return candidate.trim();
1058
+ }
1059
+ function toTelemetryModelId(modelId) {
1060
+ if (typeof modelId !== "string") {
1061
+ return void 0;
1062
+ }
1063
+ const trimmed = modelId.trim();
1064
+ if (trimmed.length === 0) {
1065
+ return void 0;
1066
+ }
1067
+ const sanitized = trimmed.replace(/[.:/\\\s]+/g, "-").replace(/[^A-Za-z0-9_-]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
1068
+ return sanitized.length > 0 ? sanitized : trimmed;
1069
+ }
1070
+ function buildWorkflowTelemetrySpans(spans, modelInfo, usage, endTimeMs) {
1071
+ const inputTokens = usage.inputTokens ?? 0;
1072
+ const outputTokens = usage.outputTokens ?? 0;
1073
+ if (inputTokens <= 0 && outputTokens <= 0) {
1074
+ return spans;
1075
+ }
1076
+ if (hasParseableModelUsageSpan(spans)) {
1077
+ return spans;
1078
+ }
1079
+ const providerUrl = resolveProviderUrl(modelInfo, spans);
1080
+ if (!providerUrl) {
1081
+ return spans;
1082
+ }
1083
+ const modelId = resolveSyntheticModelId(modelInfo, spans);
1084
+ const traceId = getTraceIdCandidate(spans);
1085
+ return [
1086
+ ...spans,
1087
+ createSyntheticModelUsageSpan({
1088
+ endTimeMs,
1089
+ inputTokens,
1090
+ modelId,
1091
+ outputTokens,
1092
+ providerUrl,
1093
+ ...modelInfo.provider ? { provider: modelInfo.provider } : {},
1094
+ ...traceId ? { traceId } : {}
1095
+ })
1096
+ ];
1097
+ }
1098
+ function hasParseableModelUsageSpan(spans) {
1099
+ return spans.some((span) => {
1100
+ const attributes = span.attributes && typeof span.attributes === "object" ? span.attributes : {};
1101
+ const rawUrl = attributes["http.url"] ?? attributes["url.full"];
1102
+ const url = typeof rawUrl === "string" ? rawUrl : void 0;
1103
+ if (!url || !isLlmProviderUrl(url)) {
1104
+ return false;
1105
+ }
1106
+ const responseBody = getStringField(span, "response_body", "responseBody");
1107
+ if (!responseBody) {
1108
+ return false;
1109
+ }
1110
+ if (!hasUsageInBody(responseBody)) {
1111
+ return false;
1112
+ }
1113
+ const modelFromResponse = extractModelIdFromBody(responseBody);
1114
+ if (modelFromResponse) {
1115
+ return true;
1116
+ }
1117
+ const requestBody = getStringField(span, "request_body", "requestBody");
1118
+ if (!requestBody) {
1119
+ return false;
1120
+ }
1121
+ return extractModelIdFromBody(requestBody) !== void 0;
1122
+ });
1123
+ }
1124
+ function hasUsageInBody(body) {
1125
+ try {
1126
+ const parsed = JSON.parse(body);
1127
+ const usage = parsed.usage;
1128
+ return typeof usage?.prompt_tokens === "number" || typeof usage?.completion_tokens === "number" || typeof usage?.input_tokens === "number" || typeof usage?.output_tokens === "number";
1129
+ } catch {
1130
+ return false;
1131
+ }
1132
+ }
1133
+ function extractModelIdFromBody(body) {
1134
+ try {
1135
+ const parsed = JSON.parse(body);
1136
+ const model = typeof parsed.model === "string" ? parsed.model.trim() : void 0;
1137
+ return model && model.length > 0 ? model : void 0;
1138
+ } catch {
1139
+ return void 0;
1140
+ }
1141
+ }
1142
+ function createSyntheticModelUsageSpan({
1143
+ endTimeMs,
1144
+ inputTokens,
1145
+ modelId,
1146
+ outputTokens,
1147
+ provider,
1148
+ providerUrl,
1149
+ traceId
1150
+ }) {
1151
+ const endTimeNs = Math.max(1, Math.floor(endTimeMs * 1e6));
1152
+ const startTimeNs = Math.max(0, endTimeNs - 1);
1153
+ const normalizedTraceId = normalizeHexId(traceId, 32);
1154
+ const spanId = normalizeHexId(void 0, 16);
1155
+ const telemetryModelId = toTelemetryModelId(modelId) ?? modelId;
1156
+ return {
1157
+ attributes: {
1158
+ "http.method": "POST",
1159
+ "http.url": providerUrl,
1160
+ "openbox.synthetic": true
1161
+ },
1162
+ duration_ns: 1,
1163
+ end_time: endTimeNs,
1164
+ events: [],
1165
+ kind: "CLIENT",
1166
+ name: "openbox.synthetic.model_usage",
1167
+ request_body: JSON.stringify({
1168
+ model: telemetryModelId,
1169
+ model_id: modelId,
1170
+ ...provider ? { model_provider: provider } : {},
1171
+ ...provider ? { provider } : {}
1172
+ }),
1173
+ response_body: JSON.stringify({
1174
+ model: telemetryModelId,
1175
+ model_id: modelId,
1176
+ ...provider ? { model_provider: provider } : {},
1177
+ ...provider ? { provider } : {},
1178
+ usage: {
1179
+ completion_tokens: outputTokens,
1180
+ input_tokens: inputTokens,
1181
+ output_tokens: outputTokens,
1182
+ prompt_tokens: inputTokens,
1183
+ total_tokens: inputTokens + outputTokens
1184
+ }
1185
+ }),
1186
+ semantic_type: "llm_completion",
1187
+ span_id: spanId,
1188
+ start_time: startTimeNs,
1189
+ status: {
1190
+ code: "OK"
1191
+ },
1192
+ trace_id: normalizedTraceId
1193
+ };
1194
+ }
1195
+ function resolveProviderUrl(modelInfo, spans) {
1196
+ const provider = modelInfo.provider?.toLowerCase();
1197
+ const modelId = modelInfo.modelId?.toLowerCase();
1198
+ if (provider?.includes("openai")) {
1199
+ return "https://api.openai.com/v1/responses";
1200
+ }
1201
+ if (provider?.includes("anthropic")) {
1202
+ return "https://api.anthropic.com/v1/messages";
1203
+ }
1204
+ if (provider?.includes("google") || provider?.includes("gemini")) {
1205
+ return "https://generativelanguage.googleapis.com/v1beta/models";
1206
+ }
1207
+ for (const span of spans) {
1208
+ const attributes = span.attributes && typeof span.attributes === "object" ? span.attributes : {};
1209
+ const rawUrl = attributes["http.url"] ?? attributes["url.full"];
1210
+ const url = typeof rawUrl === "string" ? rawUrl : void 0;
1211
+ if (!url) {
1212
+ continue;
1213
+ }
1214
+ if (url.includes("api.openai.com")) {
1215
+ return "https://api.openai.com/v1/responses";
1216
+ }
1217
+ if (url.includes("api.anthropic.com")) {
1218
+ return "https://api.anthropic.com/v1/messages";
1219
+ }
1220
+ if (url.includes("generativelanguage.googleapis.com")) {
1221
+ return "https://generativelanguage.googleapis.com/v1beta/models";
1222
+ }
1223
+ }
1224
+ if (!modelId) {
1225
+ return void 0;
1226
+ }
1227
+ if (modelId.startsWith("gpt-") || modelId.startsWith("o1") || modelId.startsWith("o3")) {
1228
+ return "https://api.openai.com/v1/responses";
1229
+ }
1230
+ if (modelId.startsWith("claude-")) {
1231
+ return "https://api.anthropic.com/v1/messages";
1232
+ }
1233
+ if (modelId.startsWith("gemini")) {
1234
+ return "https://generativelanguage.googleapis.com/v1beta/models";
1235
+ }
1236
+ return void 0;
1237
+ }
1238
+ function resolveSyntheticModelId(modelInfo, spans) {
1239
+ for (const span of spans) {
1240
+ const responseBody = getStringField(span, "response_body", "responseBody");
1241
+ if (responseBody) {
1242
+ const modelFromResponse = extractModelIdFromBody(responseBody);
1243
+ if (modelFromResponse) {
1244
+ return modelFromResponse;
1245
+ }
1246
+ }
1247
+ const requestBody = getStringField(span, "request_body", "requestBody");
1248
+ if (!requestBody) {
1249
+ continue;
1250
+ }
1251
+ const modelFromRequest = extractModelIdFromBody(requestBody);
1252
+ if (modelFromRequest) {
1253
+ return modelFromRequest;
1254
+ }
1255
+ }
1256
+ if (modelInfo.modelId) {
1257
+ return modelInfo.modelId;
1258
+ }
1259
+ return "unknown-model";
1260
+ }
1261
+ function getTraceIdCandidate(spans) {
1262
+ for (const span of spans) {
1263
+ const traceId = getStringField(span, "trace_id", "traceId");
1264
+ if (traceId) {
1265
+ return traceId;
1266
+ }
1267
+ }
1268
+ return void 0;
1269
+ }
1270
+ function getStringField(record, snakeKey, camelKey) {
1271
+ const snake = record[snakeKey];
1272
+ if (typeof snake === "string") {
1273
+ return snake;
1274
+ }
1275
+ const camel = record[camelKey];
1276
+ if (typeof camel === "string") {
1277
+ return camel;
1278
+ }
1279
+ return void 0;
1280
+ }
1281
+ function isLlmProviderUrl(url) {
1282
+ return url.includes("api.openai.com") || url.includes("api.anthropic.com") || url.includes("generativelanguage.googleapis.com");
1283
+ }
1284
+ function resolveWorkflowModelInfo(output, fallbackModelInfo, spans) {
1285
+ const outputModelInfo = extractModelInfo(output, {});
1286
+ const spanModelInfo = extractModelInfoFromSpans(spans);
1287
+ return {
1288
+ ...outputModelInfo.modelId ? { modelId: outputModelInfo.modelId } : spanModelInfo.modelId ? { modelId: spanModelInfo.modelId } : fallbackModelInfo.modelId ? { modelId: fallbackModelInfo.modelId } : {},
1289
+ ...outputModelInfo.provider ? { provider: outputModelInfo.provider } : spanModelInfo.provider ? { provider: spanModelInfo.provider } : fallbackModelInfo.provider ? { provider: fallbackModelInfo.provider } : {}
1290
+ };
1291
+ }
1292
+ function extractModelInfoFromSpans(spans) {
1293
+ let modelId;
1294
+ let provider;
1295
+ for (const span of spans) {
1296
+ const attributes = span.attributes && typeof span.attributes === "object" ? span.attributes : {};
1297
+ const rawUrl = attributes["http.url"] ?? attributes["url.full"];
1298
+ const url = typeof rawUrl === "string" ? rawUrl : void 0;
1299
+ if (url && !provider) {
1300
+ provider = inferProviderFromUrl(url);
1301
+ }
1302
+ const responseBody = getStringField(span, "response_body", "responseBody");
1303
+ if (!modelId && responseBody) {
1304
+ modelId = extractModelIdFromBody(responseBody);
1305
+ }
1306
+ const requestBody = getStringField(span, "request_body", "requestBody");
1307
+ if (!modelId && requestBody) {
1308
+ modelId = extractModelIdFromBody(requestBody);
1309
+ }
1310
+ if (modelId && provider) {
1311
+ break;
1312
+ }
1313
+ }
1314
+ return {
1315
+ ...modelId ? { modelId } : {},
1316
+ ...provider ? { provider } : {}
1317
+ };
1318
+ }
1319
+ function inferProviderFromUrl(url) {
1320
+ const normalized = url.toLowerCase();
1321
+ if (normalized.includes("api.openai.com")) {
1322
+ return "openai";
1323
+ }
1324
+ if (normalized.includes("api.anthropic.com")) {
1325
+ return "anthropic";
1326
+ }
1327
+ if (normalized.includes("generativelanguage.googleapis.com")) {
1328
+ return "google";
1329
+ }
1330
+ return void 0;
1331
+ }
1332
+ function normalizeHexId(candidate, width) {
1333
+ const source = (candidate ?? randomUUID().replaceAll("-", "")).toLowerCase();
1334
+ const filtered = source.replace(/[^a-f0-9]/g, "");
1335
+ if (filtered.length >= width) {
1336
+ return filtered.slice(0, width);
1337
+ }
1338
+ return filtered.padEnd(width, "0");
1339
+ }
1340
+ async function sendAgentFailure(options, runId, workflowId, workflowType, error, streamMeta, agentGoal) {
1341
+ if (options.config.skipWorkflowTypes.has(workflowType)) {
1342
+ clearAgentRunState(runId);
1343
+ return;
1344
+ }
1345
+ void streamMeta;
1346
+ try {
1347
+ await emitAgentOutputSignal(
1348
+ options,
1349
+ runId,
1350
+ workflowId,
1351
+ workflowType,
1352
+ {
1353
+ error: serializeError(error),
1354
+ status: "failed"
1355
+ },
1356
+ agentGoal
1357
+ );
1358
+ await evaluateAgentEvent(options, {
1359
+ error: serializeError(error),
1360
+ event_type: WorkflowEventType.WORKFLOW_FAILED,
1361
+ ...agentGoal ? { goal: agentGoal } : {},
1362
+ run_id: runId,
1363
+ workflow_id: workflowId,
1364
+ workflow_type: workflowType
1365
+ });
1366
+ } finally {
1367
+ clearAgentRunState(runId);
1368
+ }
1369
+ }
1370
+ async function emitAgentOutputSignal(options, runId, workflowId, workflowType, output, goal) {
1371
+ if (options.config.skipSignals.has(AGENT_OUTPUT_SIGNAL_NAME)) {
1372
+ return;
1373
+ }
1374
+ const signalArgs = serializeAgentOutputSignalArgs(output, goal);
1375
+ const outputSignalBasePayload = {
1376
+ event_type: WorkflowEventType.SIGNAL_RECEIVED,
1377
+ ...goal ? { goal } : {},
1378
+ run_id: runId,
1379
+ signal_args: signalArgs,
1380
+ signal_name: AGENT_OUTPUT_SIGNAL_NAME,
1381
+ task_queue: "mastra",
1382
+ workflow_id: workflowId,
1383
+ workflow_type: workflowType
1384
+ };
1385
+ const outputSignalSpans = buildAgentOutputSignalSpans(
1386
+ options,
1387
+ workflowId,
1388
+ runId
1389
+ );
1390
+ const outputSignalPayload = outputSignalSpans.length > 0 ? {
1391
+ ...outputSignalBasePayload,
1392
+ span_count: outputSignalSpans.length,
1393
+ spans: outputSignalSpans
1394
+ } : outputSignalBasePayload;
1395
+ await evaluateAgentEvent(
1396
+ options,
1397
+ outputSignalPayload,
1398
+ outputSignalBasePayload
1399
+ );
1400
+ }
1401
+ async function evaluateAgentEvent(options, payload, fallbackPayload, minimalPayload) {
1402
+ const candidates = buildCandidatePayloads(
1403
+ payload,
1404
+ fallbackPayload,
1405
+ minimalPayload
1406
+ ).filter((candidate, index, all) => {
1407
+ const isLast = index === all.length - 1;
1408
+ return !isPayloadOverBudget(
1409
+ candidate.payload,
1410
+ options.config.maxEvaluatePayloadBytes,
1411
+ isLast
1412
+ );
1413
+ });
1414
+ let resolvedError = null;
1415
+ for (let index = 0; index < candidates.length; index += 1) {
1416
+ const candidate = candidates[index];
1417
+ if (!candidate) {
1418
+ continue;
1419
+ }
1420
+ try {
1421
+ const result = await options.client.evaluate({
1422
+ source: "workflow-telemetry",
1423
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1424
+ ...candidate.payload
1425
+ });
1426
+ if (result !== null) {
1427
+ return result;
1428
+ }
1429
+ continue;
1430
+ } catch (error) {
1431
+ resolvedError = error;
1432
+ const hasNext = index < candidates.length - 1;
1433
+ if (hasNext && isRecoverableGovernanceError(error)) {
1434
+ continue;
1435
+ }
1436
+ break;
1437
+ }
1438
+ }
1439
+ if (options.config.onApiError === "fail_closed") {
1440
+ return {
1441
+ action: "stop",
1442
+ alignmentScore: void 0,
1443
+ approvalId: void 0,
1444
+ behavioralViolations: void 0,
1445
+ constraints: void 0,
1446
+ governanceEventId: void 0,
1447
+ guardrailsResult: void 0,
1448
+ metadata: void 0,
1449
+ policyId: void 0,
1450
+ reason: `Governance API error: ${resolvedError instanceof Error ? resolvedError.message : String(resolvedError)}`,
1451
+ riskScore: 0,
1452
+ trustTier: void 0,
1453
+ verdict: Verdict.HALT
1454
+ };
1455
+ }
1456
+ return null;
1457
+ }
1458
+ function isBadRequestSchemaError(error) {
1459
+ return error instanceof GovernanceAPIError && /HTTP 400/i.test(error.message);
1460
+ }
1461
+ function isPayloadTooLargeError(error) {
1462
+ return error instanceof GovernanceAPIError && /(blob data size exceeds limit|payload too large|request entity too large|message too large)/i.test(
1463
+ error.message
1464
+ );
1465
+ }
1466
+ function isTransientGovernanceError(error) {
1467
+ if (!(error instanceof GovernanceAPIError)) {
1468
+ return false;
1469
+ }
1470
+ return /HTTP\s(429|5\d\d)\b/i.test(error.message) || /(context deadline exceeded|temporarily unavailable|timeout|timed out|connection reset|econnreset|etimedout|upstream connect error)/i.test(
1471
+ error.message
1472
+ );
1473
+ }
1474
+ function isRecoverableGovernanceError(error) {
1475
+ return isBadRequestSchemaError(error) || isPayloadTooLargeError(error) || isTransientGovernanceError(error);
1476
+ }
1477
+ function buildCandidatePayloads(payload, fallbackPayload, minimalPayload) {
1478
+ const candidates = [
1479
+ payload,
1480
+ fallbackPayload,
1481
+ minimalPayload
1482
+ ].filter(
1483
+ (value) => value !== void 0
1484
+ );
1485
+ const deduped = [];
1486
+ const seen = /* @__PURE__ */ new Set();
1487
+ for (const candidate of candidates) {
1488
+ const key = safeStringify(candidate);
1489
+ if (!seen.has(key)) {
1490
+ deduped.push({
1491
+ payload: candidate
1492
+ });
1493
+ seen.add(key);
1494
+ }
1495
+ }
1496
+ return deduped;
1497
+ }
1498
+ function isPayloadOverBudget(payload, maxBytes, isLastFallback) {
1499
+ const serialized = safeStringify(payload);
1500
+ const sizeBytes = Buffer.byteLength(serialized, "utf8");
1501
+ if (sizeBytes <= maxBytes || isLastFallback) {
1502
+ return false;
1503
+ }
1504
+ return true;
1505
+ }
1506
+ function safeStringify(payload) {
1507
+ try {
1508
+ return JSON.stringify(payload);
1509
+ } catch {
1510
+ return "{}";
1511
+ }
1512
+ }
1513
+ function serializeError(error) {
1514
+ if (error instanceof Error) {
1515
+ return {
1516
+ message: error.message,
1517
+ type: error.name
1518
+ };
1519
+ }
1520
+ return {
1521
+ message: String(error),
1522
+ type: typeof error
1523
+ };
1524
+ }
1525
+ function clearAgentRunState(runId) {
1526
+ OPENBOX_AGENT_RUN_GOALS.delete(runId);
1527
+ OPENBOX_AGENT_SIGNAL_SPAN_CURSOR.delete(runId);
1528
+ }
1529
+ function buildAgentOutputSignalSpans(options, workflowId, runId) {
1530
+ const queuedHookSpans = options.spanProcessor.consumeAgentSignalHookSpans(
1531
+ workflowId,
1532
+ runId
1533
+ );
1534
+ if (queuedHookSpans.length > 0) {
1535
+ return queuedHookSpans.slice(-MAX_AGENT_OUTPUT_SIGNAL_SPANS).map((span) => compactAgentSignalSpan(span));
1536
+ }
1537
+ const workflowSpans = normalizeSpansForGovernance(
1538
+ options.spanProcessor.getBuffer(workflowId, runId)?.spans ?? []
1539
+ );
1540
+ const llmSpans = workflowSpans.filter((span) => isCompletedLlmAlignmentSpan(span));
1541
+ if (llmSpans.length === 0) {
1542
+ return [];
1543
+ }
1544
+ const cursor = OPENBOX_AGENT_SIGNAL_SPAN_CURSOR.get(runId) ?? 0;
1545
+ const normalizedCursor = cursor >= 0 && cursor <= llmSpans.length ? cursor : 0;
1546
+ const unsentSpans = llmSpans.slice(normalizedCursor);
1547
+ OPENBOX_AGENT_SIGNAL_SPAN_CURSOR.set(runId, llmSpans.length);
1548
+ if (unsentSpans.length === 0) {
1549
+ return [];
1550
+ }
1551
+ const maxSourceSpanCount = Math.max(
1552
+ 1,
1553
+ Math.floor(MAX_AGENT_OUTPUT_SIGNAL_SPANS / 2)
1554
+ );
1555
+ return unsentSpans.slice(-maxSourceSpanCount).flatMap((span) => buildAgentOutputSignalSpanPhases(span)).map((span) => compactAgentSignalSpan(span));
1556
+ }
1557
+ function isCompletedLlmAlignmentSpan(span) {
1558
+ const stage = getStringField(span, "stage", "stage");
1559
+ if (stage && stage !== "completed") {
1560
+ return false;
1561
+ }
1562
+ const hasCompletedTiming = typeof span.end_time === "number" || typeof span.duration_ns === "number";
1563
+ if (!stage && !hasCompletedTiming) {
1564
+ return false;
1565
+ }
1566
+ const semanticType = getStringField(span, "semantic_type", "semanticType");
1567
+ if (semanticType && semanticType.startsWith("llm_")) {
1568
+ return true;
1569
+ }
1570
+ const attributes = span.attributes && typeof span.attributes === "object" ? span.attributes : {};
1571
+ const httpMethod = typeof attributes["http.method"] === "string" ? attributes["http.method"].trim().toUpperCase() : void 0;
1572
+ const rawUrl = attributes["http.url"] ?? attributes["url.full"];
1573
+ const httpUrl = typeof rawUrl === "string" ? rawUrl.toLowerCase() : "";
1574
+ if (httpMethod === "POST" && (httpUrl.includes("api.openai.com") || httpUrl.includes("api.anthropic.com") || httpUrl.includes("generativelanguage.googleapis.com"))) {
1575
+ return true;
1576
+ }
1577
+ const requestBody = getStringField(span, "request_body", "requestBody");
1578
+ const responseBody = getStringField(span, "response_body", "responseBody");
1579
+ return httpMethod === "POST" && looksLikeLlmPayload(requestBody, responseBody);
1580
+ }
1581
+ function looksLikeLlmPayload(requestBody, responseBody) {
1582
+ return typeof requestBody === "string" && extractModelIdFromBody(requestBody) !== void 0 || typeof responseBody === "string" && (extractModelIdFromBody(responseBody) !== void 0 || hasUsageInBody(responseBody));
1583
+ }
1584
+ function compactAgentSignalSpan(span) {
1585
+ const compacted = {
1586
+ ...span
1587
+ };
1588
+ if (typeof compacted.request_body === "string") {
1589
+ compacted.request_body = truncateString(
1590
+ compacted.request_body,
1591
+ MAX_AGENT_SIGNAL_SPAN_BODY_CHARS
1592
+ );
1593
+ }
1594
+ if (typeof compacted.response_body === "string") {
1595
+ compacted.response_body = truncateString(
1596
+ compacted.response_body,
1597
+ MAX_AGENT_SIGNAL_SPAN_BODY_CHARS
1598
+ );
1599
+ }
1600
+ return compacted;
1601
+ }
1602
+ function buildAgentOutputSignalSpanPhases(span) {
1603
+ const completedSpan = normalizeAgentOutputSignalSpan(span, "completed");
1604
+ const startedSpan = normalizeAgentOutputSignalSpan(span, "started");
1605
+ return [startedSpan, completedSpan];
1606
+ }
1607
+ function normalizeAgentOutputSignalSpan(span, stage) {
1608
+ const normalized = {
1609
+ ...span,
1610
+ stage,
1611
+ ...typeof span.semantic_type !== "string" && typeof span.semanticType !== "string" ? { semantic_type: "llm_completion" } : {}
1612
+ };
1613
+ if (stage === "started") {
1614
+ delete normalized.duration_ns;
1615
+ delete normalized.durationNs;
1616
+ delete normalized.end_time;
1617
+ delete normalized.endTime;
1618
+ delete normalized.response_body;
1619
+ delete normalized.responseBody;
1620
+ delete normalized.response_headers;
1621
+ delete normalized.responseHeaders;
1622
+ delete normalized.status;
1623
+ }
1624
+ return normalized;
1625
+ }
1626
+ function ensureAgentSpanBuffer(options, runId, workflowId, workflowType) {
1627
+ const existing = options.spanProcessor.getBuffer(workflowId, runId);
1628
+ if (!existing || existing.runId !== runId) {
1629
+ options.spanProcessor.registerWorkflow(
1630
+ workflowId,
1631
+ new WorkflowSpanBuffer({
1632
+ runId,
1633
+ taskQueue: "mastra",
1634
+ workflowId,
1635
+ workflowType
1636
+ })
1637
+ );
1638
+ }
1639
+ }
1640
+ function getAgentStreamMeta(stream) {
1641
+ if (!stream || typeof stream !== "object") {
1642
+ return void 0;
1643
+ }
1644
+ return stream[OPENBOX_AGENT_STREAM_META];
1645
+ }
1646
+ function setAgentStreamMeta(stream, meta) {
1647
+ Object.defineProperty(stream, OPENBOX_AGENT_STREAM_META, {
1648
+ configurable: true,
1649
+ enumerable: false,
1650
+ value: meta
1651
+ });
1652
+ }
1653
+ function attachStreamLifecycleHandlers(stream, handlers) {
1654
+ const streamLike = stream;
1655
+ const originalGetFullOutput = typeof streamLike.getFullOutput === "function" ? streamLike.getFullOutput.bind(streamLike) : void 0;
1656
+ const originalConsumeStream = typeof streamLike.consumeStream === "function" ? streamLike.consumeStream.bind(streamLike) : void 0;
1657
+ if (!originalGetFullOutput && !originalConsumeStream && !isReadableStream(streamLike.fullStream)) {
1658
+ return;
1659
+ }
1660
+ let settled = false;
1661
+ let settledPromise;
1662
+ const settleSuccess = (fullOutput) => {
1663
+ if (settledPromise) {
1664
+ return settledPromise;
1665
+ }
1666
+ settled = true;
1667
+ settledPromise = handlers.onSuccess(fullOutput);
1668
+ return settledPromise;
1669
+ };
1670
+ const settleFailure = (error) => {
1671
+ if (settledPromise) {
1672
+ return settledPromise;
1673
+ }
1674
+ settled = true;
1675
+ settledPromise = handlers.onFailure(error);
1676
+ return settledPromise;
1677
+ };
1678
+ if (originalGetFullOutput) {
1679
+ streamLike.getFullOutput = async (...args) => {
1680
+ try {
1681
+ const fullOutput = await originalGetFullOutput(...args);
1682
+ await settleSuccess(fullOutput);
1683
+ return fullOutput;
1684
+ } catch (error) {
1685
+ await settleFailure(error);
1686
+ throw error;
1687
+ }
1688
+ };
1689
+ }
1690
+ if (originalConsumeStream) {
1691
+ streamLike.consumeStream = async (...args) => {
1692
+ try {
1693
+ const consumed = await originalConsumeStream(...args);
1694
+ if (!settled) {
1695
+ const snapshot = buildStreamSnapshot(streamLike);
1696
+ await settleSuccess(snapshot).catch(() => {
1697
+ });
1698
+ }
1699
+ return consumed;
1700
+ } catch (error) {
1701
+ await settleFailure(error);
1702
+ throw error;
1703
+ }
1704
+ };
1705
+ }
1706
+ if (isReadableStream(streamLike.fullStream)) {
1707
+ const observedStream = streamLike.fullStream.pipeThrough(
1708
+ new TransformStream({
1709
+ flush() {
1710
+ if (settled) {
1711
+ return;
1712
+ }
1713
+ const snapshot = buildStreamSnapshot(streamLike);
1714
+ return settleSuccess(snapshot).catch(() => {
1715
+ });
1716
+ }
1717
+ })
1718
+ );
1719
+ Object.defineProperty(streamLike, "fullStream", {
1720
+ configurable: true,
1721
+ enumerable: false,
1722
+ value: observedStream,
1723
+ writable: true
1724
+ });
1725
+ }
1726
+ }
1727
+ function buildStreamSnapshot(stream) {
1728
+ return {
1729
+ finishReason: stream._getImmediateFinishReason?.(),
1730
+ status: stream.status,
1731
+ text: stream._getImmediateText?.(),
1732
+ toolCalls: stream._getImmediateToolCalls?.(),
1733
+ toolResults: stream._getImmediateToolResults?.(),
1734
+ usage: stream._getImmediateUsage?.(),
1735
+ warnings: stream._getImmediateWarnings?.()
1736
+ };
1737
+ }
1738
+ function isReadableStream(value) {
1739
+ return typeof value === "object" && value !== null && "pipeThrough" in value && typeof value.pipeThrough === "function";
1740
+ }
1741
+ export {
1742
+ wrapAgent
1743
+ };
1744
+ //# sourceMappingURL=wrap-agent.js.map