@agentmark-ai/shared-utils 0.3.0 → 0.3.1
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/dist/index.d.mts +26 -3
- package/dist/index.d.ts +26 -3
- package/dist/index.js +535 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +534 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.mjs
CHANGED
|
@@ -298,7 +298,326 @@ ${typeMapping.join(",\n")}
|
|
|
298
298
|
var isNewFormat = (frontmatter) => {
|
|
299
299
|
return frontmatter["text_config"] || frontmatter["object_config"] || frontmatter["image_config"];
|
|
300
300
|
};
|
|
301
|
-
|
|
301
|
+
function pythonPrimitiveType(schemaType) {
|
|
302
|
+
const map = {
|
|
303
|
+
string: "str",
|
|
304
|
+
number: "float",
|
|
305
|
+
integer: "int",
|
|
306
|
+
boolean: "bool",
|
|
307
|
+
null: "None"
|
|
308
|
+
};
|
|
309
|
+
return map[schemaType] || "Any";
|
|
310
|
+
}
|
|
311
|
+
function propToPascal(prop) {
|
|
312
|
+
return prop.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
313
|
+
}
|
|
314
|
+
function schemaToPythonType(schema, parentClass, propKey, collected) {
|
|
315
|
+
if (!schema) return "Any";
|
|
316
|
+
const union = schema.anyOf || schema.oneOf;
|
|
317
|
+
if (union) {
|
|
318
|
+
const nullIdx = union.findIndex((v) => v.type === "null");
|
|
319
|
+
const hasNull = nullIdx >= 0;
|
|
320
|
+
const others = union.filter((_, i) => i !== nullIdx);
|
|
321
|
+
if (hasNull && others.length === 1) {
|
|
322
|
+
return `${schemaToPythonType(others[0], parentClass, propKey, collected)} | None`;
|
|
323
|
+
}
|
|
324
|
+
const parts = others.map(
|
|
325
|
+
(v, i) => schemaToPythonType(v, parentClass, `${propKey}${i}`, collected)
|
|
326
|
+
);
|
|
327
|
+
if (hasNull) parts.push("None");
|
|
328
|
+
return parts.join(" | ");
|
|
329
|
+
}
|
|
330
|
+
if (Array.isArray(schema.type)) {
|
|
331
|
+
const hasNull = schema.type.includes("null");
|
|
332
|
+
const nonNull = schema.type.filter((t) => t !== "null");
|
|
333
|
+
if (nonNull.length === 1 && nonNull[0] === "object" && schema.properties) {
|
|
334
|
+
const clsName = `${parentClass}${propToPascal(propKey)}`;
|
|
335
|
+
collected.push(buildTypedDict(clsName, schema, collected));
|
|
336
|
+
return hasNull ? `${clsName} | None` : clsName;
|
|
337
|
+
}
|
|
338
|
+
if (nonNull.length === 1 && nonNull[0] === "array" && schema.items) {
|
|
339
|
+
const item = schemaToPythonType(
|
|
340
|
+
schema.items,
|
|
341
|
+
parentClass,
|
|
342
|
+
propKey,
|
|
343
|
+
collected
|
|
344
|
+
);
|
|
345
|
+
return hasNull ? `list[${item}] | None` : `list[${item}]`;
|
|
346
|
+
}
|
|
347
|
+
const base = nonNull.length === 1 ? pythonPrimitiveType(nonNull[0]) : nonNull.map(pythonPrimitiveType).join(" | ");
|
|
348
|
+
return hasNull ? `${base} | None` : base;
|
|
349
|
+
}
|
|
350
|
+
switch (schema.type) {
|
|
351
|
+
case "string":
|
|
352
|
+
case "number":
|
|
353
|
+
case "integer":
|
|
354
|
+
case "boolean":
|
|
355
|
+
case "null":
|
|
356
|
+
return pythonPrimitiveType(schema.type);
|
|
357
|
+
case "array": {
|
|
358
|
+
const item = schema.items ? schemaToPythonType(schema.items, parentClass, propKey, collected) : "Any";
|
|
359
|
+
return `list[${item}]`;
|
|
360
|
+
}
|
|
361
|
+
case "object": {
|
|
362
|
+
if (!schema.properties || Object.keys(schema.properties).length === 0) {
|
|
363
|
+
return "dict[str, Any]";
|
|
364
|
+
}
|
|
365
|
+
const clsName = `${parentClass}${propToPascal(propKey)}`;
|
|
366
|
+
collected.push(buildTypedDict(clsName, schema, collected));
|
|
367
|
+
return clsName;
|
|
368
|
+
}
|
|
369
|
+
default:
|
|
370
|
+
if (schema.properties) {
|
|
371
|
+
const clsName = `${parentClass}${propToPascal(propKey)}`;
|
|
372
|
+
collected.push(buildTypedDict(clsName, schema, collected));
|
|
373
|
+
return clsName;
|
|
374
|
+
}
|
|
375
|
+
return "Any";
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
function buildTypedDict(className, schema, collected) {
|
|
379
|
+
const props = schema.properties || {};
|
|
380
|
+
const requiredSet = new Set(schema.required || []);
|
|
381
|
+
const lines = [];
|
|
382
|
+
const desc = schema.description;
|
|
383
|
+
if (desc) {
|
|
384
|
+
lines.push(`class ${className}(TypedDict):`);
|
|
385
|
+
lines.push(` """${desc}"""`);
|
|
386
|
+
} else {
|
|
387
|
+
lines.push(`class ${className}(TypedDict):`);
|
|
388
|
+
}
|
|
389
|
+
const entries = Object.entries(props);
|
|
390
|
+
if (entries.length === 0) {
|
|
391
|
+
lines.push(" pass");
|
|
392
|
+
return lines.join("\n");
|
|
393
|
+
}
|
|
394
|
+
for (const [key, propSchema] of entries) {
|
|
395
|
+
const pyType = schemaToPythonType(
|
|
396
|
+
propSchema,
|
|
397
|
+
className,
|
|
398
|
+
key,
|
|
399
|
+
collected
|
|
400
|
+
);
|
|
401
|
+
const isRequired = requiredSet.has(key);
|
|
402
|
+
const annotation = isRequired ? pyType : `NotRequired[${pyType}]`;
|
|
403
|
+
const propDesc = propSchema.description;
|
|
404
|
+
if (propDesc) {
|
|
405
|
+
const prefix = ` ${key}: ${annotation} # `;
|
|
406
|
+
const maxDesc = 99 - prefix.length;
|
|
407
|
+
if (maxDesc > 10) {
|
|
408
|
+
const shortDesc = propDesc.length > maxDesc ? propDesc.substring(0, maxDesc - 3) + "..." : propDesc;
|
|
409
|
+
lines.push(`${prefix}${shortDesc}`);
|
|
410
|
+
} else {
|
|
411
|
+
lines.push(` ${key}: ${annotation}`);
|
|
412
|
+
}
|
|
413
|
+
} else {
|
|
414
|
+
lines.push(` ${key}: ${annotation}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return lines.join("\n");
|
|
418
|
+
}
|
|
419
|
+
function generatePythonToolTypes(tools) {
|
|
420
|
+
if (Object.keys(tools).length === 0) return null;
|
|
421
|
+
const collected = [];
|
|
422
|
+
for (const [toolName, schema] of Object.entries(tools)) {
|
|
423
|
+
const argsName = `${getToolInterfaceName(toolName)}Args`;
|
|
424
|
+
if (schema.parameters && schema.parameters.properties) {
|
|
425
|
+
collected.push(buildTypedDict(argsName, schema.parameters, collected));
|
|
426
|
+
} else {
|
|
427
|
+
collected.push(`class ${argsName}(TypedDict):
|
|
428
|
+
pass`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
const toolLines = Object.keys(tools).map((name) => ` ${name}: ${getToolInterfaceName(name)}Args`).join("\n");
|
|
432
|
+
collected.push(`class Tools(TypedDict):
|
|
433
|
+
${toolLines}`);
|
|
434
|
+
return collected.join("\n\n\n");
|
|
435
|
+
}
|
|
436
|
+
function buildPythonHeader(body) {
|
|
437
|
+
const imports = ["TypedDict"];
|
|
438
|
+
if (body.includes("NotRequired[")) imports.push("NotRequired");
|
|
439
|
+
if (body.includes("Literal[")) imports.push("Literal");
|
|
440
|
+
if (/\bAny\b/.test(body)) imports.push("Any");
|
|
441
|
+
imports.sort();
|
|
442
|
+
return `# Auto-generated types from AgentMark
|
|
443
|
+
# Do not edit this file directly
|
|
444
|
+
|
|
445
|
+
from __future__ import annotations
|
|
446
|
+
|
|
447
|
+
from typing import ${imports.join(", ")}
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
`;
|
|
451
|
+
}
|
|
452
|
+
async function generatePythonTypeDefinitionsV1_0(prompts) {
|
|
453
|
+
const allClasses = [];
|
|
454
|
+
const typeMapping = [];
|
|
455
|
+
for (const prompt of prompts) {
|
|
456
|
+
const { path: promptPath, input_schema } = prompt;
|
|
457
|
+
const name = getInterfaceName(promptPath);
|
|
458
|
+
try {
|
|
459
|
+
let kind = "text";
|
|
460
|
+
let outputSchema = null;
|
|
461
|
+
let tools = {};
|
|
462
|
+
if ("text_config" in prompt) {
|
|
463
|
+
kind = "text";
|
|
464
|
+
tools = prompt.text_config.tools || {};
|
|
465
|
+
} else if ("object_config" in prompt) {
|
|
466
|
+
kind = "object";
|
|
467
|
+
tools = prompt.object_config.tools || {};
|
|
468
|
+
outputSchema = prompt.object_config.schema;
|
|
469
|
+
} else if ("image_config" in prompt) {
|
|
470
|
+
kind = "image";
|
|
471
|
+
tools = prompt.image_config.tools || {};
|
|
472
|
+
}
|
|
473
|
+
const inputCollected = [];
|
|
474
|
+
if (input_schema && input_schema.properties) {
|
|
475
|
+
inputCollected.push(
|
|
476
|
+
buildTypedDict(`${name}In`, input_schema, inputCollected)
|
|
477
|
+
);
|
|
478
|
+
} else {
|
|
479
|
+
inputCollected.push(`class ${name}In(TypedDict):
|
|
480
|
+
pass`);
|
|
481
|
+
}
|
|
482
|
+
allClasses.push(...inputCollected);
|
|
483
|
+
const outputCollected = [];
|
|
484
|
+
if (outputSchema && outputSchema.properties) {
|
|
485
|
+
outputCollected.push(
|
|
486
|
+
buildTypedDict(`${name}Out`, outputSchema, outputCollected)
|
|
487
|
+
);
|
|
488
|
+
} else if (kind === "object") {
|
|
489
|
+
outputCollected.push(`class ${name}Out(TypedDict):
|
|
490
|
+
pass`);
|
|
491
|
+
} else {
|
|
492
|
+
outputCollected.push(`${name}Out = str`);
|
|
493
|
+
}
|
|
494
|
+
allClasses.push(...outputCollected);
|
|
495
|
+
if (Object.keys(tools).length > 0) {
|
|
496
|
+
const toolOutput = generatePythonToolTypes(tools);
|
|
497
|
+
if (toolOutput) allClasses.push(toolOutput);
|
|
498
|
+
}
|
|
499
|
+
const toolsLine = Object.keys(tools).length > 0 ? "\n tools: NotRequired[list[str]]" : "";
|
|
500
|
+
allClasses.push(
|
|
501
|
+
`class ${name}(TypedDict):
|
|
502
|
+
kind: Literal['${kind}']
|
|
503
|
+
input: ${name}In
|
|
504
|
+
output: ${name}Out${toolsLine}`
|
|
505
|
+
);
|
|
506
|
+
typeMapping.push({ path: promptPath, name });
|
|
507
|
+
const withoutMdx = promptPath.replace(/\.mdx$/, "");
|
|
508
|
+
if (withoutMdx !== promptPath)
|
|
509
|
+
typeMapping.push({ path: withoutMdx, name });
|
|
510
|
+
const shortName = promptPath.replace(/\.prompt\.mdx$/, "");
|
|
511
|
+
if (shortName !== promptPath && shortName !== withoutMdx) {
|
|
512
|
+
typeMapping.push({ path: shortName, name });
|
|
513
|
+
}
|
|
514
|
+
} catch (error) {
|
|
515
|
+
console.error(`Error processing ${promptPath}:`, error);
|
|
516
|
+
allClasses.push(`class ${name}In(TypedDict):
|
|
517
|
+
pass`);
|
|
518
|
+
allClasses.push(`${name}Out = str`);
|
|
519
|
+
allClasses.push(
|
|
520
|
+
`class ${name}(TypedDict):
|
|
521
|
+
kind: Literal['text']
|
|
522
|
+
input: ${name}In
|
|
523
|
+
output: ${name}Out`
|
|
524
|
+
);
|
|
525
|
+
typeMapping.push({ path: promptPath, name });
|
|
526
|
+
const withoutMdx = promptPath.replace(/\.mdx$/, "");
|
|
527
|
+
if (withoutMdx !== promptPath)
|
|
528
|
+
typeMapping.push({ path: withoutMdx, name });
|
|
529
|
+
const shortName = promptPath.replace(/\.prompt\.mdx$/, "");
|
|
530
|
+
if (shortName !== promptPath && shortName !== withoutMdx) {
|
|
531
|
+
typeMapping.push({ path: shortName, name });
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
const mappingLines = typeMapping.map(({ path: path2, name }) => ` '${path2}': ${name}`).join(",\n");
|
|
536
|
+
allClasses.push(
|
|
537
|
+
`AgentmarkTypes = TypedDict('AgentmarkTypes', {
|
|
538
|
+
${mappingLines},
|
|
539
|
+
})`
|
|
540
|
+
);
|
|
541
|
+
const body = allClasses.join("\n\n\n") + "\n";
|
|
542
|
+
return buildPythonHeader(body) + body;
|
|
543
|
+
}
|
|
544
|
+
async function generatePythonTypeDefinitionsV0(prompts) {
|
|
545
|
+
var _a, _b;
|
|
546
|
+
const allClasses = [];
|
|
547
|
+
const typeMapping = [];
|
|
548
|
+
for (const prompt of prompts) {
|
|
549
|
+
const { path: promptPath, metadata, input_schema } = prompt;
|
|
550
|
+
const name = getInterfaceName(promptPath);
|
|
551
|
+
try {
|
|
552
|
+
const inputCollected = [];
|
|
553
|
+
if (input_schema && input_schema.properties) {
|
|
554
|
+
inputCollected.push(
|
|
555
|
+
buildTypedDict(`${name}In`, input_schema, inputCollected)
|
|
556
|
+
);
|
|
557
|
+
} else {
|
|
558
|
+
inputCollected.push(`class ${name}In(TypedDict):
|
|
559
|
+
pass`);
|
|
560
|
+
}
|
|
561
|
+
allClasses.push(...inputCollected);
|
|
562
|
+
const outputSchema = (_b = (_a = metadata == null ? void 0 : metadata.model) == null ? void 0 : _a.settings) == null ? void 0 : _b.schema;
|
|
563
|
+
const outputCollected = [];
|
|
564
|
+
if (outputSchema && outputSchema.properties) {
|
|
565
|
+
outputCollected.push(
|
|
566
|
+
buildTypedDict(`${name}Out`, outputSchema, outputCollected)
|
|
567
|
+
);
|
|
568
|
+
} else {
|
|
569
|
+
outputCollected.push(`${name}Out = str`);
|
|
570
|
+
}
|
|
571
|
+
allClasses.push(...outputCollected);
|
|
572
|
+
allClasses.push(
|
|
573
|
+
`class ${name}(TypedDict):
|
|
574
|
+
input: ${name}In
|
|
575
|
+
output: ${name}Out`
|
|
576
|
+
);
|
|
577
|
+
typeMapping.push({ path: promptPath, name });
|
|
578
|
+
const withoutMdx = promptPath.replace(/\.mdx$/, "");
|
|
579
|
+
if (withoutMdx !== promptPath)
|
|
580
|
+
typeMapping.push({ path: withoutMdx, name });
|
|
581
|
+
const shortName = promptPath.replace(/\.prompt\.mdx$/, "");
|
|
582
|
+
if (shortName !== promptPath && shortName !== withoutMdx) {
|
|
583
|
+
typeMapping.push({ path: shortName, name });
|
|
584
|
+
}
|
|
585
|
+
} catch (error) {
|
|
586
|
+
console.error(`Error processing ${promptPath}:`, error);
|
|
587
|
+
allClasses.push(`class ${name}In(TypedDict):
|
|
588
|
+
pass`);
|
|
589
|
+
allClasses.push(`${name}Out = str`);
|
|
590
|
+
allClasses.push(
|
|
591
|
+
`class ${name}(TypedDict):
|
|
592
|
+
input: ${name}In
|
|
593
|
+
output: ${name}Out`
|
|
594
|
+
);
|
|
595
|
+
typeMapping.push({ path: promptPath, name });
|
|
596
|
+
const withoutMdx = promptPath.replace(/\.mdx$/, "");
|
|
597
|
+
if (withoutMdx !== promptPath)
|
|
598
|
+
typeMapping.push({ path: withoutMdx, name });
|
|
599
|
+
const shortName = promptPath.replace(/\.prompt\.mdx$/, "");
|
|
600
|
+
if (shortName !== promptPath && shortName !== withoutMdx) {
|
|
601
|
+
typeMapping.push({ path: shortName, name });
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
const mappingLines = typeMapping.map(({ path: path2, name }) => ` '${path2}': ${name}`).join(",\n");
|
|
606
|
+
allClasses.push(
|
|
607
|
+
`AgentmarkTypes = TypedDict('AgentmarkTypes', {
|
|
608
|
+
${mappingLines},
|
|
609
|
+
})`
|
|
610
|
+
);
|
|
611
|
+
const body = allClasses.join("\n\n\n") + "\n";
|
|
612
|
+
return buildPythonHeader(body) + body;
|
|
613
|
+
}
|
|
614
|
+
async function generateTypeDefinitions(prompts, language = "typescript") {
|
|
615
|
+
if (language === "python") {
|
|
616
|
+
if (prompts[0].version === "1.0") {
|
|
617
|
+
return generatePythonTypeDefinitionsV1_0(prompts);
|
|
618
|
+
}
|
|
619
|
+
return generatePythonTypeDefinitionsV0(prompts);
|
|
620
|
+
}
|
|
302
621
|
if (prompts[0].version === "1.0") {
|
|
303
622
|
return generateTypeDefinitionsV1_0(prompts);
|
|
304
623
|
}
|
|
@@ -505,6 +824,7 @@ var KNOWN_METADATA_FIELDS = /* @__PURE__ */ new Set([
|
|
|
505
824
|
"dataset_path",
|
|
506
825
|
"dataset_item_name",
|
|
507
826
|
"dataset_expected_output",
|
|
827
|
+
"dataset_input",
|
|
508
828
|
"prompt_name",
|
|
509
829
|
"props",
|
|
510
830
|
"commit_sha"
|
|
@@ -1292,10 +1612,12 @@ function parseAgentMarkAttributes(attributes, prefix = "agentmark.") {
|
|
|
1292
1612
|
if (get("trace_name")) result.traceName = String(get("trace_name"));
|
|
1293
1613
|
if (get("prompt_name")) result.promptName = String(get("prompt_name"));
|
|
1294
1614
|
if (get("props")) result.props = String(get("props"));
|
|
1615
|
+
if (get("span.kind")) result.kind = String(get("span.kind"));
|
|
1295
1616
|
if (get("dataset_run_id")) result.datasetRunId = String(get("dataset_run_id"));
|
|
1296
1617
|
if (get("dataset_run_name")) result.datasetRunName = String(get("dataset_run_name"));
|
|
1297
1618
|
if (get("dataset_item_name")) result.datasetItemName = String(get("dataset_item_name"));
|
|
1298
1619
|
if (get("dataset_expected_output")) result.datasetExpectedOutput = String(get("dataset_expected_output"));
|
|
1620
|
+
if (get("dataset_input")) result.datasetInput = String(get("dataset_input"));
|
|
1299
1621
|
if (get("dataset_path")) result.datasetPath = String(get("dataset_path"));
|
|
1300
1622
|
return result;
|
|
1301
1623
|
}
|
|
@@ -1408,6 +1730,10 @@ var AgentMarkTransformer = class {
|
|
|
1408
1730
|
if (result.inputTokens !== void 0 && result.outputTokens !== void 0) {
|
|
1409
1731
|
result.totalTokens = result.inputTokens + result.outputTokens;
|
|
1410
1732
|
}
|
|
1733
|
+
const costUsd = attributes["agentmark.usage.cost_usd"];
|
|
1734
|
+
if (typeof costUsd === "number" && costUsd > 0) {
|
|
1735
|
+
result.cost = costUsd;
|
|
1736
|
+
}
|
|
1411
1737
|
const finishReasons = attributes[GenAIAttributes.RESPONSE_FINISH_REASONS];
|
|
1412
1738
|
if (finishReasons) {
|
|
1413
1739
|
try {
|
|
@@ -1453,6 +1779,22 @@ var AgentMarkTransformer = class {
|
|
|
1453
1779
|
const responseOutput = attributes[GenAIAttributes.RESPONSE_OUTPUT];
|
|
1454
1780
|
if (responseOutput && typeof responseOutput === "string") {
|
|
1455
1781
|
result.output = responseOutput;
|
|
1782
|
+
try {
|
|
1783
|
+
result.outputObject = JSON.parse(responseOutput);
|
|
1784
|
+
} catch {
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
const amInput = attributes["agentmark.input"];
|
|
1788
|
+
if (amInput && typeof amInput === "string" && !result.input) {
|
|
1789
|
+
result.input = [{ role: "user", content: amInput }];
|
|
1790
|
+
}
|
|
1791
|
+
const amOutput = attributes["agentmark.output"];
|
|
1792
|
+
if (amOutput && typeof amOutput === "string" && !result.output) {
|
|
1793
|
+
result.output = amOutput;
|
|
1794
|
+
try {
|
|
1795
|
+
result.outputObject = JSON.parse(amOutput);
|
|
1796
|
+
} catch {
|
|
1797
|
+
}
|
|
1456
1798
|
}
|
|
1457
1799
|
const toolName = attributes[GenAIAttributes.TOOL_NAME];
|
|
1458
1800
|
const toolCallId = attributes[GenAIAttributes.TOOL_CALL_ID];
|
|
@@ -1494,6 +1836,194 @@ var AgentMarkTransformer = class {
|
|
|
1494
1836
|
};
|
|
1495
1837
|
var AGENTMARK_SCOPE_NAME = "agentmark";
|
|
1496
1838
|
|
|
1839
|
+
// src/normalizer/transformers/otel-genai/index.ts
|
|
1840
|
+
var Attrs = {
|
|
1841
|
+
// Standard OTel GenAI attributes
|
|
1842
|
+
SYSTEM: "gen_ai.system",
|
|
1843
|
+
PROVIDER_NAME: "gen_ai.provider.name",
|
|
1844
|
+
OPERATION_NAME: "gen_ai.operation.name",
|
|
1845
|
+
REQUEST_MODEL: "gen_ai.request.model",
|
|
1846
|
+
REQUEST_MAX_TOKENS: "gen_ai.request.max_tokens",
|
|
1847
|
+
REQUEST_TEMPERATURE: "gen_ai.request.temperature",
|
|
1848
|
+
RESPONSE_ID: "gen_ai.response.id",
|
|
1849
|
+
RESPONSE_MODEL: "gen_ai.response.model",
|
|
1850
|
+
RESPONSE_FINISH_REASONS: "gen_ai.response.finish_reasons",
|
|
1851
|
+
USAGE_INPUT_TOKENS: "gen_ai.usage.input_tokens",
|
|
1852
|
+
USAGE_OUTPUT_TOKENS: "gen_ai.usage.output_tokens",
|
|
1853
|
+
// v1.37.0+ content attributes
|
|
1854
|
+
INPUT_MESSAGES: "gen_ai.input.messages",
|
|
1855
|
+
OUTPUT_MESSAGES: "gen_ai.output.messages",
|
|
1856
|
+
SYSTEM_INSTRUCTIONS: "gen_ai.system_instructions",
|
|
1857
|
+
TOOL_DEFINITIONS: "gen_ai.tool.definitions",
|
|
1858
|
+
// Tool call attributes (v1.37.0+)
|
|
1859
|
+
TOOL_NAME: "gen_ai.tool.name",
|
|
1860
|
+
TOOL_CALL_ID: "gen_ai.tool.call.id",
|
|
1861
|
+
TOOL_CALL_ARGS: "gen_ai.tool.call.arguments",
|
|
1862
|
+
TOOL_CALL_RESULT: "gen_ai.tool.call.result"
|
|
1863
|
+
};
|
|
1864
|
+
function partsToText(parts) {
|
|
1865
|
+
return parts.filter((p) => p.type === "text" && p.content).map((p) => p.content).join("\n");
|
|
1866
|
+
}
|
|
1867
|
+
function normalizeMessages(raw) {
|
|
1868
|
+
try {
|
|
1869
|
+
const parsed = JSON.parse(raw);
|
|
1870
|
+
if (!Array.isArray(parsed) || parsed.length === 0) return null;
|
|
1871
|
+
const messages = [];
|
|
1872
|
+
for (const msg of parsed) {
|
|
1873
|
+
if (!msg.role) continue;
|
|
1874
|
+
if (msg.content && typeof msg.content === "string") {
|
|
1875
|
+
messages.push(msg);
|
|
1876
|
+
} else if (msg.parts && Array.isArray(msg.parts)) {
|
|
1877
|
+
const text = partsToText(msg.parts);
|
|
1878
|
+
if (text) {
|
|
1879
|
+
messages.push({ role: msg.role, content: text });
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
return messages.length > 0 ? messages : null;
|
|
1884
|
+
} catch {
|
|
1885
|
+
return null;
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
function extractStructuredOutput(raw) {
|
|
1889
|
+
try {
|
|
1890
|
+
const parsed = JSON.parse(raw);
|
|
1891
|
+
if (!Array.isArray(parsed)) return null;
|
|
1892
|
+
for (const msg of parsed) {
|
|
1893
|
+
for (const part of msg.parts || []) {
|
|
1894
|
+
if (part.type === "tool_call" && part.arguments) {
|
|
1895
|
+
return {
|
|
1896
|
+
output: JSON.stringify(part.arguments),
|
|
1897
|
+
outputObject: part.arguments
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
for (const msg of parsed) {
|
|
1903
|
+
const text = partsToText(msg.parts || []);
|
|
1904
|
+
if (text) return { output: text };
|
|
1905
|
+
}
|
|
1906
|
+
return null;
|
|
1907
|
+
} catch {
|
|
1908
|
+
return null;
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
var OtelGenAiTransformer = class {
|
|
1912
|
+
classify(span, attributes) {
|
|
1913
|
+
if (span.name.startsWith("chat ")) return "GENERATION" /* GENERATION */;
|
|
1914
|
+
if (span.name.startsWith("invoke_agent") || span.name === "agent run") return "SPAN" /* SPAN */;
|
|
1915
|
+
if (span.name.startsWith("execute_tool") || span.name.startsWith("running ")) return "SPAN" /* SPAN */;
|
|
1916
|
+
if (attributes[Attrs.USAGE_INPUT_TOKENS] !== void 0) return "GENERATION" /* GENERATION */;
|
|
1917
|
+
return "SPAN" /* SPAN */;
|
|
1918
|
+
}
|
|
1919
|
+
transform(span, attributes) {
|
|
1920
|
+
const result = {};
|
|
1921
|
+
const model = attributes[Attrs.RESPONSE_MODEL] || attributes[Attrs.REQUEST_MODEL];
|
|
1922
|
+
if (model && typeof model === "string") {
|
|
1923
|
+
result.model = model;
|
|
1924
|
+
}
|
|
1925
|
+
const inputTokens = attributes[Attrs.USAGE_INPUT_TOKENS];
|
|
1926
|
+
const outputTokens = attributes[Attrs.USAGE_OUTPUT_TOKENS];
|
|
1927
|
+
if (typeof inputTokens === "number") result.inputTokens = inputTokens;
|
|
1928
|
+
if (typeof outputTokens === "number") result.outputTokens = outputTokens;
|
|
1929
|
+
if (result.inputTokens !== void 0 && result.outputTokens !== void 0) {
|
|
1930
|
+
result.totalTokens = result.inputTokens + result.outputTokens;
|
|
1931
|
+
}
|
|
1932
|
+
const finishReasons = attributes[Attrs.RESPONSE_FINISH_REASONS];
|
|
1933
|
+
if (Array.isArray(finishReasons) && finishReasons.length > 0) {
|
|
1934
|
+
result.finishReason = finishReasons[0];
|
|
1935
|
+
}
|
|
1936
|
+
const temperature = attributes[Attrs.REQUEST_TEMPERATURE];
|
|
1937
|
+
if (typeof temperature === "number") {
|
|
1938
|
+
result.settings = { ...result.settings, temperature };
|
|
1939
|
+
}
|
|
1940
|
+
const inputMessages = attributes[Attrs.INPUT_MESSAGES];
|
|
1941
|
+
if (inputMessages && typeof inputMessages === "string") {
|
|
1942
|
+
const messages = normalizeMessages(inputMessages);
|
|
1943
|
+
if (messages) result.input = messages;
|
|
1944
|
+
}
|
|
1945
|
+
const outputMessages = attributes[Attrs.OUTPUT_MESSAGES];
|
|
1946
|
+
if (outputMessages && typeof outputMessages === "string") {
|
|
1947
|
+
const extracted = extractStructuredOutput(outputMessages);
|
|
1948
|
+
if (extracted) {
|
|
1949
|
+
result.output = extracted.output;
|
|
1950
|
+
if (extracted.outputObject) {
|
|
1951
|
+
result.outputObject = extracted.outputObject;
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
const allMessages = attributes["pydantic_ai.all_messages"];
|
|
1956
|
+
if (allMessages && typeof allMessages === "string" && !result.input) {
|
|
1957
|
+
const messages = normalizeMessages(allMessages);
|
|
1958
|
+
if (messages) {
|
|
1959
|
+
const userMessages = messages.filter((m) => m.role === "user");
|
|
1960
|
+
if (userMessages.length > 0) {
|
|
1961
|
+
result.input = userMessages;
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
const finalResult = attributes["final_result"];
|
|
1966
|
+
if (finalResult && typeof finalResult === "string" && !result.output) {
|
|
1967
|
+
result.output = finalResult;
|
|
1968
|
+
try {
|
|
1969
|
+
result.outputObject = JSON.parse(finalResult);
|
|
1970
|
+
} catch {
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
const propsStr = attributes["agentmark.props"];
|
|
1974
|
+
if (propsStr && typeof propsStr === "string" && !result.input) {
|
|
1975
|
+
try {
|
|
1976
|
+
const props = JSON.parse(propsStr);
|
|
1977
|
+
result.input = [{ role: "user", content: JSON.stringify(props) }];
|
|
1978
|
+
} catch {
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
const outputStr = attributes["agentmark.output"];
|
|
1982
|
+
if (outputStr && typeof outputStr === "string" && !result.output) {
|
|
1983
|
+
result.output = outputStr;
|
|
1984
|
+
try {
|
|
1985
|
+
result.outputObject = JSON.parse(outputStr);
|
|
1986
|
+
} catch {
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
const toolName = attributes[Attrs.TOOL_NAME];
|
|
1990
|
+
if (toolName && typeof toolName === "string") {
|
|
1991
|
+
result.name = toolName;
|
|
1992
|
+
const toolCall = {
|
|
1993
|
+
type: "tool-call",
|
|
1994
|
+
toolCallId: attributes[Attrs.TOOL_CALL_ID] || "",
|
|
1995
|
+
toolName,
|
|
1996
|
+
args: {}
|
|
1997
|
+
};
|
|
1998
|
+
const toolArgs = attributes[Attrs.TOOL_CALL_ARGS];
|
|
1999
|
+
if (toolArgs && typeof toolArgs === "string") {
|
|
2000
|
+
try {
|
|
2001
|
+
toolCall.args = JSON.parse(toolArgs);
|
|
2002
|
+
} catch {
|
|
2003
|
+
toolCall.args = { raw: toolArgs };
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
const toolResult = attributes[Attrs.TOOL_CALL_RESULT];
|
|
2007
|
+
if (toolResult && typeof toolResult === "string") {
|
|
2008
|
+
toolCall.result = toolResult;
|
|
2009
|
+
}
|
|
2010
|
+
result.toolCalls = [toolCall];
|
|
2011
|
+
}
|
|
2012
|
+
const agentmarkAttrs = parseAgentMarkAttributes(attributes);
|
|
2013
|
+
Object.assign(result, agentmarkAttrs);
|
|
2014
|
+
const parsedMeta = parseMetadata(attributes);
|
|
2015
|
+
if (parsedMeta.metadata && Object.keys(parsedMeta.metadata).length > 0) {
|
|
2016
|
+
result.metadata = { ...result.metadata, ...parsedMeta.metadata };
|
|
2017
|
+
}
|
|
2018
|
+
const customMeta = extractCustomMetadata(attributes);
|
|
2019
|
+
if (Object.keys(customMeta).length > 0) {
|
|
2020
|
+
result.metadata = { ...result.metadata, ...customMeta };
|
|
2021
|
+
}
|
|
2022
|
+
return result;
|
|
2023
|
+
}
|
|
2024
|
+
};
|
|
2025
|
+
OtelGenAiTransformer.SCOPE_NAME = "pydantic-ai";
|
|
2026
|
+
|
|
1497
2027
|
// src/normalizer/converters/otlp-converter.ts
|
|
1498
2028
|
function convertOtlpValue(value) {
|
|
1499
2029
|
var _a;
|
|
@@ -1595,7 +2125,8 @@ var typeClassifier = new TypeClassifier();
|
|
|
1595
2125
|
registry.register("ai", new AiSdkTransformer());
|
|
1596
2126
|
registry.register("default-tracer", new MastraTransformer());
|
|
1597
2127
|
registry.register("agentmark", new AgentMarkTransformer());
|
|
1598
|
-
registry.
|
|
2128
|
+
registry.register("pydantic-ai", new OtelGenAiTransformer());
|
|
2129
|
+
registry.setDefault(new OtelGenAiTransformer());
|
|
1599
2130
|
function normalizeSpan(resource, scope, span) {
|
|
1600
2131
|
var _a, _b, _c;
|
|
1601
2132
|
const allAttributes = {
|
|
@@ -1669,6 +2200,7 @@ export {
|
|
|
1669
2200
|
AiSdkTransformer,
|
|
1670
2201
|
AgentMarkTransformer as ClaudeAgentTransformer,
|
|
1671
2202
|
MastraTransformer,
|
|
2203
|
+
OtelGenAiTransformer,
|
|
1672
2204
|
SpanType,
|
|
1673
2205
|
TransformerRegistry,
|
|
1674
2206
|
TypeClassifier,
|