@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.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
- async function generateTypeDefinitions(prompts) {
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.setDefault(new AiSdkTransformer());
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