@agentmark-ai/shared-utils 0.3.0 → 0.3.2
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 +48 -3
- package/dist/index.d.ts +48 -3
- package/dist/index.js +621 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +618 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -35,6 +35,8 @@ __export(index_exports, {
|
|
|
35
35
|
AiSdkTransformer: () => AiSdkTransformer,
|
|
36
36
|
ClaudeAgentTransformer: () => AgentMarkTransformer,
|
|
37
37
|
MastraTransformer: () => MastraTransformer,
|
|
38
|
+
OtelGenAiTransformer: () => OtelGenAiTransformer,
|
|
39
|
+
SEMANTIC_KINDS: () => SEMANTIC_KINDS,
|
|
38
40
|
SpanType: () => SpanType,
|
|
39
41
|
TransformerRegistry: () => TransformerRegistry,
|
|
40
42
|
TypeClassifier: () => TypeClassifier,
|
|
@@ -54,6 +56,7 @@ __export(index_exports, {
|
|
|
54
56
|
parseMetadata: () => parseMetadata,
|
|
55
57
|
parseTokens: () => parseTokens,
|
|
56
58
|
registry: () => registry,
|
|
59
|
+
resolveSemanticKind: () => resolveSemanticKind,
|
|
57
60
|
toFrontMatter: () => toFrontMatter,
|
|
58
61
|
typeClassifier: () => typeClassifier,
|
|
59
62
|
verifySignature: () => verifySignature
|
|
@@ -360,7 +363,326 @@ ${typeMapping.join(",\n")}
|
|
|
360
363
|
var isNewFormat = (frontmatter) => {
|
|
361
364
|
return frontmatter["text_config"] || frontmatter["object_config"] || frontmatter["image_config"];
|
|
362
365
|
};
|
|
363
|
-
|
|
366
|
+
function pythonPrimitiveType(schemaType) {
|
|
367
|
+
const map = {
|
|
368
|
+
string: "str",
|
|
369
|
+
number: "float",
|
|
370
|
+
integer: "int",
|
|
371
|
+
boolean: "bool",
|
|
372
|
+
null: "None"
|
|
373
|
+
};
|
|
374
|
+
return map[schemaType] || "Any";
|
|
375
|
+
}
|
|
376
|
+
function propToPascal(prop) {
|
|
377
|
+
return prop.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
378
|
+
}
|
|
379
|
+
function schemaToPythonType(schema, parentClass, propKey, collected) {
|
|
380
|
+
if (!schema) return "Any";
|
|
381
|
+
const union = schema.anyOf || schema.oneOf;
|
|
382
|
+
if (union) {
|
|
383
|
+
const nullIdx = union.findIndex((v) => v.type === "null");
|
|
384
|
+
const hasNull = nullIdx >= 0;
|
|
385
|
+
const others = union.filter((_, i) => i !== nullIdx);
|
|
386
|
+
if (hasNull && others.length === 1) {
|
|
387
|
+
return `${schemaToPythonType(others[0], parentClass, propKey, collected)} | None`;
|
|
388
|
+
}
|
|
389
|
+
const parts = others.map(
|
|
390
|
+
(v, i) => schemaToPythonType(v, parentClass, `${propKey}${i}`, collected)
|
|
391
|
+
);
|
|
392
|
+
if (hasNull) parts.push("None");
|
|
393
|
+
return parts.join(" | ");
|
|
394
|
+
}
|
|
395
|
+
if (Array.isArray(schema.type)) {
|
|
396
|
+
const hasNull = schema.type.includes("null");
|
|
397
|
+
const nonNull = schema.type.filter((t) => t !== "null");
|
|
398
|
+
if (nonNull.length === 1 && nonNull[0] === "object" && schema.properties) {
|
|
399
|
+
const clsName = `${parentClass}${propToPascal(propKey)}`;
|
|
400
|
+
collected.push(buildTypedDict(clsName, schema, collected));
|
|
401
|
+
return hasNull ? `${clsName} | None` : clsName;
|
|
402
|
+
}
|
|
403
|
+
if (nonNull.length === 1 && nonNull[0] === "array" && schema.items) {
|
|
404
|
+
const item = schemaToPythonType(
|
|
405
|
+
schema.items,
|
|
406
|
+
parentClass,
|
|
407
|
+
propKey,
|
|
408
|
+
collected
|
|
409
|
+
);
|
|
410
|
+
return hasNull ? `list[${item}] | None` : `list[${item}]`;
|
|
411
|
+
}
|
|
412
|
+
const base = nonNull.length === 1 ? pythonPrimitiveType(nonNull[0]) : nonNull.map(pythonPrimitiveType).join(" | ");
|
|
413
|
+
return hasNull ? `${base} | None` : base;
|
|
414
|
+
}
|
|
415
|
+
switch (schema.type) {
|
|
416
|
+
case "string":
|
|
417
|
+
case "number":
|
|
418
|
+
case "integer":
|
|
419
|
+
case "boolean":
|
|
420
|
+
case "null":
|
|
421
|
+
return pythonPrimitiveType(schema.type);
|
|
422
|
+
case "array": {
|
|
423
|
+
const item = schema.items ? schemaToPythonType(schema.items, parentClass, propKey, collected) : "Any";
|
|
424
|
+
return `list[${item}]`;
|
|
425
|
+
}
|
|
426
|
+
case "object": {
|
|
427
|
+
if (!schema.properties || Object.keys(schema.properties).length === 0) {
|
|
428
|
+
return "dict[str, Any]";
|
|
429
|
+
}
|
|
430
|
+
const clsName = `${parentClass}${propToPascal(propKey)}`;
|
|
431
|
+
collected.push(buildTypedDict(clsName, schema, collected));
|
|
432
|
+
return clsName;
|
|
433
|
+
}
|
|
434
|
+
default:
|
|
435
|
+
if (schema.properties) {
|
|
436
|
+
const clsName = `${parentClass}${propToPascal(propKey)}`;
|
|
437
|
+
collected.push(buildTypedDict(clsName, schema, collected));
|
|
438
|
+
return clsName;
|
|
439
|
+
}
|
|
440
|
+
return "Any";
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function buildTypedDict(className, schema, collected) {
|
|
444
|
+
const props = schema.properties || {};
|
|
445
|
+
const requiredSet = new Set(schema.required || []);
|
|
446
|
+
const lines = [];
|
|
447
|
+
const desc = schema.description;
|
|
448
|
+
if (desc) {
|
|
449
|
+
lines.push(`class ${className}(TypedDict):`);
|
|
450
|
+
lines.push(` """${desc}"""`);
|
|
451
|
+
} else {
|
|
452
|
+
lines.push(`class ${className}(TypedDict):`);
|
|
453
|
+
}
|
|
454
|
+
const entries = Object.entries(props);
|
|
455
|
+
if (entries.length === 0) {
|
|
456
|
+
lines.push(" pass");
|
|
457
|
+
return lines.join("\n");
|
|
458
|
+
}
|
|
459
|
+
for (const [key, propSchema] of entries) {
|
|
460
|
+
const pyType = schemaToPythonType(
|
|
461
|
+
propSchema,
|
|
462
|
+
className,
|
|
463
|
+
key,
|
|
464
|
+
collected
|
|
465
|
+
);
|
|
466
|
+
const isRequired = requiredSet.has(key);
|
|
467
|
+
const annotation = isRequired ? pyType : `NotRequired[${pyType}]`;
|
|
468
|
+
const propDesc = propSchema.description;
|
|
469
|
+
if (propDesc) {
|
|
470
|
+
const prefix = ` ${key}: ${annotation} # `;
|
|
471
|
+
const maxDesc = 99 - prefix.length;
|
|
472
|
+
if (maxDesc > 10) {
|
|
473
|
+
const shortDesc = propDesc.length > maxDesc ? propDesc.substring(0, maxDesc - 3) + "..." : propDesc;
|
|
474
|
+
lines.push(`${prefix}${shortDesc}`);
|
|
475
|
+
} else {
|
|
476
|
+
lines.push(` ${key}: ${annotation}`);
|
|
477
|
+
}
|
|
478
|
+
} else {
|
|
479
|
+
lines.push(` ${key}: ${annotation}`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return lines.join("\n");
|
|
483
|
+
}
|
|
484
|
+
function generatePythonToolTypes(tools) {
|
|
485
|
+
if (Object.keys(tools).length === 0) return null;
|
|
486
|
+
const collected = [];
|
|
487
|
+
for (const [toolName, schema] of Object.entries(tools)) {
|
|
488
|
+
const argsName = `${getToolInterfaceName(toolName)}Args`;
|
|
489
|
+
if (schema.parameters && schema.parameters.properties) {
|
|
490
|
+
collected.push(buildTypedDict(argsName, schema.parameters, collected));
|
|
491
|
+
} else {
|
|
492
|
+
collected.push(`class ${argsName}(TypedDict):
|
|
493
|
+
pass`);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
const toolLines = Object.keys(tools).map((name) => ` ${name}: ${getToolInterfaceName(name)}Args`).join("\n");
|
|
497
|
+
collected.push(`class Tools(TypedDict):
|
|
498
|
+
${toolLines}`);
|
|
499
|
+
return collected.join("\n\n\n");
|
|
500
|
+
}
|
|
501
|
+
function buildPythonHeader(body) {
|
|
502
|
+
const imports = ["TypedDict"];
|
|
503
|
+
if (body.includes("NotRequired[")) imports.push("NotRequired");
|
|
504
|
+
if (body.includes("Literal[")) imports.push("Literal");
|
|
505
|
+
if (/\bAny\b/.test(body)) imports.push("Any");
|
|
506
|
+
imports.sort();
|
|
507
|
+
return `# Auto-generated types from AgentMark
|
|
508
|
+
# Do not edit this file directly
|
|
509
|
+
|
|
510
|
+
from __future__ import annotations
|
|
511
|
+
|
|
512
|
+
from typing import ${imports.join(", ")}
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
`;
|
|
516
|
+
}
|
|
517
|
+
async function generatePythonTypeDefinitionsV1_0(prompts) {
|
|
518
|
+
const allClasses = [];
|
|
519
|
+
const typeMapping = [];
|
|
520
|
+
for (const prompt of prompts) {
|
|
521
|
+
const { path: promptPath, input_schema } = prompt;
|
|
522
|
+
const name = getInterfaceName(promptPath);
|
|
523
|
+
try {
|
|
524
|
+
let kind = "text";
|
|
525
|
+
let outputSchema = null;
|
|
526
|
+
let tools = {};
|
|
527
|
+
if ("text_config" in prompt) {
|
|
528
|
+
kind = "text";
|
|
529
|
+
tools = prompt.text_config.tools || {};
|
|
530
|
+
} else if ("object_config" in prompt) {
|
|
531
|
+
kind = "object";
|
|
532
|
+
tools = prompt.object_config.tools || {};
|
|
533
|
+
outputSchema = prompt.object_config.schema;
|
|
534
|
+
} else if ("image_config" in prompt) {
|
|
535
|
+
kind = "image";
|
|
536
|
+
tools = prompt.image_config.tools || {};
|
|
537
|
+
}
|
|
538
|
+
const inputCollected = [];
|
|
539
|
+
if (input_schema && input_schema.properties) {
|
|
540
|
+
inputCollected.push(
|
|
541
|
+
buildTypedDict(`${name}In`, input_schema, inputCollected)
|
|
542
|
+
);
|
|
543
|
+
} else {
|
|
544
|
+
inputCollected.push(`class ${name}In(TypedDict):
|
|
545
|
+
pass`);
|
|
546
|
+
}
|
|
547
|
+
allClasses.push(...inputCollected);
|
|
548
|
+
const outputCollected = [];
|
|
549
|
+
if (outputSchema && outputSchema.properties) {
|
|
550
|
+
outputCollected.push(
|
|
551
|
+
buildTypedDict(`${name}Out`, outputSchema, outputCollected)
|
|
552
|
+
);
|
|
553
|
+
} else if (kind === "object") {
|
|
554
|
+
outputCollected.push(`class ${name}Out(TypedDict):
|
|
555
|
+
pass`);
|
|
556
|
+
} else {
|
|
557
|
+
outputCollected.push(`${name}Out = str`);
|
|
558
|
+
}
|
|
559
|
+
allClasses.push(...outputCollected);
|
|
560
|
+
if (Object.keys(tools).length > 0) {
|
|
561
|
+
const toolOutput = generatePythonToolTypes(tools);
|
|
562
|
+
if (toolOutput) allClasses.push(toolOutput);
|
|
563
|
+
}
|
|
564
|
+
const toolsLine = Object.keys(tools).length > 0 ? "\n tools: NotRequired[list[str]]" : "";
|
|
565
|
+
allClasses.push(
|
|
566
|
+
`class ${name}(TypedDict):
|
|
567
|
+
kind: Literal['${kind}']
|
|
568
|
+
input: ${name}In
|
|
569
|
+
output: ${name}Out${toolsLine}`
|
|
570
|
+
);
|
|
571
|
+
typeMapping.push({ path: promptPath, name });
|
|
572
|
+
const withoutMdx = promptPath.replace(/\.mdx$/, "");
|
|
573
|
+
if (withoutMdx !== promptPath)
|
|
574
|
+
typeMapping.push({ path: withoutMdx, name });
|
|
575
|
+
const shortName = promptPath.replace(/\.prompt\.mdx$/, "");
|
|
576
|
+
if (shortName !== promptPath && shortName !== withoutMdx) {
|
|
577
|
+
typeMapping.push({ path: shortName, name });
|
|
578
|
+
}
|
|
579
|
+
} catch (error) {
|
|
580
|
+
console.error(`Error processing ${promptPath}:`, error);
|
|
581
|
+
allClasses.push(`class ${name}In(TypedDict):
|
|
582
|
+
pass`);
|
|
583
|
+
allClasses.push(`${name}Out = str`);
|
|
584
|
+
allClasses.push(
|
|
585
|
+
`class ${name}(TypedDict):
|
|
586
|
+
kind: Literal['text']
|
|
587
|
+
input: ${name}In
|
|
588
|
+
output: ${name}Out`
|
|
589
|
+
);
|
|
590
|
+
typeMapping.push({ path: promptPath, name });
|
|
591
|
+
const withoutMdx = promptPath.replace(/\.mdx$/, "");
|
|
592
|
+
if (withoutMdx !== promptPath)
|
|
593
|
+
typeMapping.push({ path: withoutMdx, name });
|
|
594
|
+
const shortName = promptPath.replace(/\.prompt\.mdx$/, "");
|
|
595
|
+
if (shortName !== promptPath && shortName !== withoutMdx) {
|
|
596
|
+
typeMapping.push({ path: shortName, name });
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
const mappingLines = typeMapping.map(({ path: path2, name }) => ` '${path2}': ${name}`).join(",\n");
|
|
601
|
+
allClasses.push(
|
|
602
|
+
`AgentmarkTypes = TypedDict('AgentmarkTypes', {
|
|
603
|
+
${mappingLines},
|
|
604
|
+
})`
|
|
605
|
+
);
|
|
606
|
+
const body = allClasses.join("\n\n\n") + "\n";
|
|
607
|
+
return buildPythonHeader(body) + body;
|
|
608
|
+
}
|
|
609
|
+
async function generatePythonTypeDefinitionsV0(prompts) {
|
|
610
|
+
var _a, _b;
|
|
611
|
+
const allClasses = [];
|
|
612
|
+
const typeMapping = [];
|
|
613
|
+
for (const prompt of prompts) {
|
|
614
|
+
const { path: promptPath, metadata, input_schema } = prompt;
|
|
615
|
+
const name = getInterfaceName(promptPath);
|
|
616
|
+
try {
|
|
617
|
+
const inputCollected = [];
|
|
618
|
+
if (input_schema && input_schema.properties) {
|
|
619
|
+
inputCollected.push(
|
|
620
|
+
buildTypedDict(`${name}In`, input_schema, inputCollected)
|
|
621
|
+
);
|
|
622
|
+
} else {
|
|
623
|
+
inputCollected.push(`class ${name}In(TypedDict):
|
|
624
|
+
pass`);
|
|
625
|
+
}
|
|
626
|
+
allClasses.push(...inputCollected);
|
|
627
|
+
const outputSchema = (_b = (_a = metadata == null ? void 0 : metadata.model) == null ? void 0 : _a.settings) == null ? void 0 : _b.schema;
|
|
628
|
+
const outputCollected = [];
|
|
629
|
+
if (outputSchema && outputSchema.properties) {
|
|
630
|
+
outputCollected.push(
|
|
631
|
+
buildTypedDict(`${name}Out`, outputSchema, outputCollected)
|
|
632
|
+
);
|
|
633
|
+
} else {
|
|
634
|
+
outputCollected.push(`${name}Out = str`);
|
|
635
|
+
}
|
|
636
|
+
allClasses.push(...outputCollected);
|
|
637
|
+
allClasses.push(
|
|
638
|
+
`class ${name}(TypedDict):
|
|
639
|
+
input: ${name}In
|
|
640
|
+
output: ${name}Out`
|
|
641
|
+
);
|
|
642
|
+
typeMapping.push({ path: promptPath, name });
|
|
643
|
+
const withoutMdx = promptPath.replace(/\.mdx$/, "");
|
|
644
|
+
if (withoutMdx !== promptPath)
|
|
645
|
+
typeMapping.push({ path: withoutMdx, name });
|
|
646
|
+
const shortName = promptPath.replace(/\.prompt\.mdx$/, "");
|
|
647
|
+
if (shortName !== promptPath && shortName !== withoutMdx) {
|
|
648
|
+
typeMapping.push({ path: shortName, name });
|
|
649
|
+
}
|
|
650
|
+
} catch (error) {
|
|
651
|
+
console.error(`Error processing ${promptPath}:`, error);
|
|
652
|
+
allClasses.push(`class ${name}In(TypedDict):
|
|
653
|
+
pass`);
|
|
654
|
+
allClasses.push(`${name}Out = str`);
|
|
655
|
+
allClasses.push(
|
|
656
|
+
`class ${name}(TypedDict):
|
|
657
|
+
input: ${name}In
|
|
658
|
+
output: ${name}Out`
|
|
659
|
+
);
|
|
660
|
+
typeMapping.push({ path: promptPath, name });
|
|
661
|
+
const withoutMdx = promptPath.replace(/\.mdx$/, "");
|
|
662
|
+
if (withoutMdx !== promptPath)
|
|
663
|
+
typeMapping.push({ path: withoutMdx, name });
|
|
664
|
+
const shortName = promptPath.replace(/\.prompt\.mdx$/, "");
|
|
665
|
+
if (shortName !== promptPath && shortName !== withoutMdx) {
|
|
666
|
+
typeMapping.push({ path: shortName, name });
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
const mappingLines = typeMapping.map(({ path: path2, name }) => ` '${path2}': ${name}`).join(",\n");
|
|
671
|
+
allClasses.push(
|
|
672
|
+
`AgentmarkTypes = TypedDict('AgentmarkTypes', {
|
|
673
|
+
${mappingLines},
|
|
674
|
+
})`
|
|
675
|
+
);
|
|
676
|
+
const body = allClasses.join("\n\n\n") + "\n";
|
|
677
|
+
return buildPythonHeader(body) + body;
|
|
678
|
+
}
|
|
679
|
+
async function generateTypeDefinitions(prompts, language = "typescript") {
|
|
680
|
+
if (language === "python") {
|
|
681
|
+
if (prompts[0].version === "1.0") {
|
|
682
|
+
return generatePythonTypeDefinitionsV1_0(prompts);
|
|
683
|
+
}
|
|
684
|
+
return generatePythonTypeDefinitionsV0(prompts);
|
|
685
|
+
}
|
|
364
686
|
if (prompts[0].version === "1.0") {
|
|
365
687
|
return generateTypeDefinitionsV1_0(prompts);
|
|
366
688
|
}
|
|
@@ -567,9 +889,9 @@ var KNOWN_METADATA_FIELDS = /* @__PURE__ */ new Set([
|
|
|
567
889
|
"dataset_path",
|
|
568
890
|
"dataset_item_name",
|
|
569
891
|
"dataset_expected_output",
|
|
892
|
+
"dataset_input",
|
|
570
893
|
"prompt_name",
|
|
571
|
-
"props"
|
|
572
|
-
"commit_sha"
|
|
894
|
+
"props"
|
|
573
895
|
]);
|
|
574
896
|
function parseMetadata(attributes, prefix = "agentmark.metadata.") {
|
|
575
897
|
const result = {};
|
|
@@ -1354,10 +1676,12 @@ function parseAgentMarkAttributes(attributes, prefix = "agentmark.") {
|
|
|
1354
1676
|
if (get("trace_name")) result.traceName = String(get("trace_name"));
|
|
1355
1677
|
if (get("prompt_name")) result.promptName = String(get("prompt_name"));
|
|
1356
1678
|
if (get("props")) result.props = String(get("props"));
|
|
1679
|
+
if (get("span.kind")) result.semanticKind = String(get("span.kind"));
|
|
1357
1680
|
if (get("dataset_run_id")) result.datasetRunId = String(get("dataset_run_id"));
|
|
1358
1681
|
if (get("dataset_run_name")) result.datasetRunName = String(get("dataset_run_name"));
|
|
1359
1682
|
if (get("dataset_item_name")) result.datasetItemName = String(get("dataset_item_name"));
|
|
1360
1683
|
if (get("dataset_expected_output")) result.datasetExpectedOutput = String(get("dataset_expected_output"));
|
|
1684
|
+
if (get("dataset_input")) result.datasetInput = String(get("dataset_input"));
|
|
1361
1685
|
if (get("dataset_path")) result.datasetPath = String(get("dataset_path"));
|
|
1362
1686
|
return result;
|
|
1363
1687
|
}
|
|
@@ -1422,6 +1746,9 @@ var AgentMarkTransformer = class {
|
|
|
1422
1746
|
if (operationName === OperationNames.CHAT || operationName === OperationNames.TEXT_COMPLETION) {
|
|
1423
1747
|
return "GENERATION" /* GENERATION */;
|
|
1424
1748
|
}
|
|
1749
|
+
if (operationName === OperationNames.EMBEDDINGS) {
|
|
1750
|
+
return "GENERATION" /* GENERATION */;
|
|
1751
|
+
}
|
|
1425
1752
|
if (span.name === SpanNames.CHAT || span.name.startsWith(SpanNames.CHAT + " ")) {
|
|
1426
1753
|
return "GENERATION" /* GENERATION */;
|
|
1427
1754
|
}
|
|
@@ -1470,6 +1797,10 @@ var AgentMarkTransformer = class {
|
|
|
1470
1797
|
if (result.inputTokens !== void 0 && result.outputTokens !== void 0) {
|
|
1471
1798
|
result.totalTokens = result.inputTokens + result.outputTokens;
|
|
1472
1799
|
}
|
|
1800
|
+
const costUsd = attributes["agentmark.usage.cost_usd"];
|
|
1801
|
+
if (typeof costUsd === "number" && costUsd > 0) {
|
|
1802
|
+
result.cost = costUsd;
|
|
1803
|
+
}
|
|
1473
1804
|
const finishReasons = attributes[GenAIAttributes.RESPONSE_FINISH_REASONS];
|
|
1474
1805
|
if (finishReasons) {
|
|
1475
1806
|
try {
|
|
@@ -1515,6 +1846,22 @@ var AgentMarkTransformer = class {
|
|
|
1515
1846
|
const responseOutput = attributes[GenAIAttributes.RESPONSE_OUTPUT];
|
|
1516
1847
|
if (responseOutput && typeof responseOutput === "string") {
|
|
1517
1848
|
result.output = responseOutput;
|
|
1849
|
+
try {
|
|
1850
|
+
result.outputObject = JSON.parse(responseOutput);
|
|
1851
|
+
} catch {
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
const amInput = attributes["agentmark.input"];
|
|
1855
|
+
if (amInput && typeof amInput === "string" && !result.input) {
|
|
1856
|
+
result.input = [{ role: "user", content: amInput }];
|
|
1857
|
+
}
|
|
1858
|
+
const amOutput = attributes["agentmark.output"];
|
|
1859
|
+
if (amOutput && typeof amOutput === "string" && !result.output) {
|
|
1860
|
+
result.output = amOutput;
|
|
1861
|
+
try {
|
|
1862
|
+
result.outputObject = JSON.parse(amOutput);
|
|
1863
|
+
} catch {
|
|
1864
|
+
}
|
|
1518
1865
|
}
|
|
1519
1866
|
const toolName = attributes[GenAIAttributes.TOOL_NAME];
|
|
1520
1867
|
const toolCallId = attributes[GenAIAttributes.TOOL_CALL_ID];
|
|
@@ -1556,6 +1903,194 @@ var AgentMarkTransformer = class {
|
|
|
1556
1903
|
};
|
|
1557
1904
|
var AGENTMARK_SCOPE_NAME = "agentmark";
|
|
1558
1905
|
|
|
1906
|
+
// src/normalizer/transformers/otel-genai/index.ts
|
|
1907
|
+
var Attrs = {
|
|
1908
|
+
// Standard OTel GenAI attributes
|
|
1909
|
+
SYSTEM: "gen_ai.system",
|
|
1910
|
+
PROVIDER_NAME: "gen_ai.provider.name",
|
|
1911
|
+
OPERATION_NAME: "gen_ai.operation.name",
|
|
1912
|
+
REQUEST_MODEL: "gen_ai.request.model",
|
|
1913
|
+
REQUEST_MAX_TOKENS: "gen_ai.request.max_tokens",
|
|
1914
|
+
REQUEST_TEMPERATURE: "gen_ai.request.temperature",
|
|
1915
|
+
RESPONSE_ID: "gen_ai.response.id",
|
|
1916
|
+
RESPONSE_MODEL: "gen_ai.response.model",
|
|
1917
|
+
RESPONSE_FINISH_REASONS: "gen_ai.response.finish_reasons",
|
|
1918
|
+
USAGE_INPUT_TOKENS: "gen_ai.usage.input_tokens",
|
|
1919
|
+
USAGE_OUTPUT_TOKENS: "gen_ai.usage.output_tokens",
|
|
1920
|
+
// v1.37.0+ content attributes
|
|
1921
|
+
INPUT_MESSAGES: "gen_ai.input.messages",
|
|
1922
|
+
OUTPUT_MESSAGES: "gen_ai.output.messages",
|
|
1923
|
+
SYSTEM_INSTRUCTIONS: "gen_ai.system_instructions",
|
|
1924
|
+
TOOL_DEFINITIONS: "gen_ai.tool.definitions",
|
|
1925
|
+
// Tool call attributes (v1.37.0+)
|
|
1926
|
+
TOOL_NAME: "gen_ai.tool.name",
|
|
1927
|
+
TOOL_CALL_ID: "gen_ai.tool.call.id",
|
|
1928
|
+
TOOL_CALL_ARGS: "gen_ai.tool.call.arguments",
|
|
1929
|
+
TOOL_CALL_RESULT: "gen_ai.tool.call.result"
|
|
1930
|
+
};
|
|
1931
|
+
function partsToText(parts) {
|
|
1932
|
+
return parts.filter((p) => p.type === "text" && p.content).map((p) => p.content).join("\n");
|
|
1933
|
+
}
|
|
1934
|
+
function normalizeMessages(raw) {
|
|
1935
|
+
try {
|
|
1936
|
+
const parsed = JSON.parse(raw);
|
|
1937
|
+
if (!Array.isArray(parsed) || parsed.length === 0) return null;
|
|
1938
|
+
const messages = [];
|
|
1939
|
+
for (const msg of parsed) {
|
|
1940
|
+
if (!msg.role) continue;
|
|
1941
|
+
if (msg.content && typeof msg.content === "string") {
|
|
1942
|
+
messages.push(msg);
|
|
1943
|
+
} else if (msg.parts && Array.isArray(msg.parts)) {
|
|
1944
|
+
const text = partsToText(msg.parts);
|
|
1945
|
+
if (text) {
|
|
1946
|
+
messages.push({ role: msg.role, content: text });
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
return messages.length > 0 ? messages : null;
|
|
1951
|
+
} catch {
|
|
1952
|
+
return null;
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
function extractStructuredOutput(raw) {
|
|
1956
|
+
try {
|
|
1957
|
+
const parsed = JSON.parse(raw);
|
|
1958
|
+
if (!Array.isArray(parsed)) return null;
|
|
1959
|
+
for (const msg of parsed) {
|
|
1960
|
+
for (const part of msg.parts || []) {
|
|
1961
|
+
if (part.type === "tool_call" && part.arguments) {
|
|
1962
|
+
return {
|
|
1963
|
+
output: JSON.stringify(part.arguments),
|
|
1964
|
+
outputObject: part.arguments
|
|
1965
|
+
};
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
for (const msg of parsed) {
|
|
1970
|
+
const text = partsToText(msg.parts || []);
|
|
1971
|
+
if (text) return { output: text };
|
|
1972
|
+
}
|
|
1973
|
+
return null;
|
|
1974
|
+
} catch {
|
|
1975
|
+
return null;
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
var OtelGenAiTransformer = class {
|
|
1979
|
+
classify(span, attributes) {
|
|
1980
|
+
if (span.name.startsWith("chat ")) return "GENERATION" /* GENERATION */;
|
|
1981
|
+
if (span.name.startsWith("invoke_agent") || span.name === "agent run") return "SPAN" /* SPAN */;
|
|
1982
|
+
if (span.name.startsWith("execute_tool") || span.name.startsWith("running ")) return "SPAN" /* SPAN */;
|
|
1983
|
+
if (attributes[Attrs.USAGE_INPUT_TOKENS] !== void 0) return "GENERATION" /* GENERATION */;
|
|
1984
|
+
return "SPAN" /* SPAN */;
|
|
1985
|
+
}
|
|
1986
|
+
transform(span, attributes) {
|
|
1987
|
+
const result = {};
|
|
1988
|
+
const model = attributes[Attrs.RESPONSE_MODEL] || attributes[Attrs.REQUEST_MODEL];
|
|
1989
|
+
if (model && typeof model === "string") {
|
|
1990
|
+
result.model = model;
|
|
1991
|
+
}
|
|
1992
|
+
const inputTokens = attributes[Attrs.USAGE_INPUT_TOKENS];
|
|
1993
|
+
const outputTokens = attributes[Attrs.USAGE_OUTPUT_TOKENS];
|
|
1994
|
+
if (typeof inputTokens === "number") result.inputTokens = inputTokens;
|
|
1995
|
+
if (typeof outputTokens === "number") result.outputTokens = outputTokens;
|
|
1996
|
+
if (result.inputTokens !== void 0 && result.outputTokens !== void 0) {
|
|
1997
|
+
result.totalTokens = result.inputTokens + result.outputTokens;
|
|
1998
|
+
}
|
|
1999
|
+
const finishReasons = attributes[Attrs.RESPONSE_FINISH_REASONS];
|
|
2000
|
+
if (Array.isArray(finishReasons) && finishReasons.length > 0) {
|
|
2001
|
+
result.finishReason = finishReasons[0];
|
|
2002
|
+
}
|
|
2003
|
+
const temperature = attributes[Attrs.REQUEST_TEMPERATURE];
|
|
2004
|
+
if (typeof temperature === "number") {
|
|
2005
|
+
result.settings = { ...result.settings, temperature };
|
|
2006
|
+
}
|
|
2007
|
+
const inputMessages = attributes[Attrs.INPUT_MESSAGES];
|
|
2008
|
+
if (inputMessages && typeof inputMessages === "string") {
|
|
2009
|
+
const messages = normalizeMessages(inputMessages);
|
|
2010
|
+
if (messages) result.input = messages;
|
|
2011
|
+
}
|
|
2012
|
+
const outputMessages = attributes[Attrs.OUTPUT_MESSAGES];
|
|
2013
|
+
if (outputMessages && typeof outputMessages === "string") {
|
|
2014
|
+
const extracted = extractStructuredOutput(outputMessages);
|
|
2015
|
+
if (extracted) {
|
|
2016
|
+
result.output = extracted.output;
|
|
2017
|
+
if (extracted.outputObject) {
|
|
2018
|
+
result.outputObject = extracted.outputObject;
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
const allMessages = attributes["pydantic_ai.all_messages"];
|
|
2023
|
+
if (allMessages && typeof allMessages === "string" && !result.input) {
|
|
2024
|
+
const messages = normalizeMessages(allMessages);
|
|
2025
|
+
if (messages) {
|
|
2026
|
+
const userMessages = messages.filter((m) => m.role === "user");
|
|
2027
|
+
if (userMessages.length > 0) {
|
|
2028
|
+
result.input = userMessages;
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
const finalResult = attributes["final_result"];
|
|
2033
|
+
if (finalResult && typeof finalResult === "string" && !result.output) {
|
|
2034
|
+
result.output = finalResult;
|
|
2035
|
+
try {
|
|
2036
|
+
result.outputObject = JSON.parse(finalResult);
|
|
2037
|
+
} catch {
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
const propsStr = attributes["agentmark.props"];
|
|
2041
|
+
if (propsStr && typeof propsStr === "string" && !result.input) {
|
|
2042
|
+
try {
|
|
2043
|
+
const props = JSON.parse(propsStr);
|
|
2044
|
+
result.input = [{ role: "user", content: JSON.stringify(props) }];
|
|
2045
|
+
} catch {
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
const outputStr = attributes["agentmark.output"];
|
|
2049
|
+
if (outputStr && typeof outputStr === "string" && !result.output) {
|
|
2050
|
+
result.output = outputStr;
|
|
2051
|
+
try {
|
|
2052
|
+
result.outputObject = JSON.parse(outputStr);
|
|
2053
|
+
} catch {
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
const toolName = attributes[Attrs.TOOL_NAME];
|
|
2057
|
+
if (toolName && typeof toolName === "string") {
|
|
2058
|
+
result.name = toolName;
|
|
2059
|
+
const toolCall = {
|
|
2060
|
+
type: "tool-call",
|
|
2061
|
+
toolCallId: attributes[Attrs.TOOL_CALL_ID] || "",
|
|
2062
|
+
toolName,
|
|
2063
|
+
args: {}
|
|
2064
|
+
};
|
|
2065
|
+
const toolArgs = attributes[Attrs.TOOL_CALL_ARGS];
|
|
2066
|
+
if (toolArgs && typeof toolArgs === "string") {
|
|
2067
|
+
try {
|
|
2068
|
+
toolCall.args = JSON.parse(toolArgs);
|
|
2069
|
+
} catch {
|
|
2070
|
+
toolCall.args = { raw: toolArgs };
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
const toolResult = attributes[Attrs.TOOL_CALL_RESULT];
|
|
2074
|
+
if (toolResult && typeof toolResult === "string") {
|
|
2075
|
+
toolCall.result = toolResult;
|
|
2076
|
+
}
|
|
2077
|
+
result.toolCalls = [toolCall];
|
|
2078
|
+
}
|
|
2079
|
+
const agentmarkAttrs = parseAgentMarkAttributes(attributes);
|
|
2080
|
+
Object.assign(result, agentmarkAttrs);
|
|
2081
|
+
const parsedMeta = parseMetadata(attributes);
|
|
2082
|
+
if (parsedMeta.metadata && Object.keys(parsedMeta.metadata).length > 0) {
|
|
2083
|
+
result.metadata = { ...result.metadata, ...parsedMeta.metadata };
|
|
2084
|
+
}
|
|
2085
|
+
const customMeta = extractCustomMetadata(attributes);
|
|
2086
|
+
if (Object.keys(customMeta).length > 0) {
|
|
2087
|
+
result.metadata = { ...result.metadata, ...customMeta };
|
|
2088
|
+
}
|
|
2089
|
+
return result;
|
|
2090
|
+
}
|
|
2091
|
+
};
|
|
2092
|
+
OtelGenAiTransformer.SCOPE_NAME = "pydantic-ai";
|
|
2093
|
+
|
|
1559
2094
|
// src/normalizer/converters/otlp-converter.ts
|
|
1560
2095
|
function convertOtlpValue(value) {
|
|
1561
2096
|
var _a;
|
|
@@ -1636,6 +2171,83 @@ function extractResourceScopeSpan(resourceSpans) {
|
|
|
1636
2171
|
return result;
|
|
1637
2172
|
}
|
|
1638
2173
|
|
|
2174
|
+
// src/normalizer/resolvers/semantic-kind-resolver.ts
|
|
2175
|
+
var SEMANTIC_KINDS = ["function", "llm", "tool", "agent", "retrieval", "embedding", "guardrail"];
|
|
2176
|
+
var VALID_KINDS = new Set(SEMANTIC_KINDS);
|
|
2177
|
+
var OPENINFERENCE_MAP = {
|
|
2178
|
+
"CHAIN": "function",
|
|
2179
|
+
"LLM": "llm",
|
|
2180
|
+
"TOOL": "tool",
|
|
2181
|
+
"AGENT": "agent",
|
|
2182
|
+
"RETRIEVER": "retrieval",
|
|
2183
|
+
"EMBEDDING": "embedding",
|
|
2184
|
+
"GUARDRAIL": "guardrail",
|
|
2185
|
+
"RERANKER": "retrieval"
|
|
2186
|
+
};
|
|
2187
|
+
var FRAMEWORK_MAPPINGS = [
|
|
2188
|
+
{
|
|
2189
|
+
key: "ai.operationId",
|
|
2190
|
+
// Vercel AI SDK
|
|
2191
|
+
map: {
|
|
2192
|
+
"embed": "embedding",
|
|
2193
|
+
"ai.embed": "embedding",
|
|
2194
|
+
"generateText": "llm",
|
|
2195
|
+
"streamText": "llm",
|
|
2196
|
+
"generateObject": "llm",
|
|
2197
|
+
"streamObject": "llm"
|
|
2198
|
+
}
|
|
2199
|
+
},
|
|
2200
|
+
{
|
|
2201
|
+
key: "traceloop.span.kind",
|
|
2202
|
+
// Traceloop / OpenLLMetry
|
|
2203
|
+
map: { "LLM": "llm", "TOOL": "tool", "AGENT": "agent", "WORKFLOW": "function", "TASK": "function" }
|
|
2204
|
+
},
|
|
2205
|
+
{
|
|
2206
|
+
key: "langchain.run_type",
|
|
2207
|
+
// LangChain via OTLP
|
|
2208
|
+
map: { "llm": "llm", "chat_model": "llm", "retriever": "retrieval", "tool": "tool", "chain": "function", "embedding": "embedding" }
|
|
2209
|
+
},
|
|
2210
|
+
{
|
|
2211
|
+
key: "genkit:type",
|
|
2212
|
+
// Firebase Genkit
|
|
2213
|
+
map: { "model": "llm", "tool": "tool", "flow": "function", "retriever": "retrieval", "embedder": "embedding" }
|
|
2214
|
+
}
|
|
2215
|
+
];
|
|
2216
|
+
function resolveSemanticKind(normalized, allAttributes) {
|
|
2217
|
+
if (normalized.semanticKind && VALID_KINDS.has(normalized.semanticKind)) {
|
|
2218
|
+
return normalized.semanticKind;
|
|
2219
|
+
}
|
|
2220
|
+
const oiKind = allAttributes["openinference.span.kind"];
|
|
2221
|
+
if (oiKind) {
|
|
2222
|
+
const mapped = OPENINFERENCE_MAP[String(oiKind).toUpperCase()];
|
|
2223
|
+
if (mapped) return mapped;
|
|
2224
|
+
}
|
|
2225
|
+
for (const { key, map } of FRAMEWORK_MAPPINGS) {
|
|
2226
|
+
const val = allAttributes[key];
|
|
2227
|
+
if (val) {
|
|
2228
|
+
const mapped = map[String(val)];
|
|
2229
|
+
if (mapped) return mapped;
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
const opName = allAttributes["gen_ai.operation.name"];
|
|
2233
|
+
if (opName) {
|
|
2234
|
+
const op = String(opName).toLowerCase();
|
|
2235
|
+
if (op === "chat" || op === "text_completion" || op === "generate_content") return "llm";
|
|
2236
|
+
if (op === "embeddings") return "embedding";
|
|
2237
|
+
}
|
|
2238
|
+
if (normalized.type === "GENERATION" /* GENERATION */) {
|
|
2239
|
+
return "llm";
|
|
2240
|
+
}
|
|
2241
|
+
if (normalized.toolCalls && normalized.toolCalls.length > 0) {
|
|
2242
|
+
return "tool";
|
|
2243
|
+
}
|
|
2244
|
+
const name = (normalized.name || "").toLowerCase();
|
|
2245
|
+
if (/retriev|search|rag/i.test(name)) return "retrieval";
|
|
2246
|
+
if (/embed/i.test(name)) return "embedding";
|
|
2247
|
+
if (/guard|safety/i.test(name)) return "guardrail";
|
|
2248
|
+
return "function";
|
|
2249
|
+
}
|
|
2250
|
+
|
|
1639
2251
|
// src/normalizer/type-classifier.ts
|
|
1640
2252
|
var TypeClassifier = class {
|
|
1641
2253
|
classify(span, attributes) {
|
|
@@ -1657,7 +2269,8 @@ var typeClassifier = new TypeClassifier();
|
|
|
1657
2269
|
registry.register("ai", new AiSdkTransformer());
|
|
1658
2270
|
registry.register("default-tracer", new MastraTransformer());
|
|
1659
2271
|
registry.register("agentmark", new AgentMarkTransformer());
|
|
1660
|
-
registry.
|
|
2272
|
+
registry.register("pydantic-ai", new OtelGenAiTransformer());
|
|
2273
|
+
registry.setDefault(new OtelGenAiTransformer());
|
|
1661
2274
|
function normalizeSpan(resource, scope, span) {
|
|
1662
2275
|
var _a, _b, _c;
|
|
1663
2276
|
const allAttributes = {
|
|
@@ -1713,6 +2326,7 @@ function normalizeSpan(resource, scope, span) {
|
|
|
1713
2326
|
}
|
|
1714
2327
|
const agentMarkAttributes = parseAgentMarkAttributes(allAttributes);
|
|
1715
2328
|
Object.assign(normalized, agentMarkAttributes);
|
|
2329
|
+
normalized.semanticKind = resolveSemanticKind(normalized, allAttributes);
|
|
1716
2330
|
return normalized;
|
|
1717
2331
|
}
|
|
1718
2332
|
function normalizeOtlpSpans(resourceSpans) {
|
|
@@ -1732,6 +2346,8 @@ function normalizeOtlpSpans(resourceSpans) {
|
|
|
1732
2346
|
AiSdkTransformer,
|
|
1733
2347
|
ClaudeAgentTransformer,
|
|
1734
2348
|
MastraTransformer,
|
|
2349
|
+
OtelGenAiTransformer,
|
|
2350
|
+
SEMANTIC_KINDS,
|
|
1735
2351
|
SpanType,
|
|
1736
2352
|
TransformerRegistry,
|
|
1737
2353
|
TypeClassifier,
|
|
@@ -1751,6 +2367,7 @@ function normalizeOtlpSpans(resourceSpans) {
|
|
|
1751
2367
|
parseMetadata,
|
|
1752
2368
|
parseTokens,
|
|
1753
2369
|
registry,
|
|
2370
|
+
resolveSemanticKind,
|
|
1754
2371
|
toFrontMatter,
|
|
1755
2372
|
typeClassifier,
|
|
1756
2373
|
verifySignature
|