@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,2249 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { createRequire, syncBuiltinESMExports } from "node:module";
3
+ import { context, trace } from "@opentelemetry/api";
4
+ import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
5
+ import {
6
+ getPendingApproval,
7
+ isActivityApproved
8
+ } from "../governance/approval-registry.js";
9
+ import { getOpenBoxExecutionContext } from "../governance/context.js";
10
+ import { OpenBoxSpanProcessor } from "../span/index.js";
11
+ import {
12
+ ApprovalPendingError,
13
+ GovernanceHaltError,
14
+ Verdict,
15
+ WorkflowEventType
16
+ } from "../types/index.js";
17
+ const DB_INSTRUMENTATION_NAMES = /* @__PURE__ */ new Map([
18
+ ["pg", ["@opentelemetry/instrumentation-pg"]],
19
+ ["postgres", ["@opentelemetry/instrumentation-pg"]],
20
+ ["mysql", ["@opentelemetry/instrumentation-mysql"]],
21
+ ["mysql2", ["@opentelemetry/instrumentation-mysql2"]],
22
+ ["mongodb", ["@opentelemetry/instrumentation-mongodb"]],
23
+ ["mongoose", ["@opentelemetry/instrumentation-mongoose"]],
24
+ ["redis", ["@opentelemetry/instrumentation-redis"]],
25
+ ["ioredis", ["@opentelemetry/instrumentation-ioredis"]],
26
+ ["knex", ["@opentelemetry/instrumentation-knex"]],
27
+ ["oracledb", ["@opentelemetry/instrumentation-oracledb"]],
28
+ ["cassandra", ["@opentelemetry/instrumentation-cassandra-driver"]],
29
+ ["tedious", ["@opentelemetry/instrumentation-tedious"]]
30
+ ]);
31
+ const HTTP_INSTRUMENTATION_DEFINITIONS = [
32
+ {
33
+ exportName: "HttpInstrumentation",
34
+ moduleName: "@opentelemetry/instrumentation-http"
35
+ },
36
+ {
37
+ exportName: "UndiciInstrumentation",
38
+ moduleName: "@opentelemetry/instrumentation-undici"
39
+ }
40
+ ];
41
+ const DB_INSTRUMENTATION_DEFINITIONS = /* @__PURE__ */ new Map([
42
+ [
43
+ "@opentelemetry/instrumentation-pg",
44
+ {
45
+ exportName: "PgInstrumentation",
46
+ moduleName: "@opentelemetry/instrumentation-pg"
47
+ }
48
+ ],
49
+ [
50
+ "@opentelemetry/instrumentation-mysql",
51
+ {
52
+ exportName: "MySQLInstrumentation",
53
+ moduleName: "@opentelemetry/instrumentation-mysql"
54
+ }
55
+ ],
56
+ [
57
+ "@opentelemetry/instrumentation-mysql2",
58
+ {
59
+ exportName: "MySQL2Instrumentation",
60
+ moduleName: "@opentelemetry/instrumentation-mysql2"
61
+ }
62
+ ],
63
+ [
64
+ "@opentelemetry/instrumentation-mongodb",
65
+ {
66
+ exportName: "MongoDBInstrumentation",
67
+ moduleName: "@opentelemetry/instrumentation-mongodb"
68
+ }
69
+ ],
70
+ [
71
+ "@opentelemetry/instrumentation-mongoose",
72
+ {
73
+ exportName: "MongooseInstrumentation",
74
+ moduleName: "@opentelemetry/instrumentation-mongoose"
75
+ }
76
+ ],
77
+ [
78
+ "@opentelemetry/instrumentation-redis",
79
+ {
80
+ exportName: "RedisInstrumentation",
81
+ moduleName: "@opentelemetry/instrumentation-redis"
82
+ }
83
+ ],
84
+ [
85
+ "@opentelemetry/instrumentation-ioredis",
86
+ {
87
+ exportName: "IORedisInstrumentation",
88
+ moduleName: "@opentelemetry/instrumentation-ioredis"
89
+ }
90
+ ],
91
+ [
92
+ "@opentelemetry/instrumentation-knex",
93
+ {
94
+ exportName: "KnexInstrumentation",
95
+ moduleName: "@opentelemetry/instrumentation-knex"
96
+ }
97
+ ],
98
+ [
99
+ "@opentelemetry/instrumentation-oracledb",
100
+ {
101
+ exportName: "OracleInstrumentation",
102
+ moduleName: "@opentelemetry/instrumentation-oracledb"
103
+ }
104
+ ],
105
+ [
106
+ "@opentelemetry/instrumentation-cassandra-driver",
107
+ {
108
+ exportName: "CassandraDriverInstrumentation",
109
+ moduleName: "@opentelemetry/instrumentation-cassandra-driver"
110
+ }
111
+ ],
112
+ [
113
+ "@opentelemetry/instrumentation-tedious",
114
+ {
115
+ exportName: "TediousInstrumentation",
116
+ moduleName: "@opentelemetry/instrumentation-tedious"
117
+ }
118
+ ]
119
+ ]);
120
+ const DEFAULT_FILE_SKIP_PATTERNS = [
121
+ "/dev/",
122
+ "/proc/",
123
+ "/sys/",
124
+ "\\\\?\\pipe\\",
125
+ "__pycache__",
126
+ ".pyc",
127
+ ".pyo",
128
+ ".so",
129
+ ".dylib"
130
+ ];
131
+ const TEXT_CONTENT_TYPES = [
132
+ "text/",
133
+ "application/json",
134
+ "application/xml",
135
+ "application/javascript",
136
+ "application/x-www-form-urlencoded"
137
+ ];
138
+ const APPROVAL_ABORT_PREFIX = "__openbox_approval__:";
139
+ let activeFetchRestore;
140
+ let activeFileRestore;
141
+ let activeHookGovernanceRuntime;
142
+ let activeUnregister;
143
+ function setupOpenBoxOpenTelemetry({
144
+ captureHttpBodies = true,
145
+ dbLibraries,
146
+ fileSkipPatterns = DEFAULT_FILE_SKIP_PATTERNS,
147
+ governanceClient,
148
+ ignoredUrls = [],
149
+ instrumentDatabases = true,
150
+ instrumentFileIo = false,
151
+ onHookApiError,
152
+ spanProcessor
153
+ }) {
154
+ teardownActiveTelemetry();
155
+ const require2 = createRequire(import.meta.url);
156
+ const { registerInstrumentations } = require2(
157
+ "@opentelemetry/instrumentation"
158
+ );
159
+ const tracerProvider = new NodeTracerProvider({
160
+ spanProcessors: [spanProcessor]
161
+ });
162
+ tracerProvider.register();
163
+ const hookGovernance = governanceClient ? {
164
+ client: governanceClient,
165
+ onApiError: onHookApiError ?? governanceClient.onApiError ?? "fail_open",
166
+ spanProcessor
167
+ } : void 0;
168
+ activeHookGovernanceRuntime = hookGovernance;
169
+ const instrumentations = [
170
+ ...selectHttpInstrumentations(ignoredUrls, captureHttpBodies),
171
+ ...selectDatabaseInstrumentations(
172
+ instrumentDatabases,
173
+ dbLibraries,
174
+ hookGovernance
175
+ ),
176
+ ...selectFileInstrumentation(instrumentFileIo, fileSkipPatterns)
177
+ ];
178
+ activeUnregister = registerInstrumentations({
179
+ instrumentations,
180
+ tracerProvider
181
+ });
182
+ if (captureHttpBodies) {
183
+ activeFetchRestore = patchFetch(
184
+ spanProcessor,
185
+ ignoredUrls,
186
+ hookGovernance
187
+ );
188
+ }
189
+ if (instrumentFileIo) {
190
+ activeFileRestore = patchFileIo(fileSkipPatterns, hookGovernance);
191
+ }
192
+ return {
193
+ instrumentations,
194
+ async shutdown() {
195
+ teardownActiveTelemetry();
196
+ await tracerProvider.shutdown();
197
+ disableGlobalTraceApi();
198
+ },
199
+ tracerProvider
200
+ };
201
+ }
202
+ function traced(fn, options = {}) {
203
+ return async function openBoxTraced(...args) {
204
+ const hookGovernance = activeHookGovernanceRuntime;
205
+ if (!hookGovernance) {
206
+ return fn.apply(this, args);
207
+ }
208
+ const functionName = options.name ?? fn.name ?? "anonymous";
209
+ const moduleName = options.module ?? "unknown";
210
+ const tracer = trace.getTracer(options.tracerName ?? "openbox.tracing");
211
+ return tracer.startActiveSpan(`function.${functionName}`, async (span) => {
212
+ const spanContext = span.spanContext();
213
+ const startTimeNs = Date.now() * 1e6;
214
+ const hookSpanId = normalizeHexId(void 0, 16);
215
+ span.setAttribute("code.function", functionName);
216
+ span.setAttribute("code.namespace", moduleName);
217
+ let fnStarted = false;
218
+ try {
219
+ await evaluateHookGovernance(hookGovernance, {
220
+ activeSpan: span,
221
+ hookTrigger: {
222
+ attribute_key_identifiers: ["code.function", "code.namespace"],
223
+ ...options.captureArgs ? { args: sanitizeForGovernancePayload(args) } : {},
224
+ function: functionName,
225
+ module: moduleName,
226
+ stage: "started",
227
+ type: "function_call"
228
+ },
229
+ span: createHookSpan({
230
+ attributes: {
231
+ "code.function": functionName,
232
+ "code.namespace": moduleName
233
+ },
234
+ endTimeNs: startTimeNs,
235
+ functionArgs: options.captureArgs ? args : void 0,
236
+ functionModule: moduleName,
237
+ functionName,
238
+ hookType: "function_call",
239
+ kind: "INTERNAL",
240
+ name: `function.${functionName}`,
241
+ parentSpanId: spanContext.spanId,
242
+ semanticType: "function_call",
243
+ spanId: hookSpanId,
244
+ stage: "started",
245
+ startTimeNs,
246
+ traceId: spanContext.traceId
247
+ }),
248
+ stage: "started",
249
+ traceId: spanContext.traceId
250
+ });
251
+ fnStarted = true;
252
+ const result = await fn.apply(this, args);
253
+ const endTimeNs = Date.now() * 1e6;
254
+ await evaluateHookGovernance(hookGovernance, {
255
+ activeSpan: span,
256
+ hookTrigger: {
257
+ attribute_key_identifiers: ["code.function", "code.namespace"],
258
+ function: functionName,
259
+ module: moduleName,
260
+ ...options.captureResult ? { result: sanitizeForGovernancePayload(result) } : {},
261
+ stage: "completed",
262
+ type: "function_call"
263
+ },
264
+ span: createHookSpan({
265
+ attributes: {
266
+ "code.function": functionName,
267
+ "code.namespace": moduleName
268
+ },
269
+ endTimeNs,
270
+ functionModule: moduleName,
271
+ functionName,
272
+ functionResult: options.captureResult ? result : void 0,
273
+ hookType: "function_call",
274
+ kind: "INTERNAL",
275
+ name: `function.${functionName}`,
276
+ parentSpanId: spanContext.spanId,
277
+ semanticType: "function_call",
278
+ spanId: hookSpanId,
279
+ stage: "completed",
280
+ startTimeNs,
281
+ traceId: spanContext.traceId
282
+ }),
283
+ stage: "completed",
284
+ traceId: spanContext.traceId
285
+ });
286
+ return result;
287
+ } catch (error) {
288
+ if (fnStarted) {
289
+ const endTimeNs = Date.now() * 1e6;
290
+ await evaluateHookGovernance(hookGovernance, {
291
+ activeSpan: span,
292
+ hookTrigger: {
293
+ attribute_key_identifiers: ["code.function", "code.namespace"],
294
+ error: error instanceof Error ? error.message : String(error),
295
+ function: functionName,
296
+ module: moduleName,
297
+ stage: "completed",
298
+ type: "function_call"
299
+ },
300
+ span: createHookSpan({
301
+ attributes: {
302
+ "code.function": functionName,
303
+ "code.namespace": moduleName
304
+ },
305
+ endTimeNs,
306
+ error: error instanceof Error ? error.message : String(error),
307
+ functionModule: moduleName,
308
+ functionName,
309
+ hookType: "function_call",
310
+ kind: "INTERNAL",
311
+ name: `function.${functionName}`,
312
+ parentSpanId: spanContext.spanId,
313
+ semanticType: "function_call",
314
+ spanId: hookSpanId,
315
+ stage: "completed",
316
+ startTimeNs,
317
+ traceId: spanContext.traceId
318
+ }),
319
+ stage: "completed",
320
+ traceId: spanContext.traceId
321
+ });
322
+ }
323
+ throw error;
324
+ } finally {
325
+ span.end();
326
+ }
327
+ });
328
+ };
329
+ }
330
+ function selectHttpInstrumentations(ignoredUrls, captureHttpBodies) {
331
+ if (!captureHttpBodies) {
332
+ return [];
333
+ }
334
+ return HTTP_INSTRUMENTATION_DEFINITIONS.map((definition) => {
335
+ if (definition.moduleName === "@opentelemetry/instrumentation-http") {
336
+ return loadInstrumentation(definition, {
337
+ disableIncomingRequestInstrumentation: true,
338
+ headersToSpanAttributes: {},
339
+ ignoreOutgoingRequestHook: (request) => {
340
+ const url = buildRequestUrl(request);
341
+ return shouldIgnoreUrl(url, ignoredUrls);
342
+ }
343
+ });
344
+ }
345
+ return loadInstrumentation(definition);
346
+ });
347
+ }
348
+ function selectDatabaseInstrumentations(instrumentDatabases, dbLibraries, hookGovernance) {
349
+ if (!instrumentDatabases) {
350
+ return [];
351
+ }
352
+ const enabledNames = dbLibraries && dbLibraries.size > 0 ? new Set(
353
+ [...dbLibraries].flatMap(
354
+ (name) => DB_INSTRUMENTATION_NAMES.get(name.toLowerCase()) ?? []
355
+ )
356
+ ) : void 0;
357
+ const definitions = enabledNames ? [...enabledNames].map((name) => DB_INSTRUMENTATION_DEFINITIONS.get(name)).filter(
358
+ (definition) => definition !== void 0
359
+ ) : [...DB_INSTRUMENTATION_DEFINITIONS.values()];
360
+ return definitions.map(
361
+ (definition) => loadInstrumentation(
362
+ definition,
363
+ createDatabaseInstrumentationConfig(
364
+ definition.moduleName,
365
+ hookGovernance
366
+ )
367
+ )
368
+ );
369
+ }
370
+ function selectFileInstrumentation(instrumentFileIo, fileSkipPatterns) {
371
+ if (!instrumentFileIo) {
372
+ return [];
373
+ }
374
+ const require2 = createRequire(import.meta.url);
375
+ const { FsInstrumentation } = require2(
376
+ "@opentelemetry/instrumentation-fs"
377
+ );
378
+ const instrumentation = new FsInstrumentation({
379
+ createHook(_functionName, info) {
380
+ const filePath = getFilePathFromArgs(info.args);
381
+ if (!filePath) {
382
+ return true;
383
+ }
384
+ if (fileSkipPatterns.some((pattern) => filePath.includes(pattern))) {
385
+ return false;
386
+ }
387
+ return !filePath.startsWith("/dev/");
388
+ },
389
+ requireParentSpan: true
390
+ });
391
+ return [instrumentation];
392
+ }
393
+ function createDatabaseInstrumentationConfig(moduleName, hookGovernance) {
394
+ if (!hookGovernance) {
395
+ return void 0;
396
+ }
397
+ const queryStartTimes = /* @__PURE__ */ new Map();
398
+ const emitStarted = (span, details) => {
399
+ const spanId = span.spanContext().spanId;
400
+ const startTimeNs = Date.now() * 1e6;
401
+ const hookSpanId = normalizeHexId(void 0, 16);
402
+ queryStartTimes.set(spanId, {
403
+ hookSpanId,
404
+ startTimeNs
405
+ });
406
+ void emitDatabaseHookGovernance({
407
+ details,
408
+ hookSpanId,
409
+ hookGovernance,
410
+ span,
411
+ stage: "started",
412
+ startTimeNs
413
+ }).catch(() => void 0);
414
+ };
415
+ const emitCompleted = (span, details) => {
416
+ const spanId = span.spanContext().spanId;
417
+ const trackedSpan = queryStartTimes.get(spanId);
418
+ const startTimeNs = trackedSpan?.startTimeNs ?? Date.now() * 1e6;
419
+ const hookSpanId = trackedSpan?.hookSpanId ?? normalizeHexId(void 0, 16);
420
+ queryStartTimes.delete(spanId);
421
+ void emitDatabaseHookGovernance({
422
+ details,
423
+ hookSpanId,
424
+ hookGovernance,
425
+ span,
426
+ stage: "completed",
427
+ startTimeNs
428
+ }).catch(() => void 0);
429
+ };
430
+ if (moduleName === "@opentelemetry/instrumentation-pg") {
431
+ return {
432
+ enhancedDatabaseReporting: true,
433
+ requestHook(span, info) {
434
+ const dbStatement = info.query?.text ?? toStringValue(getSpanAttribute(span, "db.statement"));
435
+ emitStarted(span, {
436
+ dbName: info.connection?.database ?? toStringValue(getSpanAttribute(span, "db.name")),
437
+ dbOperation: parseDbOperation(dbStatement) ?? toStringValue(getSpanAttribute(span, "db.operation")),
438
+ dbStatement,
439
+ dbSystem: toStringValue(getSpanAttribute(span, "db.system")) ?? "postgresql",
440
+ serverAddress: info.connection?.host ?? toStringValue(getSpanAttribute(span, "server.address")) ?? toStringValue(getSpanAttribute(span, "net.peer.name")),
441
+ serverPort: toNumberValue(getSpanAttribute(span, "server.port")) ?? toNumberValue(getSpanAttribute(span, "net.peer.port")) ?? info.connection?.port
442
+ });
443
+ },
444
+ responseHook(span) {
445
+ const dbStatement = toStringValue(getSpanAttribute(span, "db.statement"));
446
+ emitCompleted(span, {
447
+ dbName: toStringValue(getSpanAttribute(span, "db.name")),
448
+ dbOperation: parseDbOperation(dbStatement) ?? toStringValue(getSpanAttribute(span, "db.operation")),
449
+ dbStatement,
450
+ dbSystem: toStringValue(getSpanAttribute(span, "db.system")) ?? "postgresql",
451
+ error: toStringValue(getSpanAttribute(span, "error.type")) ?? toStringValue(getSpanAttribute(span, "exception.message")),
452
+ serverAddress: toStringValue(getSpanAttribute(span, "server.address")) ?? toStringValue(getSpanAttribute(span, "net.peer.name")),
453
+ serverPort: toNumberValue(getSpanAttribute(span, "server.port")) ?? toNumberValue(getSpanAttribute(span, "net.peer.port"))
454
+ });
455
+ }
456
+ };
457
+ }
458
+ if (moduleName === "@opentelemetry/instrumentation-oracledb") {
459
+ return {
460
+ enhancedDatabaseReporting: true,
461
+ requestHook(span, info) {
462
+ const dbStatement = Array.isArray(info.inputArgs) ? toStringValue(info.inputArgs[0]) : void 0;
463
+ emitStarted(span, {
464
+ dbName: info.connection?.serviceName ?? toStringValue(getSpanAttribute(span, "db.name")),
465
+ dbOperation: parseDbOperation(dbStatement) ?? toStringValue(getSpanAttribute(span, "db.operation")),
466
+ dbStatement: dbStatement ?? toStringValue(getSpanAttribute(span, "db.statement")),
467
+ dbSystem: toStringValue(getSpanAttribute(span, "db.system")) ?? "oracle",
468
+ serverAddress: info.connection?.hostName ?? toStringValue(getSpanAttribute(span, "server.address")) ?? toStringValue(getSpanAttribute(span, "net.peer.name")),
469
+ serverPort: toNumberValue(getSpanAttribute(span, "server.port")) ?? toNumberValue(getSpanAttribute(span, "net.peer.port")) ?? info.connection?.port
470
+ });
471
+ },
472
+ responseHook(span) {
473
+ const dbStatement = toStringValue(getSpanAttribute(span, "db.statement"));
474
+ emitCompleted(span, {
475
+ dbName: toStringValue(getSpanAttribute(span, "db.name")),
476
+ dbOperation: parseDbOperation(dbStatement) ?? toStringValue(getSpanAttribute(span, "db.operation")),
477
+ dbStatement,
478
+ dbSystem: toStringValue(getSpanAttribute(span, "db.system")) ?? "oracle",
479
+ error: toStringValue(getSpanAttribute(span, "error.type")) ?? toStringValue(getSpanAttribute(span, "exception.message")),
480
+ serverAddress: toStringValue(getSpanAttribute(span, "server.address")) ?? toStringValue(getSpanAttribute(span, "net.peer.name")),
481
+ serverPort: toNumberValue(getSpanAttribute(span, "server.port")) ?? toNumberValue(getSpanAttribute(span, "net.peer.port"))
482
+ });
483
+ }
484
+ };
485
+ }
486
+ return void 0;
487
+ }
488
+ async function emitDatabaseHookGovernance(input) {
489
+ const spanContext = input.span.spanContext();
490
+ const nowNs = Date.now() * 1e6;
491
+ const dbOperation = input.details.dbOperation ?? "query";
492
+ const hookTrigger = {
493
+ attribute_key_identifiers: ["db.system", "db.operation", "db.statement"],
494
+ db_name: input.details.dbName,
495
+ db_operation: dbOperation,
496
+ db_statement: input.details.dbStatement,
497
+ db_system: input.details.dbSystem ?? "unknown",
498
+ server_address: input.details.serverAddress,
499
+ server_port: input.details.serverPort,
500
+ stage: input.stage,
501
+ type: "db_query"
502
+ };
503
+ if (input.stage === "completed") {
504
+ hookTrigger.duration_ms = Math.max(
505
+ 0,
506
+ Math.round((nowNs - input.startTimeNs) / 1e6)
507
+ );
508
+ hookTrigger.error = input.details.error;
509
+ }
510
+ await evaluateHookGovernance(input.hookGovernance, {
511
+ activeSpan: input.span,
512
+ hookTrigger,
513
+ span: createHookSpan({
514
+ attributes: {
515
+ "db.name": input.details.dbName ?? "unknown",
516
+ "db.operation": dbOperation,
517
+ "db.statement": input.details.dbStatement ?? "",
518
+ "db.system": input.details.dbSystem ?? "unknown",
519
+ ...input.details.serverAddress ? { "server.address": input.details.serverAddress } : {},
520
+ ...typeof input.details.serverPort === "number" ? { "server.port": input.details.serverPort } : {}
521
+ },
522
+ dbName: input.details.dbName,
523
+ dbOperation,
524
+ dbStatement: input.details.dbStatement,
525
+ dbSystem: input.details.dbSystem ?? "unknown",
526
+ endTimeNs: nowNs,
527
+ error: input.details.error,
528
+ hookType: "db_query",
529
+ kind: "CLIENT",
530
+ name: input.span.name ?? `DB ${dbOperation}`,
531
+ parentSpanId: spanContext.spanId,
532
+ semanticType: resolveDatabaseSemanticType(dbOperation),
533
+ serverAddress: input.details.serverAddress,
534
+ serverPort: input.details.serverPort,
535
+ spanId: input.hookSpanId,
536
+ stage: input.stage,
537
+ startTimeNs: input.startTimeNs,
538
+ traceId: spanContext.traceId
539
+ }),
540
+ stage: input.stage,
541
+ traceId: spanContext.traceId
542
+ });
543
+ }
544
+ function patchFetch(spanProcessor, ignoredUrls, hookGovernance) {
545
+ const originalFetch = globalThis.fetch;
546
+ if (!originalFetch || !globalThis.Request || !globalThis.Response || !globalThis.Headers) {
547
+ throw new Error("Global fetch APIs are required for OpenBox HTTP body capture");
548
+ }
549
+ globalThis.fetch = async function patchedFetch(input, init) {
550
+ const request = new globalThis.Request(input, init);
551
+ const url = request.url;
552
+ if (shouldIgnoreUrl(url, ignoredUrls)) {
553
+ return originalFetch(request);
554
+ }
555
+ const activeSpan = trace.getActiveSpan();
556
+ if (!activeSpan) {
557
+ return originalFetch(request);
558
+ }
559
+ const requestBody = normalizeHookBodyForTelemetry(
560
+ await captureRequestBody(request)
561
+ );
562
+ const requestHeaders = headersToRecord(request.headers);
563
+ const spanContext = activeSpan.spanContext();
564
+ const startTimeNs = Date.now() * 1e6;
565
+ const hookSpanId = normalizeHexId(void 0, 16);
566
+ const startedSemanticType = resolveHttpSemanticType({
567
+ method: request.method,
568
+ requestBody,
569
+ url
570
+ });
571
+ await evaluateHookGovernance(hookGovernance, {
572
+ activeSpan,
573
+ hookTrigger: {
574
+ method: request.method,
575
+ request_body: requestBody,
576
+ request_headers: requestHeaders,
577
+ stage: "started",
578
+ type: "http_request",
579
+ url
580
+ },
581
+ span: createHookSpan({
582
+ attributes: {
583
+ "http.method": request.method,
584
+ "http.url": url
585
+ },
586
+ endTimeNs: startTimeNs,
587
+ hookType: "http_request",
588
+ httpMethod: request.method,
589
+ httpUrl: url,
590
+ kind: "CLIENT",
591
+ name: `HTTP ${request.method}`,
592
+ parentSpanId: spanContext.spanId,
593
+ requestBody,
594
+ requestHeaders,
595
+ semanticType: startedSemanticType,
596
+ spanId: hookSpanId,
597
+ stage: "started",
598
+ startTimeNs,
599
+ traceId: spanContext.traceId
600
+ }),
601
+ stage: "started",
602
+ traceId: spanContext.traceId
603
+ });
604
+ const response = await originalFetch(request);
605
+ const responseHeaders = headersToRecord(response.headers);
606
+ const responseBody = normalizeHookBodyForTelemetry(
607
+ await captureResponseBody(response)
608
+ );
609
+ spanProcessor.storeTraceBody(spanContext.traceId, {
610
+ method: request.method,
611
+ requestBody,
612
+ requestHeaders,
613
+ responseBody,
614
+ responseHeaders,
615
+ url
616
+ });
617
+ const endTimeNs = Date.now() * 1e6;
618
+ const completedHookTrigger = {
619
+ method: request.method,
620
+ request_body: requestBody,
621
+ request_headers: requestHeaders,
622
+ response_body: responseBody,
623
+ response_headers: responseHeaders,
624
+ status_code: response.status,
625
+ type: "http_request",
626
+ url
627
+ };
628
+ const completedSemanticType = resolveHttpSemanticType({
629
+ method: request.method,
630
+ requestBody,
631
+ responseBody,
632
+ url
633
+ });
634
+ const completedHookSpanBase = {
635
+ attributes: {
636
+ "http.method": request.method,
637
+ "http.status_code": response.status,
638
+ "http.url": url
639
+ },
640
+ endTimeNs,
641
+ hookType: "http_request",
642
+ httpMethod: request.method,
643
+ httpStatusCode: response.status,
644
+ httpUrl: url,
645
+ kind: "CLIENT",
646
+ name: `HTTP ${request.method}`,
647
+ parentSpanId: spanContext.spanId,
648
+ requestBody,
649
+ requestHeaders,
650
+ responseBody,
651
+ responseHeaders,
652
+ semanticType: completedSemanticType,
653
+ spanId: hookSpanId,
654
+ startTimeNs,
655
+ traceId: spanContext.traceId
656
+ };
657
+ await evaluateHookGovernance(hookGovernance, {
658
+ activeSpan,
659
+ hookTrigger: {
660
+ ...completedHookTrigger,
661
+ stage: "completed"
662
+ },
663
+ span: createHookSpan({
664
+ ...completedHookSpanBase,
665
+ stage: "completed"
666
+ }),
667
+ stage: "completed",
668
+ traceId: spanContext.traceId
669
+ });
670
+ return response;
671
+ };
672
+ return () => {
673
+ globalThis.fetch = originalFetch;
674
+ };
675
+ }
676
+ async function captureRequestBody(request) {
677
+ const contentType = request.headers.get("content-type");
678
+ if (!isTextContentType(contentType)) {
679
+ return void 0;
680
+ }
681
+ const clone = request.clone();
682
+ const text = await clone.text();
683
+ return text || void 0;
684
+ }
685
+ async function captureResponseBody(response) {
686
+ const contentType = response.headers.get("content-type");
687
+ if (!isTextContentType(contentType)) {
688
+ return void 0;
689
+ }
690
+ const clone = response.clone();
691
+ const text = await clone.text();
692
+ return text || void 0;
693
+ }
694
+ function headersToRecord(headers) {
695
+ const result = {};
696
+ headers.forEach((value, key) => {
697
+ result[key] = value;
698
+ });
699
+ return result;
700
+ }
701
+ function shouldIgnoreUrl(url, ignoredUrls) {
702
+ if (!url) {
703
+ return false;
704
+ }
705
+ return ignoredUrls.some((prefix) => url.startsWith(prefix));
706
+ }
707
+ function resolveHttpSemanticType(input) {
708
+ const normalizedMethod = input.method.trim().toUpperCase();
709
+ const requestRecords = parseHookBodyRecords(input.requestBody);
710
+ const responseRecords = parseHookBodyRecords(input.responseBody);
711
+ const modelId = extractModelFromRecords(responseRecords) ?? extractModelFromRecords(requestRecords);
712
+ const provider = inferProviderFromUrl(input.url) ?? inferProviderFromModelId(modelId);
713
+ if (normalizedMethod === "POST" && provider) {
714
+ return isLikelyLlmEmbedding(input.url, requestRecords, responseRecords) ? "llm_embedding" : "llm_completion";
715
+ }
716
+ switch (normalizedMethod) {
717
+ case "GET":
718
+ return "http_get";
719
+ case "POST":
720
+ return "http_post";
721
+ case "PUT":
722
+ return "http_put";
723
+ case "PATCH":
724
+ return "http_patch";
725
+ case "DELETE":
726
+ return "http_delete";
727
+ default:
728
+ return "http";
729
+ }
730
+ }
731
+ function resolveDatabaseSemanticType(operation) {
732
+ const normalized = operation.trim().toUpperCase();
733
+ switch (normalized) {
734
+ case "SELECT":
735
+ return "database_select";
736
+ case "INSERT":
737
+ return "database_insert";
738
+ case "UPDATE":
739
+ return "database_update";
740
+ case "DELETE":
741
+ return "database_delete";
742
+ default:
743
+ return "database_query";
744
+ }
745
+ }
746
+ function isLikelyLlmEmbedding(url, requestRecords, responseRecords) {
747
+ const normalizedUrl = url.toLowerCase();
748
+ if (normalizedUrl.includes("embedding")) {
749
+ return true;
750
+ }
751
+ const combined = JSON.stringify([...requestRecords, ...responseRecords]).toLowerCase();
752
+ return combined.includes("embedding");
753
+ }
754
+ function isTextContentType(contentType) {
755
+ if (!contentType) {
756
+ return true;
757
+ }
758
+ const normalized = contentType.toLowerCase().split(";")[0]?.trim() ?? "";
759
+ return TEXT_CONTENT_TYPES.some((type) => normalized.startsWith(type));
760
+ }
761
+ function buildRequestUrl(request) {
762
+ if (request.href) {
763
+ return request.href;
764
+ }
765
+ if (!request.protocol || !(request.host || request.hostname)) {
766
+ return void 0;
767
+ }
768
+ const host = request.host ?? request.hostname;
769
+ return `${request.protocol}//${host}${request.path ?? ""}`;
770
+ }
771
+ function getFilePathFromArgs(args) {
772
+ const candidate = args[0];
773
+ return typeof candidate === "string" ? candidate : void 0;
774
+ }
775
+ function teardownActiveTelemetry() {
776
+ activeFetchRestore?.();
777
+ activeFetchRestore = void 0;
778
+ activeFileRestore?.();
779
+ activeFileRestore = void 0;
780
+ activeHookGovernanceRuntime = void 0;
781
+ activeUnregister?.();
782
+ activeUnregister = void 0;
783
+ }
784
+ function disableGlobalTraceApi() {
785
+ const traceApi = trace;
786
+ traceApi.disable?.();
787
+ }
788
+ function patchFileIo(fileSkipPatterns, hookGovernance) {
789
+ const require2 = createRequire(import.meta.url);
790
+ const fsPromises = require2("node:fs/promises");
791
+ const fsModule = require2("node:fs");
792
+ const tracer = trace.getTracer("openbox.file-io");
793
+ const originalReadFile = fsPromises.readFile;
794
+ const originalWriteFile = fsPromises.writeFile;
795
+ const originalFsReadFile = fsModule.promises.readFile;
796
+ const originalFsWriteFile = fsModule.promises.writeFile;
797
+ const tracedReadFile = async function openBoxReadFile(...args) {
798
+ const [path] = args;
799
+ const filePath = String(path);
800
+ if (shouldSkipFilePath(filePath, fileSkipPatterns)) {
801
+ return originalReadFile(...args);
802
+ }
803
+ return context.with(context.active(), async () => {
804
+ return tracer.startActiveSpan("file.read", async (span) => {
805
+ span.setAttribute("file.path", filePath);
806
+ span.setAttribute("file.operation", "read");
807
+ const spanContext = span.spanContext();
808
+ const startTimeNs = Date.now() * 1e6;
809
+ const hookSpanId = normalizeHexId(void 0, 16);
810
+ await evaluateHookGovernance(hookGovernance, {
811
+ activeSpan: span,
812
+ hookTrigger: {
813
+ attribute_key_identifiers: ["file.path", "file.operation"],
814
+ file_operation: "read",
815
+ file_path: filePath,
816
+ stage: "started",
817
+ type: "file_operation"
818
+ },
819
+ span: createHookSpan({
820
+ attributes: {
821
+ "file.operation": "read",
822
+ "file.path": filePath
823
+ },
824
+ endTimeNs: startTimeNs,
825
+ fileMode: "r",
826
+ fileOperation: "read",
827
+ filePath,
828
+ hookType: "file_operation",
829
+ kind: "INTERNAL",
830
+ name: "file.read",
831
+ parentSpanId: spanContext.spanId,
832
+ semanticType: "file_read",
833
+ spanId: hookSpanId,
834
+ stage: "started",
835
+ startTimeNs,
836
+ traceId: spanContext.traceId
837
+ }),
838
+ stage: "started",
839
+ traceId: spanContext.traceId
840
+ });
841
+ try {
842
+ const result = await originalReadFile(...args);
843
+ const bytes = getByteLength(result);
844
+ const endTimeNs = Date.now() * 1e6;
845
+ span.setAttribute("file.bytes", bytes);
846
+ await evaluateHookGovernance(hookGovernance, {
847
+ activeSpan: span,
848
+ hookTrigger: {
849
+ attribute_key_identifiers: ["file.path", "file.operation"],
850
+ bytes_read: bytes,
851
+ file_operation: "read",
852
+ file_path: filePath,
853
+ stage: "completed",
854
+ type: "file_operation"
855
+ },
856
+ span: createHookSpan({
857
+ attributes: {
858
+ "file.bytes": bytes,
859
+ "file.operation": "read",
860
+ "file.path": filePath
861
+ },
862
+ bytesRead: bytes,
863
+ endTimeNs,
864
+ fileMode: "r",
865
+ fileOperation: "read",
866
+ filePath,
867
+ hookType: "file_operation",
868
+ kind: "INTERNAL",
869
+ name: "file.read",
870
+ parentSpanId: spanContext.spanId,
871
+ semanticType: "file_read",
872
+ spanId: hookSpanId,
873
+ stage: "completed",
874
+ startTimeNs,
875
+ traceId: spanContext.traceId
876
+ }),
877
+ stage: "completed",
878
+ traceId: spanContext.traceId
879
+ });
880
+ return result;
881
+ } finally {
882
+ span.end();
883
+ }
884
+ });
885
+ });
886
+ };
887
+ const tracedWriteFile = async function openBoxWriteFile(...args) {
888
+ const [file, data] = args;
889
+ const filePath = String(file);
890
+ if (shouldSkipFilePath(filePath, fileSkipPatterns)) {
891
+ return originalWriteFile(...args);
892
+ }
893
+ return context.with(context.active(), async () => {
894
+ return tracer.startActiveSpan("file.write", async (span) => {
895
+ span.setAttribute("file.path", filePath);
896
+ span.setAttribute("file.operation", "write");
897
+ const bytes = getByteLength(data);
898
+ const spanContext = span.spanContext();
899
+ const startTimeNs = Date.now() * 1e6;
900
+ const hookSpanId = normalizeHexId(void 0, 16);
901
+ span.setAttribute("file.bytes", bytes);
902
+ await evaluateHookGovernance(hookGovernance, {
903
+ activeSpan: span,
904
+ hookTrigger: {
905
+ attribute_key_identifiers: ["file.path", "file.operation"],
906
+ bytes_written: bytes,
907
+ file_operation: "write",
908
+ file_path: filePath,
909
+ stage: "started",
910
+ type: "file_operation"
911
+ },
912
+ span: createHookSpan({
913
+ attributes: {
914
+ "file.bytes": bytes,
915
+ "file.operation": "write",
916
+ "file.path": filePath
917
+ },
918
+ bytesWritten: bytes,
919
+ endTimeNs: startTimeNs,
920
+ fileMode: "w",
921
+ fileOperation: "write",
922
+ filePath,
923
+ hookType: "file_operation",
924
+ kind: "INTERNAL",
925
+ name: "file.write",
926
+ parentSpanId: spanContext.spanId,
927
+ semanticType: "file_write",
928
+ spanId: hookSpanId,
929
+ stage: "started",
930
+ startTimeNs,
931
+ traceId: spanContext.traceId
932
+ }),
933
+ stage: "started",
934
+ traceId: spanContext.traceId
935
+ });
936
+ try {
937
+ const result = await originalWriteFile(...args);
938
+ const endTimeNs = Date.now() * 1e6;
939
+ await evaluateHookGovernance(hookGovernance, {
940
+ activeSpan: span,
941
+ hookTrigger: {
942
+ attribute_key_identifiers: ["file.path", "file.operation"],
943
+ bytes_written: bytes,
944
+ file_operation: "write",
945
+ file_path: filePath,
946
+ stage: "completed",
947
+ type: "file_operation"
948
+ },
949
+ span: createHookSpan({
950
+ attributes: {
951
+ "file.bytes": bytes,
952
+ "file.operation": "write",
953
+ "file.path": filePath
954
+ },
955
+ bytesWritten: bytes,
956
+ endTimeNs,
957
+ fileMode: "w",
958
+ fileOperation: "write",
959
+ filePath,
960
+ hookType: "file_operation",
961
+ kind: "INTERNAL",
962
+ name: "file.write",
963
+ parentSpanId: spanContext.spanId,
964
+ semanticType: "file_write",
965
+ spanId: hookSpanId,
966
+ stage: "completed",
967
+ startTimeNs,
968
+ traceId: spanContext.traceId
969
+ }),
970
+ stage: "completed",
971
+ traceId: spanContext.traceId
972
+ });
973
+ return result;
974
+ } finally {
975
+ span.end();
976
+ }
977
+ });
978
+ });
979
+ };
980
+ fsPromises.readFile = tracedReadFile;
981
+ fsPromises.writeFile = tracedWriteFile;
982
+ fsModule.promises.readFile = tracedReadFile;
983
+ fsModule.promises.writeFile = tracedWriteFile;
984
+ syncBuiltinESMExports();
985
+ return () => {
986
+ fsPromises.readFile = originalReadFile;
987
+ fsPromises.writeFile = originalWriteFile;
988
+ fsModule.promises.readFile = originalFsReadFile;
989
+ fsModule.promises.writeFile = originalFsWriteFile;
990
+ syncBuiltinESMExports();
991
+ };
992
+ }
993
+ function getByteLength(value) {
994
+ if (typeof value === "string") {
995
+ return Buffer.byteLength(value);
996
+ }
997
+ if (value instanceof Uint8Array) {
998
+ return value.byteLength;
999
+ }
1000
+ return 0;
1001
+ }
1002
+ function shouldSkipFilePath(filePath, fileSkipPatterns) {
1003
+ return fileSkipPatterns.some((pattern) => filePath.includes(pattern));
1004
+ }
1005
+ async function evaluateHookGovernance(hookGovernance, input) {
1006
+ if (!hookGovernance) {
1007
+ return;
1008
+ }
1009
+ const activityContext = resolveActivityContext(
1010
+ hookGovernance.spanProcessor,
1011
+ input.traceId
1012
+ );
1013
+ if (!activityContext) {
1014
+ return;
1015
+ }
1016
+ const hookSpan = enrichHookSpanForData(
1017
+ cloneHookSpanPayload(input.span)
1018
+ );
1019
+ const hookSpanForPayload = input.stage === "started" ? ensureStartedHookSpan(hookSpan) : ensureCompletedHookSpan(hookSpan);
1020
+ if (activityContext.syntheticAgentActivity) {
1021
+ hookGovernance.spanProcessor.appendAgentSignalHookSpan(
1022
+ activityContext.workflowId,
1023
+ activityContext.runId,
1024
+ hookSpanForPayload
1025
+ );
1026
+ return;
1027
+ }
1028
+ const priorAbortReason = hookGovernance.spanProcessor.getActivityAbort(
1029
+ activityContext.workflowId,
1030
+ activityContext.activityId
1031
+ );
1032
+ if (priorAbortReason) {
1033
+ if (priorAbortReason.startsWith(APPROVAL_ABORT_PREFIX)) {
1034
+ throw new ApprovalPendingError(
1035
+ priorAbortReason.slice(APPROVAL_ABORT_PREFIX.length)
1036
+ );
1037
+ }
1038
+ throw new GovernanceHaltError(`Governance blocked: ${priorAbortReason}`);
1039
+ }
1040
+ const parentActivityApproved = isActivityApproved(
1041
+ activityContext.runId,
1042
+ activityContext.activityId
1043
+ );
1044
+ const pendingApproval = getPendingApproval(activityContext.runId);
1045
+ if (pendingApproval?.activityId === activityContext.activityId) {
1046
+ return;
1047
+ }
1048
+ hookGovernance.spanProcessor.markGoverned(
1049
+ input.activeSpan.spanContext().spanId
1050
+ );
1051
+ const modelUsage = extractModelUsageFromHookSpan(hookSpan);
1052
+ const telemetryModelId = toTelemetryModelId(modelUsage.modelId);
1053
+ const hookType = toStringValue(hookSpan.hook_type) ?? toStringValue(input.hookTrigger.type) ?? "hook";
1054
+ const hookActivityType = resolveHookActivityType(
1055
+ activityContext.activityType,
1056
+ hookType
1057
+ );
1058
+ const eventType = WorkflowEventType.ACTIVITY_STARTED;
1059
+ const payload = {
1060
+ activity_id: activityContext.activityId,
1061
+ attempt: typeof activityContext.attempt === "number" ? activityContext.attempt : 1,
1062
+ activity_type: hookActivityType,
1063
+ event_type: eventType,
1064
+ hook_trigger: true,
1065
+ ...activityContext.goal ? { goal: activityContext.goal } : {},
1066
+ run_id: activityContext.runId,
1067
+ source: "workflow-telemetry",
1068
+ ...modelUsage.modelId ? { model_id: modelUsage.modelId } : {},
1069
+ ...telemetryModelId ? { model: telemetryModelId } : {},
1070
+ ...modelUsage.provider ? { model_provider: modelUsage.provider } : {},
1071
+ ...modelUsage.provider ? { provider: modelUsage.provider } : {},
1072
+ ...typeof modelUsage.inputTokens === "number" ? { input_tokens: modelUsage.inputTokens } : {},
1073
+ ...typeof modelUsage.outputTokens === "number" ? { output_tokens: modelUsage.outputTokens } : {},
1074
+ ...typeof modelUsage.totalTokens === "number" ? { total_tokens: modelUsage.totalTokens } : {},
1075
+ span_count: 1,
1076
+ spans: [hookSpanForPayload],
1077
+ task_queue: activityContext.taskQueue,
1078
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1079
+ workflow_id: activityContext.workflowId,
1080
+ workflow_type: activityContext.workflowType
1081
+ };
1082
+ if (activityContext.activityInput !== void 0) {
1083
+ payload.activity_input = activityContext.activityInput;
1084
+ }
1085
+ if (activityContext.activityType === "agentLlmCompletion") {
1086
+ const derivedActivityPayload = deriveAgentHookActivityPayload(
1087
+ input.hookTrigger,
1088
+ input.stage
1089
+ );
1090
+ if (payload.activity_input === void 0 && derivedActivityPayload.activityInput !== void 0) {
1091
+ payload.activity_input = derivedActivityPayload.activityInput;
1092
+ }
1093
+ if (derivedActivityPayload.activityOutput !== void 0) {
1094
+ payload.activity_output = derivedActivityPayload.activityOutput;
1095
+ }
1096
+ }
1097
+ if (activityContext.goal) {
1098
+ payload.activity_input = appendGoalToHookActivityInput(
1099
+ payload.activity_input,
1100
+ activityContext.goal
1101
+ );
1102
+ }
1103
+ let verdict;
1104
+ try {
1105
+ verdict = await hookGovernance.client.evaluate(payload);
1106
+ } catch (error) {
1107
+ if (hookGovernance.onApiError === "fail_open") {
1108
+ return;
1109
+ }
1110
+ throw new GovernanceHaltError(
1111
+ `Governance API error: ${error instanceof Error ? error.message : String(error)}`
1112
+ );
1113
+ }
1114
+ if (!verdict || !Verdict.shouldStop(verdict.verdict) && !Verdict.requiresApproval(verdict.verdict)) {
1115
+ return;
1116
+ }
1117
+ if (parentActivityApproved) {
1118
+ return;
1119
+ }
1120
+ const reason = verdict.reason ?? "Hook blocked by governance";
1121
+ const abortReason = Verdict.requiresApproval(verdict.verdict) ? `${APPROVAL_ABORT_PREFIX}${reason}` : reason;
1122
+ hookGovernance.spanProcessor.setActivityAbort(
1123
+ activityContext.workflowId,
1124
+ activityContext.activityId,
1125
+ abortReason
1126
+ );
1127
+ if (Verdict.requiresApproval(verdict.verdict)) {
1128
+ throw new ApprovalPendingError(reason);
1129
+ }
1130
+ if (verdict.verdict === Verdict.HALT) {
1131
+ hookGovernance.spanProcessor.setHaltRequested(
1132
+ activityContext.workflowId,
1133
+ activityContext.activityId,
1134
+ reason
1135
+ );
1136
+ }
1137
+ throw new GovernanceHaltError(`Governance blocked: ${reason}`);
1138
+ }
1139
+ function resolveHookActivityType(parentActivityType, hookType) {
1140
+ if (typeof parentActivityType === "string" && parentActivityType.toLowerCase() === "agentllmcompletion") {
1141
+ return parentActivityType;
1142
+ }
1143
+ return hookType;
1144
+ }
1145
+ function cloneHookSpanPayload(span) {
1146
+ try {
1147
+ return structuredClone(span);
1148
+ } catch {
1149
+ return { ...span };
1150
+ }
1151
+ }
1152
+ function ensureStartedHookSpan(span) {
1153
+ const startedSpan = cloneHookSpanPayload(span);
1154
+ startedSpan.stage = "started";
1155
+ delete startedSpan.end_time;
1156
+ delete startedSpan.duration_ns;
1157
+ delete startedSpan.response_body;
1158
+ delete startedSpan.response_headers;
1159
+ delete startedSpan.http_status_code;
1160
+ delete startedSpan.rowcount;
1161
+ delete startedSpan.data;
1162
+ delete startedSpan.bytes_read;
1163
+ delete startedSpan.bytes_written;
1164
+ delete startedSpan.lines_count;
1165
+ delete startedSpan.result;
1166
+ delete startedSpan.error;
1167
+ return enrichHookSpanForData(startedSpan);
1168
+ }
1169
+ function ensureCompletedHookSpan(span) {
1170
+ const completedSpan = cloneHookSpanPayload(span);
1171
+ completedSpan.stage = "completed";
1172
+ return enrichHookSpanForData(completedSpan);
1173
+ }
1174
+ function enrichHookSpanForData(span) {
1175
+ if (span.data !== void 0) {
1176
+ return span;
1177
+ }
1178
+ const hookType = toStringValue(span.hook_type);
1179
+ if (!hookType) {
1180
+ return span;
1181
+ }
1182
+ if (hookType === "http_request") {
1183
+ const data = {};
1184
+ const method = toStringValue(span.http_method);
1185
+ const url = toStringValue(span.http_url);
1186
+ const requestBody = toStringValue(span.request_body);
1187
+ const responseBody = toStringValue(span.response_body);
1188
+ const statusCode = toNumberValue(span.http_status_code);
1189
+ if (method) {
1190
+ data.method = method;
1191
+ }
1192
+ if (url) {
1193
+ data.url = url;
1194
+ }
1195
+ if (requestBody !== void 0) {
1196
+ data.request_body = requestBody;
1197
+ }
1198
+ if (responseBody !== void 0) {
1199
+ data.response_body = responseBody;
1200
+ }
1201
+ if (statusCode !== void 0) {
1202
+ data.status_code = statusCode;
1203
+ }
1204
+ if (Object.keys(data).length > 0) {
1205
+ span.data = data;
1206
+ }
1207
+ return span;
1208
+ }
1209
+ if (hookType === "db_query") {
1210
+ const data = {};
1211
+ const dbSystem = toStringValue(span.db_system);
1212
+ const dbName = toStringValue(span.db_name);
1213
+ const dbOperation = toStringValue(span.db_operation);
1214
+ const dbStatement = toStringValue(span.db_statement);
1215
+ const rowcount = toNumberValue(span.rowcount);
1216
+ const serverAddress = toStringValue(span.server_address);
1217
+ const serverPort = toNumberValue(span.server_port);
1218
+ if (dbSystem) {
1219
+ data.db_system = dbSystem;
1220
+ }
1221
+ if (dbName) {
1222
+ data.db_name = dbName;
1223
+ }
1224
+ if (dbOperation) {
1225
+ data.db_operation = dbOperation;
1226
+ }
1227
+ if (dbStatement) {
1228
+ data.db_statement = dbStatement;
1229
+ }
1230
+ if (rowcount !== void 0) {
1231
+ data.rowcount = rowcount;
1232
+ }
1233
+ if (serverAddress) {
1234
+ data.server_address = serverAddress;
1235
+ }
1236
+ if (serverPort !== void 0) {
1237
+ data.server_port = serverPort;
1238
+ }
1239
+ if (Object.keys(data).length > 0) {
1240
+ span.data = data;
1241
+ }
1242
+ return span;
1243
+ }
1244
+ if (hookType === "function_call") {
1245
+ const data = {};
1246
+ const functionName = toStringValue(span.function);
1247
+ const module = toStringValue(span.module);
1248
+ if (functionName) {
1249
+ data.function = functionName;
1250
+ }
1251
+ if (module) {
1252
+ data.module = module;
1253
+ }
1254
+ if (span.args !== void 0) {
1255
+ data.args = span.args;
1256
+ }
1257
+ if (span.result !== void 0) {
1258
+ data.result = span.result;
1259
+ }
1260
+ if (Object.keys(data).length > 0) {
1261
+ span.data = data;
1262
+ }
1263
+ return span;
1264
+ }
1265
+ if (hookType === "file_operation") {
1266
+ const data = {};
1267
+ const filePath = toStringValue(span.file_path);
1268
+ const fileMode = toStringValue(span.file_mode);
1269
+ const fileOperation = toStringValue(span.file_operation);
1270
+ const bytesRead = toNumberValue(span.bytes_read);
1271
+ const bytesWritten = toNumberValue(span.bytes_written);
1272
+ const linesCount = toNumberValue(span.lines_count);
1273
+ if (filePath) {
1274
+ data.file_path = filePath;
1275
+ }
1276
+ if (fileMode) {
1277
+ data.file_mode = fileMode;
1278
+ }
1279
+ if (fileOperation) {
1280
+ data.file_operation = fileOperation;
1281
+ }
1282
+ if (bytesRead !== void 0) {
1283
+ data.bytes_read = bytesRead;
1284
+ }
1285
+ if (bytesWritten !== void 0) {
1286
+ data.bytes_written = bytesWritten;
1287
+ }
1288
+ if (linesCount !== void 0) {
1289
+ data.lines_count = linesCount;
1290
+ }
1291
+ if (Object.keys(data).length > 0) {
1292
+ span.data = data;
1293
+ }
1294
+ }
1295
+ return span;
1296
+ }
1297
+ function extractModelUsageFromHookSpan(span) {
1298
+ const requestBody = toStringValue(span.request_body ?? span.requestBody);
1299
+ const responseBody = toStringValue(span.response_body ?? span.responseBody);
1300
+ const requestRecords = parseHookBodyRecords(requestBody);
1301
+ const responseRecords = parseHookBodyRecords(responseBody);
1302
+ const modelFromResponse = extractModelFromRecords(responseRecords);
1303
+ const modelFromRequest = extractModelFromRecords(requestRecords);
1304
+ const modelId = modelFromResponse ?? modelFromRequest;
1305
+ const usageFromResponse = extractUsageFromRecords(responseRecords);
1306
+ const attributes = span.attributes && typeof span.attributes === "object" ? span.attributes : void 0;
1307
+ const providerFromRecords = extractProviderFromRecords(responseRecords) ?? extractProviderFromRecords(requestRecords);
1308
+ const providerFromUrl = inferProviderFromUrl(
1309
+ toStringValue(attributes?.["http.url"] ?? attributes?.["url.full"])
1310
+ );
1311
+ const providerFromModel = inferProviderFromModelId(modelId);
1312
+ const provider = providerFromRecords ?? providerFromUrl ?? providerFromModel;
1313
+ return {
1314
+ ...modelId ? { modelId } : {},
1315
+ ...provider ? { provider } : {},
1316
+ ...usageFromResponse?.inputTokens !== void 0 ? { inputTokens: usageFromResponse.inputTokens } : {},
1317
+ ...usageFromResponse?.outputTokens !== void 0 ? { outputTokens: usageFromResponse.outputTokens } : {},
1318
+ ...usageFromResponse?.totalTokens !== void 0 ? { totalTokens: usageFromResponse.totalTokens } : {}
1319
+ };
1320
+ }
1321
+ function parseHookBodyRecords(body) {
1322
+ if (!body) {
1323
+ return [];
1324
+ }
1325
+ const serializedRecords = /* @__PURE__ */ new Set();
1326
+ const records = [];
1327
+ const pushRecord = (record) => {
1328
+ if (!record) {
1329
+ return;
1330
+ }
1331
+ const serialized = JSON.stringify(record);
1332
+ if (serializedRecords.has(serialized)) {
1333
+ return;
1334
+ }
1335
+ serializedRecords.add(serialized);
1336
+ records.push(record);
1337
+ };
1338
+ const direct = parseJsonRecord(body);
1339
+ pushRecord(direct);
1340
+ for (const eventBody of parseSseDataBodies(body)) {
1341
+ pushRecord(parseJsonRecord(eventBody));
1342
+ }
1343
+ for (const eventBody of parseInlineSseDataBodies(body)) {
1344
+ pushRecord(parseJsonRecord(eventBody));
1345
+ }
1346
+ return records;
1347
+ }
1348
+ function deriveAgentHookActivityPayload(hookTrigger, stage) {
1349
+ const hookType = toStringValue(hookTrigger.type);
1350
+ if (hookType === "http_request") {
1351
+ const requestRecords = parseHookBodyRecords(
1352
+ toStringValue(hookTrigger.request_body)
1353
+ );
1354
+ const responseRecords = parseHookBodyRecords(
1355
+ toStringValue(hookTrigger.response_body)
1356
+ );
1357
+ const activityInput = normalizeActivityInputList(
1358
+ compactHookPayloadValue(
1359
+ deriveAgentRequestSummaryFromRecords(requestRecords) ?? parseHookPayloadBodyValue(hookTrigger.request_body)
1360
+ )
1361
+ );
1362
+ const activityOutput = stage === "completed" ? compactHookPayloadValue(
1363
+ deriveAgentResponseSummaryFromRecords(responseRecords) ?? parseHookPayloadBodyValue(hookTrigger.response_body)
1364
+ ) : void 0;
1365
+ return {
1366
+ ...activityInput !== void 0 ? { activityInput } : {},
1367
+ ...activityOutput !== void 0 ? { activityOutput } : {}
1368
+ };
1369
+ }
1370
+ if (hookType === "function_call") {
1371
+ const activityInput = normalizeActivityInputList(
1372
+ compactHookPayloadValue(sanitizeForGovernancePayload(hookTrigger.args))
1373
+ );
1374
+ const activityOutput = stage === "completed" ? compactHookPayloadValue(
1375
+ sanitizeForGovernancePayload(hookTrigger.result)
1376
+ ) : void 0;
1377
+ return {
1378
+ ...activityInput !== void 0 ? { activityInput } : {},
1379
+ ...activityOutput !== void 0 ? { activityOutput } : {}
1380
+ };
1381
+ }
1382
+ return {};
1383
+ }
1384
+ function parseHookPayloadBodyValue(body) {
1385
+ if (body === void 0 || body === null) {
1386
+ return void 0;
1387
+ }
1388
+ if (typeof body !== "string") {
1389
+ return sanitizeForGovernancePayload(body);
1390
+ }
1391
+ const trimmed = body.trim();
1392
+ if (trimmed.length === 0) {
1393
+ return void 0;
1394
+ }
1395
+ try {
1396
+ return sanitizeForGovernancePayload(JSON.parse(trimmed));
1397
+ } catch {
1398
+ return trimmed;
1399
+ }
1400
+ }
1401
+ function compactHookPayloadValue(value, maxBytes = 16384) {
1402
+ if (value === void 0 || value === null) {
1403
+ return void 0;
1404
+ }
1405
+ if (typeof value === "string") {
1406
+ const trimmed = value.trim();
1407
+ return trimmed.length > 8e3 ? `${trimmed.slice(0, 7984)}...[truncated]` : trimmed;
1408
+ }
1409
+ const serialized = JSON.stringify(value);
1410
+ const sizeBytes = Buffer.byteLength(serialized, "utf8");
1411
+ if (sizeBytes <= maxBytes) {
1412
+ return value;
1413
+ }
1414
+ return {
1415
+ preview: `${serialized.slice(0, 3984)}...[truncated]`,
1416
+ truncated: true
1417
+ };
1418
+ }
1419
+ function normalizeActivityInputList(value) {
1420
+ if (value === void 0 || value === null) {
1421
+ return void 0;
1422
+ }
1423
+ if (Array.isArray(value)) {
1424
+ return value;
1425
+ }
1426
+ return [value];
1427
+ }
1428
+ function appendGoalToHookActivityInput(activityInput, goal) {
1429
+ const trimmedGoal = goal.trim();
1430
+ if (trimmedGoal.length === 0) {
1431
+ if (Array.isArray(activityInput)) {
1432
+ return activityInput;
1433
+ }
1434
+ if (activityInput === void 0 || activityInput === null) {
1435
+ return [];
1436
+ }
1437
+ return [activityInput];
1438
+ }
1439
+ if (Array.isArray(activityInput)) {
1440
+ const inputItems = activityInput;
1441
+ if (inputItems.length === 0) {
1442
+ return [{ goal: trimmedGoal }];
1443
+ }
1444
+ const [first, ...rest] = inputItems;
1445
+ if (first && typeof first === "object" && !Array.isArray(first)) {
1446
+ const firstRecord = first;
1447
+ const existingGoal = firstRecord.goal;
1448
+ if (typeof existingGoal === "string" && existingGoal.trim().length > 0) {
1449
+ return inputItems;
1450
+ }
1451
+ return [{ ...firstRecord, goal: trimmedGoal }, ...rest];
1452
+ }
1453
+ return [...inputItems, { goal: trimmedGoal }];
1454
+ }
1455
+ if (activityInput === void 0 || activityInput === null) {
1456
+ return [{ goal: trimmedGoal }];
1457
+ }
1458
+ if (activityInput && typeof activityInput === "object" && !Array.isArray(activityInput)) {
1459
+ const activityRecord = activityInput;
1460
+ const existingGoal = activityRecord.goal;
1461
+ if (typeof existingGoal === "string" && existingGoal.trim().length > 0) {
1462
+ return [activityRecord];
1463
+ }
1464
+ return [{ ...activityRecord, goal: trimmedGoal }];
1465
+ }
1466
+ return [activityInput, { goal: trimmedGoal }];
1467
+ }
1468
+ function parseInlineSseDataBodies(body) {
1469
+ const payloads = [];
1470
+ let searchIndex = 0;
1471
+ while (searchIndex < body.length) {
1472
+ const dataIndex = body.indexOf("data:", searchIndex);
1473
+ if (dataIndex < 0) {
1474
+ break;
1475
+ }
1476
+ const jsonStart = body.indexOf("{", dataIndex + 5);
1477
+ if (jsonStart < 0) {
1478
+ searchIndex = dataIndex + 5;
1479
+ continue;
1480
+ }
1481
+ const jsonEnd = findJsonObjectEnd(body, jsonStart);
1482
+ if (jsonEnd < 0) {
1483
+ searchIndex = dataIndex + 5;
1484
+ continue;
1485
+ }
1486
+ payloads.push(body.slice(jsonStart, jsonEnd + 1));
1487
+ searchIndex = jsonEnd + 1;
1488
+ }
1489
+ return payloads;
1490
+ }
1491
+ function findJsonObjectEnd(source, startIndex) {
1492
+ let depth = 0;
1493
+ let inString = false;
1494
+ let escaped = false;
1495
+ for (let index = startIndex; index < source.length; index += 1) {
1496
+ const char = source[index];
1497
+ if (!char) {
1498
+ continue;
1499
+ }
1500
+ if (escaped) {
1501
+ escaped = false;
1502
+ continue;
1503
+ }
1504
+ if (char === "\\") {
1505
+ escaped = true;
1506
+ continue;
1507
+ }
1508
+ if (char === '"') {
1509
+ inString = !inString;
1510
+ continue;
1511
+ }
1512
+ if (inString) {
1513
+ continue;
1514
+ }
1515
+ if (char === "{") {
1516
+ depth += 1;
1517
+ continue;
1518
+ }
1519
+ if (char === "}") {
1520
+ depth -= 1;
1521
+ if (depth === 0) {
1522
+ return index;
1523
+ }
1524
+ }
1525
+ }
1526
+ return -1;
1527
+ }
1528
+ function deriveAgentRequestSummaryFromRecords(records) {
1529
+ const modelId = extractModelFromRecords(records);
1530
+ const telemetryModelId = modelId ? toTelemetryModelId(modelId) : void 0;
1531
+ const prompt = extractLatestUserPromptFromRecords(records);
1532
+ const toolCount = extractToolCountFromRecords(records);
1533
+ const summary = {
1534
+ ...telemetryModelId ? { model: telemetryModelId } : {},
1535
+ ...modelId && modelId !== telemetryModelId ? { model_id: modelId } : {},
1536
+ ...prompt ? { prompt } : {},
1537
+ ...typeof toolCount === "number" ? { tools_count: toolCount } : {}
1538
+ };
1539
+ return Object.keys(summary).length > 0 ? summary : void 0;
1540
+ }
1541
+ function deriveAgentResponseSummaryFromRecords(records) {
1542
+ const modelId = extractModelFromRecords(records);
1543
+ const telemetryModelId = modelId ? toTelemetryModelId(modelId) : void 0;
1544
+ const usage = extractUsageFromRecords(records);
1545
+ const text = extractResponseTextFromRecords(records);
1546
+ const toolNames = extractToolCallNamesFromRecords(records);
1547
+ const summary = {
1548
+ ...telemetryModelId ? { model: telemetryModelId } : {},
1549
+ ...modelId && modelId !== telemetryModelId ? { model_id: modelId } : {},
1550
+ ...text ? { text } : {},
1551
+ ...usage ? {
1552
+ usage: {
1553
+ ...typeof usage.inputTokens === "number" ? { input_tokens: usage.inputTokens } : {},
1554
+ ...typeof usage.outputTokens === "number" ? { output_tokens: usage.outputTokens } : {},
1555
+ ...typeof usage.totalTokens === "number" ? { total_tokens: usage.totalTokens } : {}
1556
+ }
1557
+ } : {},
1558
+ ...toolNames.length > 0 ? {
1559
+ tool_calls: toolNames,
1560
+ tool_call_count: toolNames.length
1561
+ } : {}
1562
+ };
1563
+ if (summary.usage && Object.keys(summary.usage).length === 0) {
1564
+ delete summary.usage;
1565
+ }
1566
+ return Object.keys(summary).length > 0 ? summary : void 0;
1567
+ }
1568
+ function extractLatestUserPromptFromRecords(records) {
1569
+ for (let index = records.length - 1; index >= 0; index -= 1) {
1570
+ const record = records[index];
1571
+ if (!record) {
1572
+ continue;
1573
+ }
1574
+ const prompt = extractLatestUserPromptFromInput(record.input) ?? extractLatestUserPromptFromInput(record.messages) ?? extractLatestUserPromptFromInput(record.prompt);
1575
+ if (prompt) {
1576
+ return truncateText(prompt, 1e3);
1577
+ }
1578
+ }
1579
+ return void 0;
1580
+ }
1581
+ function extractLatestUserPromptFromInput(value) {
1582
+ const inputs = Array.isArray(value) ? value : value !== void 0 ? [value] : [];
1583
+ for (let index = inputs.length - 1; index >= 0; index -= 1) {
1584
+ const entry = inputs[index];
1585
+ if (typeof entry === "string") {
1586
+ const trimmed = entry.trim();
1587
+ if (trimmed.length > 0) {
1588
+ return trimmed;
1589
+ }
1590
+ continue;
1591
+ }
1592
+ if (!entry || typeof entry !== "object") {
1593
+ continue;
1594
+ }
1595
+ const record = entry;
1596
+ const role = toStringValue(record.role)?.toLowerCase();
1597
+ if (role && role !== "user") {
1598
+ continue;
1599
+ }
1600
+ const text = extractTextFromStructuredValue(record.content) ?? extractTextFromStructuredValue(record.input_text) ?? extractTextFromStructuredValue(record.text);
1601
+ if (text) {
1602
+ return text;
1603
+ }
1604
+ }
1605
+ return void 0;
1606
+ }
1607
+ function extractTextFromStructuredValue(value) {
1608
+ if (typeof value === "string") {
1609
+ const trimmed = value.trim();
1610
+ if (trimmed.length === 0) {
1611
+ return void 0;
1612
+ }
1613
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
1614
+ try {
1615
+ const parsed = JSON.parse(trimmed);
1616
+ const extracted = extractTextFromStructuredValue(parsed);
1617
+ if (extracted && extracted.trim().length > 0) {
1618
+ return extracted.trim();
1619
+ }
1620
+ } catch {
1621
+ }
1622
+ }
1623
+ return trimmed;
1624
+ }
1625
+ if (Array.isArray(value)) {
1626
+ const parts = value.map((item) => extractTextFromStructuredValue(item)).filter((item) => Boolean(item && item.trim().length > 0));
1627
+ if (parts.length === 0) {
1628
+ return void 0;
1629
+ }
1630
+ const combined = parts.join("\n").trim();
1631
+ return combined.length > 0 ? combined : void 0;
1632
+ }
1633
+ if (!value || typeof value !== "object") {
1634
+ return void 0;
1635
+ }
1636
+ const record = value;
1637
+ const type = toStringValue(record.type)?.toLowerCase();
1638
+ const text = extractTextFromStructuredValue(record.text) ?? extractTextFromStructuredValue(record.input_text) ?? extractTextFromStructuredValue(record.output_text) ?? extractTextFromStructuredValue(record.content);
1639
+ if (!text) {
1640
+ return void 0;
1641
+ }
1642
+ if (!type || type.includes("text") || type === "message") {
1643
+ return text;
1644
+ }
1645
+ return text;
1646
+ }
1647
+ function extractToolCountFromRecords(records) {
1648
+ for (let index = records.length - 1; index >= 0; index -= 1) {
1649
+ const tools = records[index]?.tools;
1650
+ if (Array.isArray(tools)) {
1651
+ return tools.length;
1652
+ }
1653
+ }
1654
+ return void 0;
1655
+ }
1656
+ function extractResponseTextFromRecords(records) {
1657
+ let deltaText = "";
1658
+ let doneText;
1659
+ let completedText;
1660
+ for (const record of records) {
1661
+ const type = toStringValue(record.type);
1662
+ if (type === "response.output_text.delta") {
1663
+ const delta = toStringValue(record.delta);
1664
+ if (delta) {
1665
+ deltaText += delta;
1666
+ }
1667
+ continue;
1668
+ }
1669
+ if (type === "response.output_text.done") {
1670
+ const done = toStringValue(record.text);
1671
+ if (done) {
1672
+ doneText = done;
1673
+ }
1674
+ continue;
1675
+ }
1676
+ if (type === "response.completed") {
1677
+ const response = record.response && typeof record.response === "object" ? record.response : void 0;
1678
+ const responseText = extractTextFromStructuredValue(response?.output_text) ?? extractTextFromStructuredValue(response?.output) ?? extractTextFromStructuredValue(response?.text);
1679
+ if (responseText) {
1680
+ completedText = responseText;
1681
+ }
1682
+ }
1683
+ }
1684
+ const resolved = completedText ?? doneText ?? (deltaText.trim().length > 0 ? deltaText : void 0);
1685
+ return resolved ? truncateText(resolved, 2e3) : void 0;
1686
+ }
1687
+ function extractToolCallNamesFromRecords(records) {
1688
+ const names = /* @__PURE__ */ new Set();
1689
+ for (const record of records) {
1690
+ const type = toStringValue(record.type);
1691
+ if (type === "response.output_item.added") {
1692
+ const item = record.item && typeof record.item === "object" ? record.item : void 0;
1693
+ const itemType = toStringValue(item?.type);
1694
+ const itemName = toStringValue(item?.name);
1695
+ if (itemType === "function_call" && itemName) {
1696
+ names.add(itemName);
1697
+ }
1698
+ }
1699
+ if (type === "response.completed") {
1700
+ const response = record.response && typeof record.response === "object" ? record.response : void 0;
1701
+ const output = Array.isArray(response?.output) ? response.output : [];
1702
+ for (const outputItem of output) {
1703
+ if (!outputItem || typeof outputItem !== "object") {
1704
+ continue;
1705
+ }
1706
+ const outputRecord = outputItem;
1707
+ const itemType = toStringValue(outputRecord.type);
1708
+ const itemName = toStringValue(outputRecord.name);
1709
+ if (itemType === "function_call" && itemName) {
1710
+ names.add(itemName);
1711
+ }
1712
+ }
1713
+ }
1714
+ }
1715
+ return [...names].slice(0, 8);
1716
+ }
1717
+ function truncateText(value, maxChars) {
1718
+ if (value.length <= maxChars) {
1719
+ return value;
1720
+ }
1721
+ return `${value.slice(0, Math.max(0, maxChars - 16))}...[truncated]`;
1722
+ }
1723
+ function normalizeHookBodyForTelemetry(body) {
1724
+ if (!body) {
1725
+ return body;
1726
+ }
1727
+ const record = parseJsonRecord(body);
1728
+ if (!record) {
1729
+ return body;
1730
+ }
1731
+ let changed = false;
1732
+ if (normalizeModelIdentifierInRecord(record)) {
1733
+ changed = true;
1734
+ }
1735
+ const nestedResponse = record.response && typeof record.response === "object" && !Array.isArray(record.response) ? record.response : void 0;
1736
+ if (nestedResponse && normalizeModelIdentifierInRecord(nestedResponse)) {
1737
+ changed = true;
1738
+ }
1739
+ if (!changed) {
1740
+ return body;
1741
+ }
1742
+ return JSON.stringify(record);
1743
+ }
1744
+ function normalizeModelIdentifierInRecord(record) {
1745
+ const modelValue = typeof record.model === "string" ? record.model.trim() : void 0;
1746
+ if (!modelValue) {
1747
+ return false;
1748
+ }
1749
+ const parsedModel = parseModelIdentifier(modelValue);
1750
+ const rawModelId = parsedModel.modelId ?? modelValue;
1751
+ const telemetryModelId = toTelemetryModelId(rawModelId) ?? rawModelId;
1752
+ let changed = false;
1753
+ if (record.model !== telemetryModelId) {
1754
+ record.model = telemetryModelId;
1755
+ changed = true;
1756
+ }
1757
+ if (rawModelId !== telemetryModelId && (typeof record.model_id !== "string" || record.model_id.trim().length === 0)) {
1758
+ record.model_id = rawModelId;
1759
+ changed = true;
1760
+ }
1761
+ if (parsedModel.provider) {
1762
+ if (typeof record.model_provider !== "string" || record.model_provider.trim().length === 0) {
1763
+ record.model_provider = parsedModel.provider;
1764
+ changed = true;
1765
+ }
1766
+ if (typeof record.provider !== "string" || record.provider.trim().length === 0) {
1767
+ record.provider = parsedModel.provider;
1768
+ changed = true;
1769
+ }
1770
+ }
1771
+ return changed;
1772
+ }
1773
+ function parseJsonRecord(raw) {
1774
+ try {
1775
+ const parsed = JSON.parse(raw);
1776
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1777
+ return void 0;
1778
+ }
1779
+ return parsed;
1780
+ } catch {
1781
+ return void 0;
1782
+ }
1783
+ }
1784
+ function parseSseDataBodies(body) {
1785
+ const lines = body.split(/\r?\n/);
1786
+ const payloads = [];
1787
+ let currentDataLines = [];
1788
+ for (const line of lines) {
1789
+ const trimmed = line.trim();
1790
+ if (trimmed.length === 0) {
1791
+ if (currentDataLines.length > 0) {
1792
+ payloads.push(currentDataLines.join("\n"));
1793
+ currentDataLines = [];
1794
+ }
1795
+ continue;
1796
+ }
1797
+ if (!trimmed.startsWith("data:")) {
1798
+ continue;
1799
+ }
1800
+ const data = trimmed.slice(5).trimStart();
1801
+ if (data.length > 0) {
1802
+ currentDataLines.push(data);
1803
+ }
1804
+ }
1805
+ if (currentDataLines.length > 0) {
1806
+ payloads.push(currentDataLines.join("\n"));
1807
+ }
1808
+ return payloads.filter((payload) => payload !== "[DONE]");
1809
+ }
1810
+ function extractModelFromRecords(records) {
1811
+ for (const record of records) {
1812
+ const nestedResponse = record.response && typeof record.response === "object" ? record.response : void 0;
1813
+ const candidates = [
1814
+ record.model_id,
1815
+ nestedResponse?.model_id,
1816
+ record.model,
1817
+ nestedResponse?.model
1818
+ ];
1819
+ for (const candidate of candidates) {
1820
+ if (typeof candidate !== "string" || candidate.trim().length === 0) {
1821
+ continue;
1822
+ }
1823
+ const parsed = parseModelIdentifier(candidate);
1824
+ if (parsed.modelId) {
1825
+ return parsed.modelId;
1826
+ }
1827
+ }
1828
+ }
1829
+ return void 0;
1830
+ }
1831
+ function extractProviderFromRecords(records) {
1832
+ for (const record of records) {
1833
+ const nestedResponse = record.response && typeof record.response === "object" ? record.response : void 0;
1834
+ const candidates = [
1835
+ record.provider,
1836
+ record.model_provider,
1837
+ nestedResponse?.provider,
1838
+ nestedResponse?.model_provider,
1839
+ record.model,
1840
+ nestedResponse?.model
1841
+ ];
1842
+ for (const candidate of candidates) {
1843
+ if (typeof candidate !== "string" || candidate.trim().length === 0) {
1844
+ continue;
1845
+ }
1846
+ const parsed = parseModelIdentifier(candidate);
1847
+ if (parsed.provider) {
1848
+ return parsed.provider;
1849
+ }
1850
+ const normalized = normalizeProvider(candidate);
1851
+ if (normalized) {
1852
+ return normalized;
1853
+ }
1854
+ }
1855
+ }
1856
+ return void 0;
1857
+ }
1858
+ function extractUsageFromRecords(records) {
1859
+ let inputTokens;
1860
+ let outputTokens;
1861
+ let totalTokens;
1862
+ for (const record of records) {
1863
+ const usage = extractUsageFromRecord(record);
1864
+ if (!usage) {
1865
+ continue;
1866
+ }
1867
+ if (inputTokens === void 0 && usage.inputTokens !== void 0) {
1868
+ inputTokens = usage.inputTokens;
1869
+ }
1870
+ if (outputTokens === void 0 && usage.outputTokens !== void 0) {
1871
+ outputTokens = usage.outputTokens;
1872
+ }
1873
+ if (totalTokens === void 0 && usage.totalTokens !== void 0) {
1874
+ totalTokens = usage.totalTokens;
1875
+ }
1876
+ }
1877
+ if (inputTokens === void 0 && outputTokens === void 0 && totalTokens === void 0) {
1878
+ return void 0;
1879
+ }
1880
+ const resolvedTotalTokens = totalTokens ?? (inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0);
1881
+ return {
1882
+ ...inputTokens !== void 0 ? { inputTokens } : {},
1883
+ ...outputTokens !== void 0 ? { outputTokens } : {},
1884
+ ...resolvedTotalTokens !== void 0 ? { totalTokens: resolvedTotalTokens } : {}
1885
+ };
1886
+ }
1887
+ function extractUsageFromRecord(record) {
1888
+ const nestedResponse = record.response && typeof record.response === "object" ? record.response : void 0;
1889
+ const candidates = [
1890
+ record.usage,
1891
+ nestedResponse?.usage,
1892
+ record,
1893
+ nestedResponse
1894
+ ];
1895
+ for (const candidate of candidates) {
1896
+ const usage = parseUsageCandidate(candidate);
1897
+ if (usage) {
1898
+ return usage;
1899
+ }
1900
+ }
1901
+ return void 0;
1902
+ }
1903
+ function parseUsageCandidate(candidate) {
1904
+ if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
1905
+ return void 0;
1906
+ }
1907
+ const record = candidate;
1908
+ const inputTokens = toNumberValue(record.input_tokens) ?? toNumberValue(record.prompt_tokens) ?? toNumberValue(record.inputTokens) ?? toNumberValue(record.promptTokens);
1909
+ const outputTokens = toNumberValue(record.output_tokens) ?? toNumberValue(record.completion_tokens) ?? toNumberValue(record.outputTokens) ?? toNumberValue(record.completionTokens);
1910
+ const totalTokens = toNumberValue(record.total_tokens) ?? toNumberValue(record.totalTokens);
1911
+ if (inputTokens === void 0 && outputTokens === void 0 && totalTokens === void 0) {
1912
+ return void 0;
1913
+ }
1914
+ const resolvedTotalTokens = totalTokens ?? (inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0);
1915
+ return {
1916
+ ...inputTokens !== void 0 ? { inputTokens } : {},
1917
+ ...outputTokens !== void 0 ? { outputTokens } : {},
1918
+ ...resolvedTotalTokens !== void 0 ? { totalTokens: resolvedTotalTokens } : {}
1919
+ };
1920
+ }
1921
+ function parseModelIdentifier(value) {
1922
+ const trimmed = value.trim();
1923
+ if (!trimmed) {
1924
+ return {};
1925
+ }
1926
+ const slashParts = trimmed.split("/");
1927
+ if (slashParts.length >= 2) {
1928
+ const possibleProvider = slashParts[0]?.trim();
1929
+ const modelPart = slashParts.slice(1).join("/").trim();
1930
+ if (possibleProvider && modelPart) {
1931
+ const provider = normalizeProvider(possibleProvider);
1932
+ if (provider) {
1933
+ return {
1934
+ modelId: modelPart,
1935
+ provider
1936
+ };
1937
+ }
1938
+ }
1939
+ }
1940
+ return {
1941
+ modelId: trimmed
1942
+ };
1943
+ }
1944
+ function normalizeProvider(candidate) {
1945
+ const normalized = candidate.trim().toLowerCase();
1946
+ if (normalized.includes("openai")) {
1947
+ return "openai";
1948
+ }
1949
+ if (normalized.includes("anthropic")) {
1950
+ return "anthropic";
1951
+ }
1952
+ if (normalized.includes("google") || normalized.includes("gemini")) {
1953
+ return "google";
1954
+ }
1955
+ return void 0;
1956
+ }
1957
+ function toTelemetryModelId(modelId) {
1958
+ if (typeof modelId !== "string") {
1959
+ return void 0;
1960
+ }
1961
+ const trimmed = modelId.trim();
1962
+ if (trimmed.length === 0) {
1963
+ return void 0;
1964
+ }
1965
+ const sanitized = trimmed.replace(/[.:/\\\s]+/g, "-").replace(/[^A-Za-z0-9_-]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
1966
+ return sanitized.length > 0 ? sanitized : trimmed;
1967
+ }
1968
+ function inferProviderFromUrl(url) {
1969
+ if (!url) {
1970
+ return void 0;
1971
+ }
1972
+ const normalized = url.toLowerCase();
1973
+ if (normalized.includes("api.openai.com")) {
1974
+ return "openai";
1975
+ }
1976
+ if (normalized.includes("api.anthropic.com")) {
1977
+ return "anthropic";
1978
+ }
1979
+ if (normalized.includes("generativelanguage.googleapis.com")) {
1980
+ return "google";
1981
+ }
1982
+ return void 0;
1983
+ }
1984
+ function inferProviderFromModelId(modelId) {
1985
+ if (!modelId) {
1986
+ return void 0;
1987
+ }
1988
+ const normalized = modelId.toLowerCase();
1989
+ if (normalized.startsWith("gpt-") || normalized.startsWith("o1") || normalized.startsWith("o3")) {
1990
+ return "openai";
1991
+ }
1992
+ if (normalized.startsWith("claude-")) {
1993
+ return "anthropic";
1994
+ }
1995
+ if (normalized.startsWith("gemini")) {
1996
+ return "google";
1997
+ }
1998
+ return void 0;
1999
+ }
2000
+ function resolveActivityContext(spanProcessor, traceId) {
2001
+ const executionContext = getOpenBoxExecutionContext();
2002
+ if (executionContext?.activityId && executionContext.activityType && executionContext.workflowId && executionContext.workflowType && executionContext.runId) {
2003
+ const spanActivityContext = spanProcessor.getActivityContext(
2004
+ executionContext.workflowId,
2005
+ executionContext.activityId
2006
+ );
2007
+ const spanGoal2 = toStringValue(spanActivityContext?.goal);
2008
+ const resolvedGoal = spanGoal2 ?? executionContext.goal;
2009
+ return {
2010
+ activityId: executionContext.activityId,
2011
+ ...spanActivityContext && Object.prototype.hasOwnProperty.call(spanActivityContext, "activity_input") ? {
2012
+ activityInput: spanActivityContext.activity_input
2013
+ } : {},
2014
+ activityType: executionContext.activityType,
2015
+ ...typeof resolvedGoal === "string" && resolvedGoal.length > 0 ? {
2016
+ goal: resolvedGoal
2017
+ } : {},
2018
+ runId: executionContext.runId,
2019
+ taskQueue: executionContext.taskQueue ?? "mastra",
2020
+ workflowId: executionContext.workflowId,
2021
+ workflowType: executionContext.workflowType,
2022
+ ...typeof executionContext.attempt === "number" ? { attempt: executionContext.attempt } : {}
2023
+ };
2024
+ }
2025
+ if (executionContext?.source === "agent" && executionContext.workflowId && executionContext.workflowType && executionContext.runId) {
2026
+ return {
2027
+ activityId: `${executionContext.workflowId}::agent-llm::${executionContext.runId}`,
2028
+ activityType: "agentLlmCompletion",
2029
+ ...executionContext.goal ? { goal: executionContext.goal } : {},
2030
+ runId: executionContext.runId,
2031
+ syntheticAgentActivity: true,
2032
+ taskQueue: executionContext.taskQueue ?? "mastra",
2033
+ workflowId: executionContext.workflowId,
2034
+ workflowType: executionContext.workflowType,
2035
+ ...typeof executionContext.attempt === "number" ? { attempt: executionContext.attempt } : {}
2036
+ };
2037
+ }
2038
+ const spanContext = spanProcessor.getActivityContextByTrace(traceId);
2039
+ if (!spanContext) {
2040
+ return void 0;
2041
+ }
2042
+ const activityId = toStringValue(spanContext.activity_id);
2043
+ const activityType = toStringValue(spanContext.activity_type);
2044
+ const workflowId = toStringValue(spanContext.workflow_id);
2045
+ const workflowType = toStringValue(spanContext.workflow_type);
2046
+ const runId = toStringValue(spanContext.run_id);
2047
+ if (!activityId || !activityType || !workflowId || !workflowType || !runId) {
2048
+ return void 0;
2049
+ }
2050
+ const spanGoal = toStringValue(spanContext.goal);
2051
+ return {
2052
+ activityId,
2053
+ activityInput: spanContext.activity_input,
2054
+ activityType,
2055
+ ...spanGoal ? { goal: spanGoal } : {},
2056
+ runId,
2057
+ taskQueue: toStringValue(spanContext.task_queue) ?? "mastra",
2058
+ workflowId,
2059
+ workflowType,
2060
+ ...typeof spanContext.attempt === "number" ? { attempt: spanContext.attempt } : {}
2061
+ };
2062
+ }
2063
+ function createHookSpan(input) {
2064
+ const span = {
2065
+ attributes: input.attributes,
2066
+ events: [],
2067
+ hook_type: input.hookType,
2068
+ kind: input.kind,
2069
+ name: input.name,
2070
+ semantic_type: input.semanticType,
2071
+ span_id: normalizeHexId(input.spanId, 16),
2072
+ stage: input.stage,
2073
+ start_time: input.startTimeNs,
2074
+ status: {
2075
+ code: input.error ? "ERROR" : "OK",
2076
+ ...input.error ? { description: input.error } : {}
2077
+ },
2078
+ trace_id: normalizeHexId(input.traceId, 32)
2079
+ };
2080
+ if (input.stage === "completed") {
2081
+ span.end_time = input.endTimeNs;
2082
+ span.duration_ns = Math.max(0, input.endTimeNs - input.startTimeNs);
2083
+ }
2084
+ if (input.parentSpanId !== void 0) {
2085
+ span.parent_span_id = normalizeHexId(input.parentSpanId, 16);
2086
+ }
2087
+ if (input.error !== void 0) {
2088
+ span.error = input.error;
2089
+ }
2090
+ if (input.requestBody !== void 0) {
2091
+ span.request_body = input.requestBody;
2092
+ }
2093
+ if (input.stage === "completed" && input.responseBody !== void 0) {
2094
+ span.response_body = input.responseBody;
2095
+ }
2096
+ if (input.requestHeaders !== void 0) {
2097
+ span.request_headers = input.requestHeaders;
2098
+ }
2099
+ if (input.stage === "completed" && input.responseHeaders !== void 0) {
2100
+ span.response_headers = input.responseHeaders;
2101
+ }
2102
+ if (input.hookType === "http_request") {
2103
+ if (input.httpMethod !== void 0) {
2104
+ span.http_method = input.httpMethod;
2105
+ }
2106
+ if (input.httpUrl !== void 0) {
2107
+ span.http_url = input.httpUrl;
2108
+ }
2109
+ if (input.stage === "completed" && input.httpStatusCode !== void 0) {
2110
+ span.http_status_code = input.httpStatusCode;
2111
+ }
2112
+ } else if (input.hookType === "db_query") {
2113
+ if (input.dbSystem !== void 0) {
2114
+ span.db_system = input.dbSystem;
2115
+ }
2116
+ if (input.dbName !== void 0) {
2117
+ span.db_name = input.dbName;
2118
+ }
2119
+ if (input.dbOperation !== void 0) {
2120
+ span.db_operation = input.dbOperation;
2121
+ }
2122
+ if (input.dbStatement !== void 0) {
2123
+ span.db_statement = input.dbStatement;
2124
+ }
2125
+ if (input.serverAddress !== void 0) {
2126
+ span.server_address = input.serverAddress;
2127
+ }
2128
+ if (input.serverPort !== void 0) {
2129
+ span.server_port = input.serverPort;
2130
+ }
2131
+ if (input.stage === "completed" && input.rowcount !== void 0) {
2132
+ span.rowcount = input.rowcount;
2133
+ }
2134
+ } else if (input.hookType === "file_operation") {
2135
+ if (input.filePath !== void 0) {
2136
+ span.file_path = input.filePath;
2137
+ }
2138
+ if (input.fileMode !== void 0) {
2139
+ span.file_mode = input.fileMode;
2140
+ }
2141
+ if (input.fileOperation !== void 0) {
2142
+ span.file_operation = input.fileOperation;
2143
+ }
2144
+ if (input.stage === "completed" && input.data !== void 0) {
2145
+ span.data = input.data;
2146
+ }
2147
+ if (input.stage === "completed" && input.bytesRead !== void 0) {
2148
+ span.bytes_read = input.bytesRead;
2149
+ }
2150
+ if (input.stage === "completed" && input.bytesWritten !== void 0) {
2151
+ span.bytes_written = input.bytesWritten;
2152
+ }
2153
+ if (input.stage === "completed" && input.linesCount !== void 0) {
2154
+ span.lines_count = input.linesCount;
2155
+ }
2156
+ } else if (input.hookType === "function_call") {
2157
+ if (input.functionName !== void 0) {
2158
+ span.function = input.functionName;
2159
+ }
2160
+ if (input.functionModule !== void 0) {
2161
+ span.module = input.functionModule;
2162
+ }
2163
+ if (input.functionArgs !== void 0) {
2164
+ span.args = sanitizeForGovernancePayload(input.functionArgs);
2165
+ }
2166
+ if (input.stage === "completed" && input.functionResult !== void 0) {
2167
+ span.result = sanitizeForGovernancePayload(input.functionResult);
2168
+ }
2169
+ }
2170
+ return span;
2171
+ }
2172
+ function normalizeHexId(value, width) {
2173
+ const base = (value ?? randomUUID().replaceAll("-", "")).toLowerCase();
2174
+ const filtered = base.replace(/[^a-f0-9]/g, "");
2175
+ if (filtered.length >= width) {
2176
+ return filtered.slice(0, width);
2177
+ }
2178
+ return filtered.padEnd(width, "0");
2179
+ }
2180
+ function toStringValue(value) {
2181
+ return typeof value === "string" ? value : void 0;
2182
+ }
2183
+ function toNumberValue(value) {
2184
+ return typeof value === "number" ? value : void 0;
2185
+ }
2186
+ function getSpanAttribute(span, key) {
2187
+ return span.attributes?.[key];
2188
+ }
2189
+ function parseDbOperation(statement) {
2190
+ if (!statement) {
2191
+ return void 0;
2192
+ }
2193
+ const trimmed = statement.trim();
2194
+ if (!trimmed) {
2195
+ return void 0;
2196
+ }
2197
+ const [operation] = trimmed.split(/\s+/);
2198
+ return operation?.toUpperCase();
2199
+ }
2200
+ function sanitizeForGovernancePayload(value) {
2201
+ const seen = /* @__PURE__ */ new WeakSet();
2202
+ try {
2203
+ return JSON.parse(
2204
+ JSON.stringify(value, (_key, entry) => {
2205
+ if (typeof entry === "bigint") {
2206
+ return entry.toString();
2207
+ }
2208
+ if (typeof entry === "function") {
2209
+ return `[function ${entry.name || "anonymous"}]`;
2210
+ }
2211
+ if (typeof entry === "symbol") {
2212
+ return entry.toString();
2213
+ }
2214
+ if (entry instanceof Error) {
2215
+ return {
2216
+ message: entry.message,
2217
+ name: entry.name,
2218
+ stack: entry.stack
2219
+ };
2220
+ }
2221
+ if (entry && typeof entry === "object") {
2222
+ if (seen.has(entry)) {
2223
+ return "[circular]";
2224
+ }
2225
+ seen.add(entry);
2226
+ }
2227
+ return entry;
2228
+ })
2229
+ );
2230
+ } catch {
2231
+ return String(value);
2232
+ }
2233
+ }
2234
+ function loadInstrumentation(definition, config) {
2235
+ const require2 = createRequire(import.meta.url);
2236
+ const moduleExports = require2(definition.moduleName);
2237
+ const InstrumentationConstructor = moduleExports[definition.exportName];
2238
+ if (typeof InstrumentationConstructor !== "function") {
2239
+ throw new Error(
2240
+ `Instrumentation export ${definition.exportName} was not found in ${definition.moduleName}`
2241
+ );
2242
+ }
2243
+ return new InstrumentationConstructor(config);
2244
+ }
2245
+ export {
2246
+ setupOpenBoxOpenTelemetry,
2247
+ traced
2248
+ };
2249
+ //# sourceMappingURL=setup-openbox-opentelemetry.js.map