@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.js
CHANGED
|
@@ -35,6 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
AiSdkTransformer: () => AiSdkTransformer,
|
|
36
36
|
ClaudeAgentTransformer: () => AgentMarkTransformer,
|
|
37
37
|
MastraTransformer: () => MastraTransformer,
|
|
38
|
+
OtelGenAiTransformer: () => OtelGenAiTransformer,
|
|
38
39
|
SpanType: () => SpanType,
|
|
39
40
|
TransformerRegistry: () => TransformerRegistry,
|
|
40
41
|
TypeClassifier: () => TypeClassifier,
|
|
@@ -360,7 +361,326 @@ ${typeMapping.join(",\n")}
|
|
|
360
361
|
var isNewFormat = (frontmatter) => {
|
|
361
362
|
return frontmatter["text_config"] || frontmatter["object_config"] || frontmatter["image_config"];
|
|
362
363
|
};
|
|
363
|
-
|
|
364
|
+
function pythonPrimitiveType(schemaType) {
|
|
365
|
+
const map = {
|
|
366
|
+
string: "str",
|
|
367
|
+
number: "float",
|
|
368
|
+
integer: "int",
|
|
369
|
+
boolean: "bool",
|
|
370
|
+
null: "None"
|
|
371
|
+
};
|
|
372
|
+
return map[schemaType] || "Any";
|
|
373
|
+
}
|
|
374
|
+
function propToPascal(prop) {
|
|
375
|
+
return prop.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
376
|
+
}
|
|
377
|
+
function schemaToPythonType(schema, parentClass, propKey, collected) {
|
|
378
|
+
if (!schema) return "Any";
|
|
379
|
+
const union = schema.anyOf || schema.oneOf;
|
|
380
|
+
if (union) {
|
|
381
|
+
const nullIdx = union.findIndex((v) => v.type === "null");
|
|
382
|
+
const hasNull = nullIdx >= 0;
|
|
383
|
+
const others = union.filter((_, i) => i !== nullIdx);
|
|
384
|
+
if (hasNull && others.length === 1) {
|
|
385
|
+
return `${schemaToPythonType(others[0], parentClass, propKey, collected)} | None`;
|
|
386
|
+
}
|
|
387
|
+
const parts = others.map(
|
|
388
|
+
(v, i) => schemaToPythonType(v, parentClass, `${propKey}${i}`, collected)
|
|
389
|
+
);
|
|
390
|
+
if (hasNull) parts.push("None");
|
|
391
|
+
return parts.join(" | ");
|
|
392
|
+
}
|
|
393
|
+
if (Array.isArray(schema.type)) {
|
|
394
|
+
const hasNull = schema.type.includes("null");
|
|
395
|
+
const nonNull = schema.type.filter((t) => t !== "null");
|
|
396
|
+
if (nonNull.length === 1 && nonNull[0] === "object" && schema.properties) {
|
|
397
|
+
const clsName = `${parentClass}${propToPascal(propKey)}`;
|
|
398
|
+
collected.push(buildTypedDict(clsName, schema, collected));
|
|
399
|
+
return hasNull ? `${clsName} | None` : clsName;
|
|
400
|
+
}
|
|
401
|
+
if (nonNull.length === 1 && nonNull[0] === "array" && schema.items) {
|
|
402
|
+
const item = schemaToPythonType(
|
|
403
|
+
schema.items,
|
|
404
|
+
parentClass,
|
|
405
|
+
propKey,
|
|
406
|
+
collected
|
|
407
|
+
);
|
|
408
|
+
return hasNull ? `list[${item}] | None` : `list[${item}]`;
|
|
409
|
+
}
|
|
410
|
+
const base = nonNull.length === 1 ? pythonPrimitiveType(nonNull[0]) : nonNull.map(pythonPrimitiveType).join(" | ");
|
|
411
|
+
return hasNull ? `${base} | None` : base;
|
|
412
|
+
}
|
|
413
|
+
switch (schema.type) {
|
|
414
|
+
case "string":
|
|
415
|
+
case "number":
|
|
416
|
+
case "integer":
|
|
417
|
+
case "boolean":
|
|
418
|
+
case "null":
|
|
419
|
+
return pythonPrimitiveType(schema.type);
|
|
420
|
+
case "array": {
|
|
421
|
+
const item = schema.items ? schemaToPythonType(schema.items, parentClass, propKey, collected) : "Any";
|
|
422
|
+
return `list[${item}]`;
|
|
423
|
+
}
|
|
424
|
+
case "object": {
|
|
425
|
+
if (!schema.properties || Object.keys(schema.properties).length === 0) {
|
|
426
|
+
return "dict[str, Any]";
|
|
427
|
+
}
|
|
428
|
+
const clsName = `${parentClass}${propToPascal(propKey)}`;
|
|
429
|
+
collected.push(buildTypedDict(clsName, schema, collected));
|
|
430
|
+
return clsName;
|
|
431
|
+
}
|
|
432
|
+
default:
|
|
433
|
+
if (schema.properties) {
|
|
434
|
+
const clsName = `${parentClass}${propToPascal(propKey)}`;
|
|
435
|
+
collected.push(buildTypedDict(clsName, schema, collected));
|
|
436
|
+
return clsName;
|
|
437
|
+
}
|
|
438
|
+
return "Any";
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
function buildTypedDict(className, schema, collected) {
|
|
442
|
+
const props = schema.properties || {};
|
|
443
|
+
const requiredSet = new Set(schema.required || []);
|
|
444
|
+
const lines = [];
|
|
445
|
+
const desc = schema.description;
|
|
446
|
+
if (desc) {
|
|
447
|
+
lines.push(`class ${className}(TypedDict):`);
|
|
448
|
+
lines.push(` """${desc}"""`);
|
|
449
|
+
} else {
|
|
450
|
+
lines.push(`class ${className}(TypedDict):`);
|
|
451
|
+
}
|
|
452
|
+
const entries = Object.entries(props);
|
|
453
|
+
if (entries.length === 0) {
|
|
454
|
+
lines.push(" pass");
|
|
455
|
+
return lines.join("\n");
|
|
456
|
+
}
|
|
457
|
+
for (const [key, propSchema] of entries) {
|
|
458
|
+
const pyType = schemaToPythonType(
|
|
459
|
+
propSchema,
|
|
460
|
+
className,
|
|
461
|
+
key,
|
|
462
|
+
collected
|
|
463
|
+
);
|
|
464
|
+
const isRequired = requiredSet.has(key);
|
|
465
|
+
const annotation = isRequired ? pyType : `NotRequired[${pyType}]`;
|
|
466
|
+
const propDesc = propSchema.description;
|
|
467
|
+
if (propDesc) {
|
|
468
|
+
const prefix = ` ${key}: ${annotation} # `;
|
|
469
|
+
const maxDesc = 99 - prefix.length;
|
|
470
|
+
if (maxDesc > 10) {
|
|
471
|
+
const shortDesc = propDesc.length > maxDesc ? propDesc.substring(0, maxDesc - 3) + "..." : propDesc;
|
|
472
|
+
lines.push(`${prefix}${shortDesc}`);
|
|
473
|
+
} else {
|
|
474
|
+
lines.push(` ${key}: ${annotation}`);
|
|
475
|
+
}
|
|
476
|
+
} else {
|
|
477
|
+
lines.push(` ${key}: ${annotation}`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return lines.join("\n");
|
|
481
|
+
}
|
|
482
|
+
function generatePythonToolTypes(tools) {
|
|
483
|
+
if (Object.keys(tools).length === 0) return null;
|
|
484
|
+
const collected = [];
|
|
485
|
+
for (const [toolName, schema] of Object.entries(tools)) {
|
|
486
|
+
const argsName = `${getToolInterfaceName(toolName)}Args`;
|
|
487
|
+
if (schema.parameters && schema.parameters.properties) {
|
|
488
|
+
collected.push(buildTypedDict(argsName, schema.parameters, collected));
|
|
489
|
+
} else {
|
|
490
|
+
collected.push(`class ${argsName}(TypedDict):
|
|
491
|
+
pass`);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
const toolLines = Object.keys(tools).map((name) => ` ${name}: ${getToolInterfaceName(name)}Args`).join("\n");
|
|
495
|
+
collected.push(`class Tools(TypedDict):
|
|
496
|
+
${toolLines}`);
|
|
497
|
+
return collected.join("\n\n\n");
|
|
498
|
+
}
|
|
499
|
+
function buildPythonHeader(body) {
|
|
500
|
+
const imports = ["TypedDict"];
|
|
501
|
+
if (body.includes("NotRequired[")) imports.push("NotRequired");
|
|
502
|
+
if (body.includes("Literal[")) imports.push("Literal");
|
|
503
|
+
if (/\bAny\b/.test(body)) imports.push("Any");
|
|
504
|
+
imports.sort();
|
|
505
|
+
return `# Auto-generated types from AgentMark
|
|
506
|
+
# Do not edit this file directly
|
|
507
|
+
|
|
508
|
+
from __future__ import annotations
|
|
509
|
+
|
|
510
|
+
from typing import ${imports.join(", ")}
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
`;
|
|
514
|
+
}
|
|
515
|
+
async function generatePythonTypeDefinitionsV1_0(prompts) {
|
|
516
|
+
const allClasses = [];
|
|
517
|
+
const typeMapping = [];
|
|
518
|
+
for (const prompt of prompts) {
|
|
519
|
+
const { path: promptPath, input_schema } = prompt;
|
|
520
|
+
const name = getInterfaceName(promptPath);
|
|
521
|
+
try {
|
|
522
|
+
let kind = "text";
|
|
523
|
+
let outputSchema = null;
|
|
524
|
+
let tools = {};
|
|
525
|
+
if ("text_config" in prompt) {
|
|
526
|
+
kind = "text";
|
|
527
|
+
tools = prompt.text_config.tools || {};
|
|
528
|
+
} else if ("object_config" in prompt) {
|
|
529
|
+
kind = "object";
|
|
530
|
+
tools = prompt.object_config.tools || {};
|
|
531
|
+
outputSchema = prompt.object_config.schema;
|
|
532
|
+
} else if ("image_config" in prompt) {
|
|
533
|
+
kind = "image";
|
|
534
|
+
tools = prompt.image_config.tools || {};
|
|
535
|
+
}
|
|
536
|
+
const inputCollected = [];
|
|
537
|
+
if (input_schema && input_schema.properties) {
|
|
538
|
+
inputCollected.push(
|
|
539
|
+
buildTypedDict(`${name}In`, input_schema, inputCollected)
|
|
540
|
+
);
|
|
541
|
+
} else {
|
|
542
|
+
inputCollected.push(`class ${name}In(TypedDict):
|
|
543
|
+
pass`);
|
|
544
|
+
}
|
|
545
|
+
allClasses.push(...inputCollected);
|
|
546
|
+
const outputCollected = [];
|
|
547
|
+
if (outputSchema && outputSchema.properties) {
|
|
548
|
+
outputCollected.push(
|
|
549
|
+
buildTypedDict(`${name}Out`, outputSchema, outputCollected)
|
|
550
|
+
);
|
|
551
|
+
} else if (kind === "object") {
|
|
552
|
+
outputCollected.push(`class ${name}Out(TypedDict):
|
|
553
|
+
pass`);
|
|
554
|
+
} else {
|
|
555
|
+
outputCollected.push(`${name}Out = str`);
|
|
556
|
+
}
|
|
557
|
+
allClasses.push(...outputCollected);
|
|
558
|
+
if (Object.keys(tools).length > 0) {
|
|
559
|
+
const toolOutput = generatePythonToolTypes(tools);
|
|
560
|
+
if (toolOutput) allClasses.push(toolOutput);
|
|
561
|
+
}
|
|
562
|
+
const toolsLine = Object.keys(tools).length > 0 ? "\n tools: NotRequired[list[str]]" : "";
|
|
563
|
+
allClasses.push(
|
|
564
|
+
`class ${name}(TypedDict):
|
|
565
|
+
kind: Literal['${kind}']
|
|
566
|
+
input: ${name}In
|
|
567
|
+
output: ${name}Out${toolsLine}`
|
|
568
|
+
);
|
|
569
|
+
typeMapping.push({ path: promptPath, name });
|
|
570
|
+
const withoutMdx = promptPath.replace(/\.mdx$/, "");
|
|
571
|
+
if (withoutMdx !== promptPath)
|
|
572
|
+
typeMapping.push({ path: withoutMdx, name });
|
|
573
|
+
const shortName = promptPath.replace(/\.prompt\.mdx$/, "");
|
|
574
|
+
if (shortName !== promptPath && shortName !== withoutMdx) {
|
|
575
|
+
typeMapping.push({ path: shortName, name });
|
|
576
|
+
}
|
|
577
|
+
} catch (error) {
|
|
578
|
+
console.error(`Error processing ${promptPath}:`, error);
|
|
579
|
+
allClasses.push(`class ${name}In(TypedDict):
|
|
580
|
+
pass`);
|
|
581
|
+
allClasses.push(`${name}Out = str`);
|
|
582
|
+
allClasses.push(
|
|
583
|
+
`class ${name}(TypedDict):
|
|
584
|
+
kind: Literal['text']
|
|
585
|
+
input: ${name}In
|
|
586
|
+
output: ${name}Out`
|
|
587
|
+
);
|
|
588
|
+
typeMapping.push({ path: promptPath, name });
|
|
589
|
+
const withoutMdx = promptPath.replace(/\.mdx$/, "");
|
|
590
|
+
if (withoutMdx !== promptPath)
|
|
591
|
+
typeMapping.push({ path: withoutMdx, name });
|
|
592
|
+
const shortName = promptPath.replace(/\.prompt\.mdx$/, "");
|
|
593
|
+
if (shortName !== promptPath && shortName !== withoutMdx) {
|
|
594
|
+
typeMapping.push({ path: shortName, name });
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
const mappingLines = typeMapping.map(({ path: path2, name }) => ` '${path2}': ${name}`).join(",\n");
|
|
599
|
+
allClasses.push(
|
|
600
|
+
`AgentmarkTypes = TypedDict('AgentmarkTypes', {
|
|
601
|
+
${mappingLines},
|
|
602
|
+
})`
|
|
603
|
+
);
|
|
604
|
+
const body = allClasses.join("\n\n\n") + "\n";
|
|
605
|
+
return buildPythonHeader(body) + body;
|
|
606
|
+
}
|
|
607
|
+
async function generatePythonTypeDefinitionsV0(prompts) {
|
|
608
|
+
var _a, _b;
|
|
609
|
+
const allClasses = [];
|
|
610
|
+
const typeMapping = [];
|
|
611
|
+
for (const prompt of prompts) {
|
|
612
|
+
const { path: promptPath, metadata, input_schema } = prompt;
|
|
613
|
+
const name = getInterfaceName(promptPath);
|
|
614
|
+
try {
|
|
615
|
+
const inputCollected = [];
|
|
616
|
+
if (input_schema && input_schema.properties) {
|
|
617
|
+
inputCollected.push(
|
|
618
|
+
buildTypedDict(`${name}In`, input_schema, inputCollected)
|
|
619
|
+
);
|
|
620
|
+
} else {
|
|
621
|
+
inputCollected.push(`class ${name}In(TypedDict):
|
|
622
|
+
pass`);
|
|
623
|
+
}
|
|
624
|
+
allClasses.push(...inputCollected);
|
|
625
|
+
const outputSchema = (_b = (_a = metadata == null ? void 0 : metadata.model) == null ? void 0 : _a.settings) == null ? void 0 : _b.schema;
|
|
626
|
+
const outputCollected = [];
|
|
627
|
+
if (outputSchema && outputSchema.properties) {
|
|
628
|
+
outputCollected.push(
|
|
629
|
+
buildTypedDict(`${name}Out`, outputSchema, outputCollected)
|
|
630
|
+
);
|
|
631
|
+
} else {
|
|
632
|
+
outputCollected.push(`${name}Out = str`);
|
|
633
|
+
}
|
|
634
|
+
allClasses.push(...outputCollected);
|
|
635
|
+
allClasses.push(
|
|
636
|
+
`class ${name}(TypedDict):
|
|
637
|
+
input: ${name}In
|
|
638
|
+
output: ${name}Out`
|
|
639
|
+
);
|
|
640
|
+
typeMapping.push({ path: promptPath, name });
|
|
641
|
+
const withoutMdx = promptPath.replace(/\.mdx$/, "");
|
|
642
|
+
if (withoutMdx !== promptPath)
|
|
643
|
+
typeMapping.push({ path: withoutMdx, name });
|
|
644
|
+
const shortName = promptPath.replace(/\.prompt\.mdx$/, "");
|
|
645
|
+
if (shortName !== promptPath && shortName !== withoutMdx) {
|
|
646
|
+
typeMapping.push({ path: shortName, name });
|
|
647
|
+
}
|
|
648
|
+
} catch (error) {
|
|
649
|
+
console.error(`Error processing ${promptPath}:`, error);
|
|
650
|
+
allClasses.push(`class ${name}In(TypedDict):
|
|
651
|
+
pass`);
|
|
652
|
+
allClasses.push(`${name}Out = str`);
|
|
653
|
+
allClasses.push(
|
|
654
|
+
`class ${name}(TypedDict):
|
|
655
|
+
input: ${name}In
|
|
656
|
+
output: ${name}Out`
|
|
657
|
+
);
|
|
658
|
+
typeMapping.push({ path: promptPath, name });
|
|
659
|
+
const withoutMdx = promptPath.replace(/\.mdx$/, "");
|
|
660
|
+
if (withoutMdx !== promptPath)
|
|
661
|
+
typeMapping.push({ path: withoutMdx, name });
|
|
662
|
+
const shortName = promptPath.replace(/\.prompt\.mdx$/, "");
|
|
663
|
+
if (shortName !== promptPath && shortName !== withoutMdx) {
|
|
664
|
+
typeMapping.push({ path: shortName, name });
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
const mappingLines = typeMapping.map(({ path: path2, name }) => ` '${path2}': ${name}`).join(",\n");
|
|
669
|
+
allClasses.push(
|
|
670
|
+
`AgentmarkTypes = TypedDict('AgentmarkTypes', {
|
|
671
|
+
${mappingLines},
|
|
672
|
+
})`
|
|
673
|
+
);
|
|
674
|
+
const body = allClasses.join("\n\n\n") + "\n";
|
|
675
|
+
return buildPythonHeader(body) + body;
|
|
676
|
+
}
|
|
677
|
+
async function generateTypeDefinitions(prompts, language = "typescript") {
|
|
678
|
+
if (language === "python") {
|
|
679
|
+
if (prompts[0].version === "1.0") {
|
|
680
|
+
return generatePythonTypeDefinitionsV1_0(prompts);
|
|
681
|
+
}
|
|
682
|
+
return generatePythonTypeDefinitionsV0(prompts);
|
|
683
|
+
}
|
|
364
684
|
if (prompts[0].version === "1.0") {
|
|
365
685
|
return generateTypeDefinitionsV1_0(prompts);
|
|
366
686
|
}
|
|
@@ -567,6 +887,7 @@ var KNOWN_METADATA_FIELDS = /* @__PURE__ */ new Set([
|
|
|
567
887
|
"dataset_path",
|
|
568
888
|
"dataset_item_name",
|
|
569
889
|
"dataset_expected_output",
|
|
890
|
+
"dataset_input",
|
|
570
891
|
"prompt_name",
|
|
571
892
|
"props",
|
|
572
893
|
"commit_sha"
|
|
@@ -1354,10 +1675,12 @@ function parseAgentMarkAttributes(attributes, prefix = "agentmark.") {
|
|
|
1354
1675
|
if (get("trace_name")) result.traceName = String(get("trace_name"));
|
|
1355
1676
|
if (get("prompt_name")) result.promptName = String(get("prompt_name"));
|
|
1356
1677
|
if (get("props")) result.props = String(get("props"));
|
|
1678
|
+
if (get("span.kind")) result.kind = String(get("span.kind"));
|
|
1357
1679
|
if (get("dataset_run_id")) result.datasetRunId = String(get("dataset_run_id"));
|
|
1358
1680
|
if (get("dataset_run_name")) result.datasetRunName = String(get("dataset_run_name"));
|
|
1359
1681
|
if (get("dataset_item_name")) result.datasetItemName = String(get("dataset_item_name"));
|
|
1360
1682
|
if (get("dataset_expected_output")) result.datasetExpectedOutput = String(get("dataset_expected_output"));
|
|
1683
|
+
if (get("dataset_input")) result.datasetInput = String(get("dataset_input"));
|
|
1361
1684
|
if (get("dataset_path")) result.datasetPath = String(get("dataset_path"));
|
|
1362
1685
|
return result;
|
|
1363
1686
|
}
|
|
@@ -1470,6 +1793,10 @@ var AgentMarkTransformer = class {
|
|
|
1470
1793
|
if (result.inputTokens !== void 0 && result.outputTokens !== void 0) {
|
|
1471
1794
|
result.totalTokens = result.inputTokens + result.outputTokens;
|
|
1472
1795
|
}
|
|
1796
|
+
const costUsd = attributes["agentmark.usage.cost_usd"];
|
|
1797
|
+
if (typeof costUsd === "number" && costUsd > 0) {
|
|
1798
|
+
result.cost = costUsd;
|
|
1799
|
+
}
|
|
1473
1800
|
const finishReasons = attributes[GenAIAttributes.RESPONSE_FINISH_REASONS];
|
|
1474
1801
|
if (finishReasons) {
|
|
1475
1802
|
try {
|
|
@@ -1515,6 +1842,22 @@ var AgentMarkTransformer = class {
|
|
|
1515
1842
|
const responseOutput = attributes[GenAIAttributes.RESPONSE_OUTPUT];
|
|
1516
1843
|
if (responseOutput && typeof responseOutput === "string") {
|
|
1517
1844
|
result.output = responseOutput;
|
|
1845
|
+
try {
|
|
1846
|
+
result.outputObject = JSON.parse(responseOutput);
|
|
1847
|
+
} catch {
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
const amInput = attributes["agentmark.input"];
|
|
1851
|
+
if (amInput && typeof amInput === "string" && !result.input) {
|
|
1852
|
+
result.input = [{ role: "user", content: amInput }];
|
|
1853
|
+
}
|
|
1854
|
+
const amOutput = attributes["agentmark.output"];
|
|
1855
|
+
if (amOutput && typeof amOutput === "string" && !result.output) {
|
|
1856
|
+
result.output = amOutput;
|
|
1857
|
+
try {
|
|
1858
|
+
result.outputObject = JSON.parse(amOutput);
|
|
1859
|
+
} catch {
|
|
1860
|
+
}
|
|
1518
1861
|
}
|
|
1519
1862
|
const toolName = attributes[GenAIAttributes.TOOL_NAME];
|
|
1520
1863
|
const toolCallId = attributes[GenAIAttributes.TOOL_CALL_ID];
|
|
@@ -1556,6 +1899,194 @@ var AgentMarkTransformer = class {
|
|
|
1556
1899
|
};
|
|
1557
1900
|
var AGENTMARK_SCOPE_NAME = "agentmark";
|
|
1558
1901
|
|
|
1902
|
+
// src/normalizer/transformers/otel-genai/index.ts
|
|
1903
|
+
var Attrs = {
|
|
1904
|
+
// Standard OTel GenAI attributes
|
|
1905
|
+
SYSTEM: "gen_ai.system",
|
|
1906
|
+
PROVIDER_NAME: "gen_ai.provider.name",
|
|
1907
|
+
OPERATION_NAME: "gen_ai.operation.name",
|
|
1908
|
+
REQUEST_MODEL: "gen_ai.request.model",
|
|
1909
|
+
REQUEST_MAX_TOKENS: "gen_ai.request.max_tokens",
|
|
1910
|
+
REQUEST_TEMPERATURE: "gen_ai.request.temperature",
|
|
1911
|
+
RESPONSE_ID: "gen_ai.response.id",
|
|
1912
|
+
RESPONSE_MODEL: "gen_ai.response.model",
|
|
1913
|
+
RESPONSE_FINISH_REASONS: "gen_ai.response.finish_reasons",
|
|
1914
|
+
USAGE_INPUT_TOKENS: "gen_ai.usage.input_tokens",
|
|
1915
|
+
USAGE_OUTPUT_TOKENS: "gen_ai.usage.output_tokens",
|
|
1916
|
+
// v1.37.0+ content attributes
|
|
1917
|
+
INPUT_MESSAGES: "gen_ai.input.messages",
|
|
1918
|
+
OUTPUT_MESSAGES: "gen_ai.output.messages",
|
|
1919
|
+
SYSTEM_INSTRUCTIONS: "gen_ai.system_instructions",
|
|
1920
|
+
TOOL_DEFINITIONS: "gen_ai.tool.definitions",
|
|
1921
|
+
// Tool call attributes (v1.37.0+)
|
|
1922
|
+
TOOL_NAME: "gen_ai.tool.name",
|
|
1923
|
+
TOOL_CALL_ID: "gen_ai.tool.call.id",
|
|
1924
|
+
TOOL_CALL_ARGS: "gen_ai.tool.call.arguments",
|
|
1925
|
+
TOOL_CALL_RESULT: "gen_ai.tool.call.result"
|
|
1926
|
+
};
|
|
1927
|
+
function partsToText(parts) {
|
|
1928
|
+
return parts.filter((p) => p.type === "text" && p.content).map((p) => p.content).join("\n");
|
|
1929
|
+
}
|
|
1930
|
+
function normalizeMessages(raw) {
|
|
1931
|
+
try {
|
|
1932
|
+
const parsed = JSON.parse(raw);
|
|
1933
|
+
if (!Array.isArray(parsed) || parsed.length === 0) return null;
|
|
1934
|
+
const messages = [];
|
|
1935
|
+
for (const msg of parsed) {
|
|
1936
|
+
if (!msg.role) continue;
|
|
1937
|
+
if (msg.content && typeof msg.content === "string") {
|
|
1938
|
+
messages.push(msg);
|
|
1939
|
+
} else if (msg.parts && Array.isArray(msg.parts)) {
|
|
1940
|
+
const text = partsToText(msg.parts);
|
|
1941
|
+
if (text) {
|
|
1942
|
+
messages.push({ role: msg.role, content: text });
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
return messages.length > 0 ? messages : null;
|
|
1947
|
+
} catch {
|
|
1948
|
+
return null;
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
function extractStructuredOutput(raw) {
|
|
1952
|
+
try {
|
|
1953
|
+
const parsed = JSON.parse(raw);
|
|
1954
|
+
if (!Array.isArray(parsed)) return null;
|
|
1955
|
+
for (const msg of parsed) {
|
|
1956
|
+
for (const part of msg.parts || []) {
|
|
1957
|
+
if (part.type === "tool_call" && part.arguments) {
|
|
1958
|
+
return {
|
|
1959
|
+
output: JSON.stringify(part.arguments),
|
|
1960
|
+
outputObject: part.arguments
|
|
1961
|
+
};
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
for (const msg of parsed) {
|
|
1966
|
+
const text = partsToText(msg.parts || []);
|
|
1967
|
+
if (text) return { output: text };
|
|
1968
|
+
}
|
|
1969
|
+
return null;
|
|
1970
|
+
} catch {
|
|
1971
|
+
return null;
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
var OtelGenAiTransformer = class {
|
|
1975
|
+
classify(span, attributes) {
|
|
1976
|
+
if (span.name.startsWith("chat ")) return "GENERATION" /* GENERATION */;
|
|
1977
|
+
if (span.name.startsWith("invoke_agent") || span.name === "agent run") return "SPAN" /* SPAN */;
|
|
1978
|
+
if (span.name.startsWith("execute_tool") || span.name.startsWith("running ")) return "SPAN" /* SPAN */;
|
|
1979
|
+
if (attributes[Attrs.USAGE_INPUT_TOKENS] !== void 0) return "GENERATION" /* GENERATION */;
|
|
1980
|
+
return "SPAN" /* SPAN */;
|
|
1981
|
+
}
|
|
1982
|
+
transform(span, attributes) {
|
|
1983
|
+
const result = {};
|
|
1984
|
+
const model = attributes[Attrs.RESPONSE_MODEL] || attributes[Attrs.REQUEST_MODEL];
|
|
1985
|
+
if (model && typeof model === "string") {
|
|
1986
|
+
result.model = model;
|
|
1987
|
+
}
|
|
1988
|
+
const inputTokens = attributes[Attrs.USAGE_INPUT_TOKENS];
|
|
1989
|
+
const outputTokens = attributes[Attrs.USAGE_OUTPUT_TOKENS];
|
|
1990
|
+
if (typeof inputTokens === "number") result.inputTokens = inputTokens;
|
|
1991
|
+
if (typeof outputTokens === "number") result.outputTokens = outputTokens;
|
|
1992
|
+
if (result.inputTokens !== void 0 && result.outputTokens !== void 0) {
|
|
1993
|
+
result.totalTokens = result.inputTokens + result.outputTokens;
|
|
1994
|
+
}
|
|
1995
|
+
const finishReasons = attributes[Attrs.RESPONSE_FINISH_REASONS];
|
|
1996
|
+
if (Array.isArray(finishReasons) && finishReasons.length > 0) {
|
|
1997
|
+
result.finishReason = finishReasons[0];
|
|
1998
|
+
}
|
|
1999
|
+
const temperature = attributes[Attrs.REQUEST_TEMPERATURE];
|
|
2000
|
+
if (typeof temperature === "number") {
|
|
2001
|
+
result.settings = { ...result.settings, temperature };
|
|
2002
|
+
}
|
|
2003
|
+
const inputMessages = attributes[Attrs.INPUT_MESSAGES];
|
|
2004
|
+
if (inputMessages && typeof inputMessages === "string") {
|
|
2005
|
+
const messages = normalizeMessages(inputMessages);
|
|
2006
|
+
if (messages) result.input = messages;
|
|
2007
|
+
}
|
|
2008
|
+
const outputMessages = attributes[Attrs.OUTPUT_MESSAGES];
|
|
2009
|
+
if (outputMessages && typeof outputMessages === "string") {
|
|
2010
|
+
const extracted = extractStructuredOutput(outputMessages);
|
|
2011
|
+
if (extracted) {
|
|
2012
|
+
result.output = extracted.output;
|
|
2013
|
+
if (extracted.outputObject) {
|
|
2014
|
+
result.outputObject = extracted.outputObject;
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
const allMessages = attributes["pydantic_ai.all_messages"];
|
|
2019
|
+
if (allMessages && typeof allMessages === "string" && !result.input) {
|
|
2020
|
+
const messages = normalizeMessages(allMessages);
|
|
2021
|
+
if (messages) {
|
|
2022
|
+
const userMessages = messages.filter((m) => m.role === "user");
|
|
2023
|
+
if (userMessages.length > 0) {
|
|
2024
|
+
result.input = userMessages;
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
const finalResult = attributes["final_result"];
|
|
2029
|
+
if (finalResult && typeof finalResult === "string" && !result.output) {
|
|
2030
|
+
result.output = finalResult;
|
|
2031
|
+
try {
|
|
2032
|
+
result.outputObject = JSON.parse(finalResult);
|
|
2033
|
+
} catch {
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
const propsStr = attributes["agentmark.props"];
|
|
2037
|
+
if (propsStr && typeof propsStr === "string" && !result.input) {
|
|
2038
|
+
try {
|
|
2039
|
+
const props = JSON.parse(propsStr);
|
|
2040
|
+
result.input = [{ role: "user", content: JSON.stringify(props) }];
|
|
2041
|
+
} catch {
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
const outputStr = attributes["agentmark.output"];
|
|
2045
|
+
if (outputStr && typeof outputStr === "string" && !result.output) {
|
|
2046
|
+
result.output = outputStr;
|
|
2047
|
+
try {
|
|
2048
|
+
result.outputObject = JSON.parse(outputStr);
|
|
2049
|
+
} catch {
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
const toolName = attributes[Attrs.TOOL_NAME];
|
|
2053
|
+
if (toolName && typeof toolName === "string") {
|
|
2054
|
+
result.name = toolName;
|
|
2055
|
+
const toolCall = {
|
|
2056
|
+
type: "tool-call",
|
|
2057
|
+
toolCallId: attributes[Attrs.TOOL_CALL_ID] || "",
|
|
2058
|
+
toolName,
|
|
2059
|
+
args: {}
|
|
2060
|
+
};
|
|
2061
|
+
const toolArgs = attributes[Attrs.TOOL_CALL_ARGS];
|
|
2062
|
+
if (toolArgs && typeof toolArgs === "string") {
|
|
2063
|
+
try {
|
|
2064
|
+
toolCall.args = JSON.parse(toolArgs);
|
|
2065
|
+
} catch {
|
|
2066
|
+
toolCall.args = { raw: toolArgs };
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
const toolResult = attributes[Attrs.TOOL_CALL_RESULT];
|
|
2070
|
+
if (toolResult && typeof toolResult === "string") {
|
|
2071
|
+
toolCall.result = toolResult;
|
|
2072
|
+
}
|
|
2073
|
+
result.toolCalls = [toolCall];
|
|
2074
|
+
}
|
|
2075
|
+
const agentmarkAttrs = parseAgentMarkAttributes(attributes);
|
|
2076
|
+
Object.assign(result, agentmarkAttrs);
|
|
2077
|
+
const parsedMeta = parseMetadata(attributes);
|
|
2078
|
+
if (parsedMeta.metadata && Object.keys(parsedMeta.metadata).length > 0) {
|
|
2079
|
+
result.metadata = { ...result.metadata, ...parsedMeta.metadata };
|
|
2080
|
+
}
|
|
2081
|
+
const customMeta = extractCustomMetadata(attributes);
|
|
2082
|
+
if (Object.keys(customMeta).length > 0) {
|
|
2083
|
+
result.metadata = { ...result.metadata, ...customMeta };
|
|
2084
|
+
}
|
|
2085
|
+
return result;
|
|
2086
|
+
}
|
|
2087
|
+
};
|
|
2088
|
+
OtelGenAiTransformer.SCOPE_NAME = "pydantic-ai";
|
|
2089
|
+
|
|
1559
2090
|
// src/normalizer/converters/otlp-converter.ts
|
|
1560
2091
|
function convertOtlpValue(value) {
|
|
1561
2092
|
var _a;
|
|
@@ -1657,7 +2188,8 @@ var typeClassifier = new TypeClassifier();
|
|
|
1657
2188
|
registry.register("ai", new AiSdkTransformer());
|
|
1658
2189
|
registry.register("default-tracer", new MastraTransformer());
|
|
1659
2190
|
registry.register("agentmark", new AgentMarkTransformer());
|
|
1660
|
-
registry.
|
|
2191
|
+
registry.register("pydantic-ai", new OtelGenAiTransformer());
|
|
2192
|
+
registry.setDefault(new OtelGenAiTransformer());
|
|
1661
2193
|
function normalizeSpan(resource, scope, span) {
|
|
1662
2194
|
var _a, _b, _c;
|
|
1663
2195
|
const allAttributes = {
|
|
@@ -1732,6 +2264,7 @@ function normalizeOtlpSpans(resourceSpans) {
|
|
|
1732
2264
|
AiSdkTransformer,
|
|
1733
2265
|
ClaudeAgentTransformer,
|
|
1734
2266
|
MastraTransformer,
|
|
2267
|
+
OtelGenAiTransformer,
|
|
1735
2268
|
SpanType,
|
|
1736
2269
|
TransformerRegistry,
|
|
1737
2270
|
TypeClassifier,
|