@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.
- package/LICENSE +21 -0
- package/README.md +158 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/openbox-client.d.ts +42 -0
- package/dist/client/openbox-client.js +405 -0
- package/dist/client/openbox-client.js.map +1 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/openbox-config.d.ts +54 -0
- package/dist/config/openbox-config.js +162 -0
- package/dist/config/openbox-config.js.map +1 -0
- package/dist/governance/activity-runtime.d.ts +42 -0
- package/dist/governance/activity-runtime.js +712 -0
- package/dist/governance/activity-runtime.js.map +1 -0
- package/dist/governance/approval-registry.d.ts +17 -0
- package/dist/governance/approval-registry.js +32 -0
- package/dist/governance/approval-registry.js.map +1 -0
- package/dist/governance/context.d.ts +16 -0
- package/dist/governance/context.js +13 -0
- package/dist/governance/context.js.map +1 -0
- package/dist/governance/index.d.ts +2 -0
- package/dist/governance/index.js +1 -0
- package/dist/governance/index.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/mastra/index.d.ts +16 -0
- package/dist/mastra/index.js +5 -0
- package/dist/mastra/index.js.map +1 -0
- package/dist/mastra/with-openbox.d.ts +30 -0
- package/dist/mastra/with-openbox.js +243 -0
- package/dist/mastra/with-openbox.js.map +1 -0
- package/dist/mastra/wrap-agent.d.ts +14 -0
- package/dist/mastra/wrap-agent.js +1744 -0
- package/dist/mastra/wrap-agent.js.map +1 -0
- package/dist/mastra/wrap-tool.d.ts +18 -0
- package/dist/mastra/wrap-tool.js +49 -0
- package/dist/mastra/wrap-tool.js.map +1 -0
- package/dist/mastra/wrap-workflow.d.ts +14 -0
- package/dist/mastra/wrap-workflow.js +386 -0
- package/dist/mastra/wrap-workflow.js.map +1 -0
- package/dist/otel/index.d.ts +11 -0
- package/dist/otel/index.js +2 -0
- package/dist/otel/index.js.map +1 -0
- package/dist/otel/setup-openbox-opentelemetry.d.ts +38 -0
- package/dist/otel/setup-openbox-opentelemetry.js +2249 -0
- package/dist/otel/setup-openbox-opentelemetry.js.map +1 -0
- package/dist/span/index.d.ts +5 -0
- package/dist/span/index.js +2 -0
- package/dist/span/index.js.map +1 -0
- package/dist/span/openbox-span-processor.d.ts +90 -0
- package/dist/span/openbox-span-processor.js +580 -0
- package/dist/span/openbox-span-processor.js.map +1 -0
- package/dist/types/errors.d.ts +25 -0
- package/dist/types/errors.js +40 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/governance-verdict-response.d.ts +57 -0
- package/dist/types/governance-verdict-response.js +84 -0
- package/dist/types/governance-verdict-response.js.map +1 -0
- package/dist/types/guardrails.d.ts +23 -0
- package/dist/types/guardrails.js +27 -0
- package/dist/types/guardrails.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/verdict.d.ts +22 -0
- package/dist/types/verdict.js +55 -0
- package/dist/types/verdict.js.map +1 -0
- package/dist/types/workflow-event-type.d.ts +10 -0
- package/dist/types/workflow-event-type.js +13 -0
- package/dist/types/workflow-event-type.js.map +1 -0
- package/dist/types/workflow-span-buffer.d.ts +31 -0
- package/dist/types/workflow-span-buffer.js +42 -0
- package/dist/types/workflow-span-buffer.js.map +1 -0
- package/docs/README.md +66 -0
- package/docs/api-reference.md +348 -0
- package/docs/approvals-and-guardrails.md +163 -0
- package/docs/architecture.md +186 -0
- package/docs/configuration.md +214 -0
- package/docs/event-model.md +215 -0
- package/docs/installation.md +108 -0
- package/docs/integration-patterns.md +214 -0
- package/docs/security-and-privacy.md +174 -0
- package/docs/telemetry.md +196 -0
- package/docs/troubleshooting.md +210 -0
- 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
|