@agentmark-ai/shared-utils 0.2.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 +545 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +544 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
package/dist/index.mjs
CHANGED
|
@@ -111,7 +111,15 @@ ${jsonToFrontMatter(content)}---
|
|
|
111
111
|
// src/generate-types.ts
|
|
112
112
|
import * as fs from "fs-extra";
|
|
113
113
|
import path from "path";
|
|
114
|
-
import
|
|
114
|
+
import yaml from "js-yaml";
|
|
115
|
+
function extractFrontmatter(content) {
|
|
116
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
117
|
+
if (!match) {
|
|
118
|
+
return { attributes: {} };
|
|
119
|
+
}
|
|
120
|
+
const attributes = yaml.load(match[1]);
|
|
121
|
+
return { attributes: attributes || {} };
|
|
122
|
+
}
|
|
115
123
|
var _compile = null;
|
|
116
124
|
async function getCompile() {
|
|
117
125
|
var _a;
|
|
@@ -290,7 +298,326 @@ ${typeMapping.join(",\n")}
|
|
|
290
298
|
var isNewFormat = (frontmatter) => {
|
|
291
299
|
return frontmatter["text_config"] || frontmatter["object_config"] || frontmatter["image_config"];
|
|
292
300
|
};
|
|
293
|
-
|
|
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
|
+
}
|
|
294
621
|
if (prompts[0].version === "1.0") {
|
|
295
622
|
return generateTypeDefinitionsV1_0(prompts);
|
|
296
623
|
}
|
|
@@ -355,7 +682,7 @@ async function fetchPromptsFrontmatter(options) {
|
|
|
355
682
|
return Promise.all(
|
|
356
683
|
promptFiles.map(async (file) => {
|
|
357
684
|
const content = await fs.readFile(file, "utf-8");
|
|
358
|
-
const { attributes } =
|
|
685
|
+
const { attributes } = extractFrontmatter(content);
|
|
359
686
|
if (isNewFormat(attributes)) {
|
|
360
687
|
return {
|
|
361
688
|
path: path.relative(options.rootDir, file),
|
|
@@ -497,6 +824,7 @@ var KNOWN_METADATA_FIELDS = /* @__PURE__ */ new Set([
|
|
|
497
824
|
"dataset_path",
|
|
498
825
|
"dataset_item_name",
|
|
499
826
|
"dataset_expected_output",
|
|
827
|
+
"dataset_input",
|
|
500
828
|
"prompt_name",
|
|
501
829
|
"props",
|
|
502
830
|
"commit_sha"
|
|
@@ -1284,10 +1612,12 @@ function parseAgentMarkAttributes(attributes, prefix = "agentmark.") {
|
|
|
1284
1612
|
if (get("trace_name")) result.traceName = String(get("trace_name"));
|
|
1285
1613
|
if (get("prompt_name")) result.promptName = String(get("prompt_name"));
|
|
1286
1614
|
if (get("props")) result.props = String(get("props"));
|
|
1615
|
+
if (get("span.kind")) result.kind = String(get("span.kind"));
|
|
1287
1616
|
if (get("dataset_run_id")) result.datasetRunId = String(get("dataset_run_id"));
|
|
1288
1617
|
if (get("dataset_run_name")) result.datasetRunName = String(get("dataset_run_name"));
|
|
1289
1618
|
if (get("dataset_item_name")) result.datasetItemName = String(get("dataset_item_name"));
|
|
1290
1619
|
if (get("dataset_expected_output")) result.datasetExpectedOutput = String(get("dataset_expected_output"));
|
|
1620
|
+
if (get("dataset_input")) result.datasetInput = String(get("dataset_input"));
|
|
1291
1621
|
if (get("dataset_path")) result.datasetPath = String(get("dataset_path"));
|
|
1292
1622
|
return result;
|
|
1293
1623
|
}
|
|
@@ -1400,6 +1730,10 @@ var AgentMarkTransformer = class {
|
|
|
1400
1730
|
if (result.inputTokens !== void 0 && result.outputTokens !== void 0) {
|
|
1401
1731
|
result.totalTokens = result.inputTokens + result.outputTokens;
|
|
1402
1732
|
}
|
|
1733
|
+
const costUsd = attributes["agentmark.usage.cost_usd"];
|
|
1734
|
+
if (typeof costUsd === "number" && costUsd > 0) {
|
|
1735
|
+
result.cost = costUsd;
|
|
1736
|
+
}
|
|
1403
1737
|
const finishReasons = attributes[GenAIAttributes.RESPONSE_FINISH_REASONS];
|
|
1404
1738
|
if (finishReasons) {
|
|
1405
1739
|
try {
|
|
@@ -1445,6 +1779,22 @@ var AgentMarkTransformer = class {
|
|
|
1445
1779
|
const responseOutput = attributes[GenAIAttributes.RESPONSE_OUTPUT];
|
|
1446
1780
|
if (responseOutput && typeof responseOutput === "string") {
|
|
1447
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
|
+
}
|
|
1448
1798
|
}
|
|
1449
1799
|
const toolName = attributes[GenAIAttributes.TOOL_NAME];
|
|
1450
1800
|
const toolCallId = attributes[GenAIAttributes.TOOL_CALL_ID];
|
|
@@ -1486,6 +1836,194 @@ var AgentMarkTransformer = class {
|
|
|
1486
1836
|
};
|
|
1487
1837
|
var AGENTMARK_SCOPE_NAME = "agentmark";
|
|
1488
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
|
+
|
|
1489
2027
|
// src/normalizer/converters/otlp-converter.ts
|
|
1490
2028
|
function convertOtlpValue(value) {
|
|
1491
2029
|
var _a;
|
|
@@ -1587,7 +2125,8 @@ var typeClassifier = new TypeClassifier();
|
|
|
1587
2125
|
registry.register("ai", new AiSdkTransformer());
|
|
1588
2126
|
registry.register("default-tracer", new MastraTransformer());
|
|
1589
2127
|
registry.register("agentmark", new AgentMarkTransformer());
|
|
1590
|
-
registry.
|
|
2128
|
+
registry.register("pydantic-ai", new OtelGenAiTransformer());
|
|
2129
|
+
registry.setDefault(new OtelGenAiTransformer());
|
|
1591
2130
|
function normalizeSpan(resource, scope, span) {
|
|
1592
2131
|
var _a, _b, _c;
|
|
1593
2132
|
const allAttributes = {
|
|
@@ -1661,6 +2200,7 @@ export {
|
|
|
1661
2200
|
AiSdkTransformer,
|
|
1662
2201
|
AgentMarkTransformer as ClaudeAgentTransformer,
|
|
1663
2202
|
MastraTransformer,
|
|
2203
|
+
OtelGenAiTransformer,
|
|
1664
2204
|
SpanType,
|
|
1665
2205
|
TransformerRegistry,
|
|
1666
2206
|
TypeClassifier,
|