@mutagent/cli 0.1.14 → 0.1.16

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/bin/cli.js CHANGED
@@ -288,7 +288,7 @@ var init_errors = __esm(() => {
288
288
  ApiError = class ApiError extends MutagentError {
289
289
  statusCode;
290
290
  constructor(status, message) {
291
- super(`API_${status}`, message, status === 401 ? "Check your API key with: mutagent auth status" : undefined, 1);
291
+ super(`API_${String(status)}`, message, status === 401 ? "Check your API key with: mutagent auth status" : undefined, 1);
292
292
  this.statusCode = status;
293
293
  }
294
294
  };
@@ -464,6 +464,7 @@ class SDKClientWrapper {
464
464
  systemPrompt: data.systemPrompt ?? undefined,
465
465
  humanPrompt: data.humanPrompt ?? undefined,
466
466
  rawPrompt: data.rawPrompt ?? undefined,
467
+ inputSchema: data.inputSchema,
467
468
  outputSchema: data.outputSchema,
468
469
  metadata: data.metadata,
469
470
  tags: data.tags ?? undefined
@@ -529,11 +530,13 @@ class SDKClientWrapper {
529
530
  labels: item.labels,
530
531
  metadata: item.metadata
531
532
  }));
533
+ const missingExpectedOutputCount = mappedItems.filter((item) => item.expectedOutput === undefined).length;
532
534
  await this.request(`/api/prompts/datasets/${String(dataset.id)}/items/bulk`, {
533
535
  method: "POST",
534
536
  body: JSON.stringify({ items: mappedItems })
535
537
  });
536
538
  itemCount = mappedItems.length;
539
+ return { ...dataset, itemCount, missingExpectedOutputCount };
537
540
  }
538
541
  return { ...dataset, itemCount };
539
542
  } catch (error) {
@@ -588,7 +591,7 @@ class SDKClientWrapper {
588
591
  body: JSON.stringify({
589
592
  datasetId: parseInt(datasetId, 10),
590
593
  config: {
591
- maxIterations: config?.maxIterations ?? 3,
594
+ maxIterations: config?.maxIterations ?? 1,
592
595
  targetScore: config?.targetScore,
593
596
  patience: config?.patience,
594
597
  model: config?.model,
@@ -849,6 +852,12 @@ class SDKClientWrapper {
849
852
  this.handleError(error);
850
853
  }
851
854
  }
855
+ getCurrentWorkspaceId() {
856
+ return this.workspaceId;
857
+ }
858
+ getCurrentOrgId() {
859
+ return this.organizationId;
860
+ }
852
861
  async testProvider(id) {
853
862
  try {
854
863
  const response = await this.sdk.providerConfigs.testProvider({
@@ -924,7 +933,7 @@ var init_sdk_client = __esm(() => {
924
933
  // src/bin/cli.ts
925
934
  import { Command as Command14 } from "commander";
926
935
  import chalk18 from "chalk";
927
- import { readFileSync as readFileSync14 } from "fs";
936
+ import { readFileSync as readFileSync12 } from "fs";
928
937
  import { join as join7, dirname } from "path";
929
938
  import { fileURLToPath } from "url";
930
939
 
@@ -1779,12 +1788,10 @@ async function runIntegrationPath() {
1779
1788
  name: "framework",
1780
1789
  message: "Which AI framework are you using?",
1781
1790
  choices: [
1782
- { name: "Mastra", value: "mastra" },
1783
1791
  { name: "LangChain", value: "langchain" },
1784
1792
  { name: "LangGraph", value: "langgraph" },
1785
1793
  { name: "Vercel AI SDK", value: "vercel-ai" },
1786
- { name: "Claude Code", value: "claude-code" },
1787
- { name: "Other / Generic", value: "generic" }
1794
+ { name: "OpenAI SDK", value: "openai" }
1788
1795
  ]
1789
1796
  }]);
1790
1797
  console.log("");
@@ -2419,17 +2426,39 @@ function isValidJsonSchema(schema) {
2419
2426
  function buildSchemaFromVariables(variables) {
2420
2427
  const properties = {};
2421
2428
  for (const variable of variables) {
2422
- const prop = { type: variable.type };
2423
- if (variable.description) {
2424
- prop.description = variable.description;
2425
- }
2426
- properties[variable.name] = prop;
2429
+ properties[variable.name] = {
2430
+ type: variable.type,
2431
+ description: variable.description
2432
+ };
2427
2433
  }
2428
2434
  return {
2429
2435
  type: "object",
2430
2436
  properties
2431
2437
  };
2432
2438
  }
2439
+ function validateSchemaDescriptions(schema) {
2440
+ if (schema === null || schema === undefined)
2441
+ return [];
2442
+ if (typeof schema !== "object" || Array.isArray(schema))
2443
+ return [];
2444
+ const obj = schema;
2445
+ const properties = obj.properties;
2446
+ if (!properties || typeof properties !== "object" || Array.isArray(properties))
2447
+ return [];
2448
+ const missing = [];
2449
+ const props = properties;
2450
+ for (const [key, value] of Object.entries(props)) {
2451
+ if (value === null || value === undefined || typeof value !== "object") {
2452
+ missing.push(key);
2453
+ continue;
2454
+ }
2455
+ const prop = value;
2456
+ if (typeof prop.description !== "string" || prop.description.trim() === "") {
2457
+ missing.push(key);
2458
+ }
2459
+ }
2460
+ return missing;
2461
+ }
2433
2462
  function formatSchemaWarning(fieldName) {
2434
2463
  return [
2435
2464
  `${fieldName} doesn't appear to be a valid JSON Schema.`,
@@ -2593,10 +2622,11 @@ async function runGuidedEvalCreator(promptId) {
2593
2622
  } else {
2594
2623
  scoringRubric = rubric;
2595
2624
  }
2625
+ const evaluationParameter = targetField.startsWith("output.") ? targetField.slice("output.".length) : targetField.startsWith("input.") ? targetField.slice("input.".length) : targetField;
2596
2626
  criteria.push({
2597
2627
  name: criterionName.trim(),
2598
- targetField,
2599
- scoringRubric,
2628
+ description: scoringRubric,
2629
+ evaluationParameter,
2600
2630
  weight: 1
2601
2631
  });
2602
2632
  const { continueAdding } = await inquirer3.prompt([{
@@ -2618,7 +2648,7 @@ async function runGuidedEvalCreator(promptId) {
2618
2648
  console.log(` Type: ${evalType}`);
2619
2649
  console.log(` Criteria: ${String(criteria.length)}`);
2620
2650
  for (const c of criteria) {
2621
- console.log(` - ${chalk5.cyan(c.name)} → ${c.targetField}`);
2651
+ console.log(` - ${chalk5.cyan(c.name)} → ${c.evaluationParameter}`);
2622
2652
  }
2623
2653
  console.log("");
2624
2654
  const { confirmed } = await inquirer3.prompt([{
@@ -2691,6 +2721,38 @@ function renderScorecard(data) {
2691
2721
  console.log(line(` Prompt: ${chalk6.cyan(truncateText(optimizedText, 38))}`));
2692
2722
  console.log(line(` Score: ${formatScore(bestScore)}${formatScoreChange(originalScore, bestScore)}`));
2693
2723
  console.log(separator);
2724
+ if (data.criteriaScores && data.criteriaScores.length > 0) {
2725
+ console.log(line(chalk6.dim(" Criterion Before After Change")));
2726
+ console.log(line(chalk6.dim(" " + "─".repeat(45))));
2727
+ for (const c of data.criteriaScores) {
2728
+ const name = c.name.length > 16 ? c.name.substring(0, 13) + "..." : c.name;
2729
+ const paddedName = name + " ".repeat(18 - name.length);
2730
+ const beforeStr = c.before !== undefined ? c.before.toFixed(2) : "N/A ";
2731
+ const afterStr = c.after !== undefined ? c.after.toFixed(2) : "N/A ";
2732
+ const changeStr = c.before !== undefined && c.after !== undefined && c.before > 0 ? (() => {
2733
+ const pct = Math.round((c.after - c.before) / c.before * 100);
2734
+ if (pct > 0)
2735
+ return chalk6.green(`+${String(pct)}%`);
2736
+ if (pct < 0)
2737
+ return chalk6.red(`${String(pct)}%`);
2738
+ return chalk6.dim("0%");
2739
+ })() : "";
2740
+ console.log(line(` ${paddedName}${beforeStr} ${afterStr} ${changeStr}`));
2741
+ }
2742
+ console.log(line(chalk6.dim(" " + "─".repeat(45))));
2743
+ const overallBefore = originalScore !== undefined ? originalScore.toFixed(2) : "N/A ";
2744
+ const overallAfter = bestScore !== undefined ? bestScore.toFixed(2) : "N/A ";
2745
+ const overallChange = originalScore !== undefined && bestScore !== undefined && originalScore > 0 ? (() => {
2746
+ const pct = Math.round((bestScore - originalScore) / originalScore * 100);
2747
+ if (pct > 0)
2748
+ return chalk6.green(`+${String(pct)}%`);
2749
+ if (pct < 0)
2750
+ return chalk6.red(`${String(pct)}%`);
2751
+ return chalk6.dim("0%");
2752
+ })() : "";
2753
+ console.log(line(` ${"Overall" + " ".repeat(11)}${overallBefore} ${overallAfter} ${overallChange}`));
2754
+ console.log(separator);
2755
+ }
2694
2756
  const statusStr = job.status === "completed" ? chalk6.green("completed") : chalk6.yellow(job.status);
2695
2757
  console.log(line(`Status: ${statusStr} | Iterations: ${String(iterations)}`));
2696
2758
  if (job.config?.model) {
@@ -2699,19 +2761,16 @@ function renderScorecard(data) {
2699
2761
  if (data.scoreProgression && data.scoreProgression.length > 0) {
2700
2762
  console.log(line(""));
2701
2763
  console.log(line(chalk6.dim("Score Progression:")));
2702
- const progression = data.scoreProgression.map((s, i) => `#${String(i + 1)}: ${s.toFixed(2)}`).join(" ");
2703
- if (progression.length > boxWidth - 4) {
2704
- const mid = Math.ceil(data.scoreProgression.length / 2);
2705
- const line1 = data.scoreProgression.slice(0, mid).map((s, i) => `#${String(i + 1)}: ${s.toFixed(2)}`).join(" ");
2706
- const line2 = data.scoreProgression.slice(mid).map((s, i) => `#${String(i + mid + 1)}: ${s.toFixed(2)}`).join(" ");
2707
- console.log(line(chalk6.dim(line1)));
2708
- console.log(line(chalk6.dim(line2)));
2709
- } else {
2710
- console.log(line(chalk6.dim(progression)));
2764
+ const barWidth = 10;
2765
+ for (let i = 0;i < data.scoreProgression.length; i++) {
2766
+ const s = data.scoreProgression[i] ?? 0;
2767
+ const filled = Math.round(s * barWidth);
2768
+ const bar = "█".repeat(filled) + "░".repeat(barWidth - filled);
2769
+ console.log(line(chalk6.dim(` #${String(i + 1)}: ${bar} ${s.toFixed(2)}`)));
2711
2770
  }
2712
2771
  }
2713
2772
  console.log(separator);
2714
- console.log(line(`Dashboard: ${chalk6.underline(optimizerLink(job.jobId))}`));
2773
+ console.log(line(`Dashboard: ${chalk6.underline(optimizerLink(job.id))}`));
2715
2774
  console.log(bottomBorder);
2716
2775
  console.log("");
2717
2776
  }
@@ -2780,18 +2839,6 @@ function isSchemaEmpty(schema) {
2780
2839
  return true;
2781
2840
  return false;
2782
2841
  }
2783
- function warnMissingSchemas(data, output) {
2784
- if (isSchemaEmpty(data.inputSchema)) {
2785
- output.warn("No inputSchema provided. Optimization requires inputSchema with defined variables.");
2786
- } else if (!isValidJsonSchema(data.inputSchema)) {
2787
- output.warn(formatSchemaWarning("inputSchema"));
2788
- }
2789
- if (isSchemaEmpty(data.outputSchema)) {
2790
- output.warn("No outputSchema provided. This may limit optimization effectiveness.");
2791
- } else if (!isValidJsonSchema(data.outputSchema)) {
2792
- output.warn(formatSchemaWarning("outputSchema"));
2793
- }
2794
- }
2795
2842
  async function collectSchemaInteractively() {
2796
2843
  const inquirer3 = (await import("inquirer")).default;
2797
2844
  const variables = [];
@@ -2820,13 +2867,18 @@ async function collectSchemaInteractively() {
2820
2867
  {
2821
2868
  type: "input",
2822
2869
  name: "description",
2823
- message: "Description (optional):"
2870
+ message: "Description (required):",
2871
+ validate: (input) => {
2872
+ if (!input.trim())
2873
+ return "Variable description is required";
2874
+ return true;
2875
+ }
2824
2876
  }
2825
2877
  ]);
2826
2878
  variables.push({
2827
2879
  name: answers.name.trim(),
2828
2880
  type: answers.type,
2829
- description: answers.description.trim() || undefined
2881
+ description: answers.description.trim()
2830
2882
  });
2831
2883
  const continueAnswer = await inquirer3.prompt([{
2832
2884
  type: "confirm",
@@ -2963,14 +3015,22 @@ ${chalk7.dim("Tip: Use --json for machine-readable output (AI agents, CI pipelin
2963
3015
  }));
2964
3016
  output.output(withLinks);
2965
3017
  } else {
2966
- const formatted = limited.map((p) => ({
2967
- id: p.id,
2968
- name: p.name,
2969
- version: p.version,
2970
- updated: p.updatedAt ? new Date(p.updatedAt).toLocaleDateString() : "N/A",
2971
- url: promptLink(p.id)
2972
- }));
2973
- output.output(formatted);
3018
+ const wsId = client.getCurrentWorkspaceId();
3019
+ if (wsId) {
3020
+ output.info(`Workspace: ${wsId}`);
3021
+ }
3022
+ if (limited.length === 0) {
3023
+ output.info("No prompts found in current workspace. Run 'mutagent config list' to check workspace context.");
3024
+ } else {
3025
+ const formatted = limited.map((p) => ({
3026
+ id: p.id,
3027
+ name: p.name,
3028
+ version: p.version,
3029
+ updated: p.updatedAt ? new Date(p.updatedAt).toLocaleDateString() : "N/A",
3030
+ url: promptLink(p.id)
3031
+ }));
3032
+ output.output(formatted);
3033
+ }
2974
3034
  }
2975
3035
  } catch (error) {
2976
3036
  handleError(error, isJson);
@@ -3120,17 +3180,32 @@ ${chalk7.dim("Note: --data and --file are mutually exclusive. outputSchema is re
3120
3180
  if (schema) {
3121
3181
  data.inputSchema = schema;
3122
3182
  }
3123
- } else {
3124
- output.warn("No inputSchema provided. Optimization requires inputSchema with defined variables.");
3125
3183
  }
3126
3184
  }
3127
- warnMissingSchemas(data, output);
3185
+ if (isSchemaEmpty(data.inputSchema)) {
3186
+ throw new MutagentError("VALIDATION_ERROR", "inputSchema is required. Optimization cannot run without defined input variables.", `Provide inputSchema via --data, --file, or interactive mode. Example:
3187
+ --data '{"inputSchema":{"type":"object","properties":{"query":{"type":"string","description":"User query"}}}}'
3188
+ Or use interactive mode (TTY) to define variables step by step.`);
3189
+ } else if (!isValidJsonSchema(data.inputSchema)) {
3190
+ throw new MutagentError("VALIDATION_ERROR", "inputSchema is not a valid JSON Schema object.", formatSchemaWarning("inputSchema"));
3191
+ } else {
3192
+ const missingDescs = validateSchemaDescriptions(data.inputSchema);
3193
+ if (missingDescs.length > 0) {
3194
+ throw new MutagentError("VALIDATION_ERROR", `inputSchema properties missing descriptions: ${missingDescs.join(", ")}`, `Add a 'description' field to each property in your inputSchema. Example: { "properties": { "field": { "type": "string", "description": "What this field contains" } } }`);
3195
+ }
3196
+ }
3197
+ if (isSchemaEmpty(data.outputSchema)) {
3198
+ output.warn("No outputSchema provided. This may limit optimization effectiveness.");
3199
+ } else if (!isValidJsonSchema(data.outputSchema)) {
3200
+ output.warn(formatSchemaWarning("outputSchema"));
3201
+ }
3128
3202
  const client = getSDKClient();
3129
3203
  const prompt = await client.createPrompt(data);
3130
3204
  if (isJson) {
3131
3205
  output.output({ ...prompt, _links: promptLinks(prompt.id) });
3132
3206
  } else {
3133
3207
  output.success(`Created prompt: ${prompt.name} (id: ${String(prompt.id)})`);
3208
+ output.info(`Workspace: ${client.getCurrentWorkspaceId() ?? "auto-inferred from API key"}`);
3134
3209
  const hints = formatCreationHints({
3135
3210
  resourceType: "Prompt",
3136
3211
  id: prompt.id,
@@ -3152,13 +3227,15 @@ ${chalk7.dim("Note: --data and --file are mutually exclusive. outputSchema is re
3152
3227
  handleError(error, isJson);
3153
3228
  }
3154
3229
  });
3155
- prompts.command("update").description("Update a prompt").argument("<id>", "Prompt ID (from: mutagent prompts list)").option("-d, --data <json>", "Update fields as JSON string (recommended — curl-style inline)").option("-f, --file <path>", "Update from JSON file").option("--raw-file <path>", "Update from plain text file (used as rawPrompt)").option("-n, --name <name>", "New name").option("-c, --content <content>", "New content (rawPrompt) [DEPRECATED: use --raw]").option("-r, --raw <text>", "Raw prompt text (single prompt)").option("--system <text>", "System prompt (use with --human)").option("--human <text>", "Human prompt (use with --system)").option("--messages <json>", `Messages array as JSON (e.g., '[{"role":"system","content":"..."}]')`).addHelpText("after", `
3230
+ prompts.command("update").description("Update a prompt").argument("<id>", "Prompt ID (from: mutagent prompts list)").option("-d, --data <json>", "Update fields as JSON string (recommended — curl-style inline)").option("-f, --file <path>", "Update from JSON file").option("--raw-file <path>", "Update from plain text file (used as rawPrompt)").option("-n, --name <name>", "New name").option("-c, --content <content>", "New content (rawPrompt) [DEPRECATED: use --raw]").option("-r, --raw <text>", "Raw prompt text (single prompt)").option("--system <text>", "System prompt (use with --human)").option("--human <text>", "Human prompt (use with --system)").option("--messages <json>", `Messages array as JSON (e.g., '[{"role":"system","content":"..."}]')`).option("--input-schema <json>", "Input schema as JSON string").option("--input-schema-file <path>", "Input schema from JSON file").option("--output-schema <json>", "Output schema as JSON string").option("--output-schema-file <path>", "Output schema from JSON file").addHelpText("after", `
3156
3231
  Examples:
3157
3232
  ${chalk7.dim("$")} mutagent prompts update <id> -d '{"name":"new-name","systemPrompt":"Updated prompt"}'
3158
3233
  ${chalk7.dim("$")} mutagent prompts update <id> --name "new-name"
3159
3234
  ${chalk7.dim("$")} mutagent prompts update <id> --system "Updated system prompt"
3160
3235
  ${chalk7.dim("$")} mutagent prompts update <id> --raw-file updated-prompt.txt
3161
3236
  ${chalk7.dim("$")} mutagent prompts update <id> --file updated-prompt.json
3237
+ ${chalk7.dim("$")} mutagent prompts update <id> --input-schema '{"type":"object","properties":{"text":{"type":"string","description":"Input text"}}}'
3238
+ ${chalk7.dim("$")} mutagent prompts update <id> --input-schema-file schema.json
3162
3239
 
3163
3240
  ${chalk7.dim("Note: --data and --file are mutually exclusive. CLI flags (--name) override --data fields.")}
3164
3241
  `).action(async (id, options) => {
@@ -3214,8 +3291,52 @@ ${chalk7.dim("Note: --data and --file are mutually exclusive. CLI flags (--name)
3214
3291
  data.rawPrompt = options.content;
3215
3292
  }
3216
3293
  }
3294
+ if (options.inputSchema && options.inputSchemaFile) {
3295
+ throw new MutagentError("INVALID_ARGUMENTS", "Cannot use --input-schema and --input-schema-file together", "Use --input-schema for inline JSON or --input-schema-file for file-based input, not both");
3296
+ }
3297
+ if (options.inputSchema) {
3298
+ try {
3299
+ data.inputSchema = JSON.parse(options.inputSchema);
3300
+ } catch {
3301
+ throw new MutagentError("INVALID_JSON", "Invalid JSON in --input-schema flag", `Provide a valid JSON Schema, e.g., '{"type":"object","properties":{"text":{"type":"string","description":"Input text"}}}'`);
3302
+ }
3303
+ } else if (options.inputSchemaFile) {
3304
+ if (!existsSync4(options.inputSchemaFile)) {
3305
+ throw new MutagentError("FILE_NOT_FOUND", `File not found: ${options.inputSchemaFile}`, "Check the file path and try again");
3306
+ }
3307
+ try {
3308
+ data.inputSchema = JSON.parse(readFileSync4(options.inputSchemaFile, "utf-8"));
3309
+ } catch {
3310
+ throw new MutagentError("INVALID_JSON", `Failed to parse JSON from ${options.inputSchemaFile}`, "Ensure the file contains valid JSON Schema");
3311
+ }
3312
+ }
3313
+ if (options.outputSchema && options.outputSchemaFile) {
3314
+ throw new MutagentError("INVALID_ARGUMENTS", "Cannot use --output-schema and --output-schema-file together", "Use --output-schema for inline JSON or --output-schema-file for file-based input, not both");
3315
+ }
3316
+ if (options.outputSchema) {
3317
+ try {
3318
+ data.outputSchema = JSON.parse(options.outputSchema);
3319
+ } catch {
3320
+ throw new MutagentError("INVALID_JSON", "Invalid JSON in --output-schema flag", `Provide a valid JSON Schema, e.g., '{"type":"object","properties":{"result":{"type":"string"}}}'`);
3321
+ }
3322
+ } else if (options.outputSchemaFile) {
3323
+ if (!existsSync4(options.outputSchemaFile)) {
3324
+ throw new MutagentError("FILE_NOT_FOUND", `File not found: ${options.outputSchemaFile}`, "Check the file path and try again");
3325
+ }
3326
+ try {
3327
+ data.outputSchema = JSON.parse(readFileSync4(options.outputSchemaFile, "utf-8"));
3328
+ } catch {
3329
+ throw new MutagentError("INVALID_JSON", `Failed to parse JSON from ${options.outputSchemaFile}`, "Ensure the file contains valid JSON Schema");
3330
+ }
3331
+ }
3332
+ if (data.inputSchema && isValidJsonSchema(data.inputSchema)) {
3333
+ const missingDescs = validateSchemaDescriptions(data.inputSchema);
3334
+ if (missingDescs.length > 0) {
3335
+ throw new MutagentError("VALIDATION_ERROR", `inputSchema properties missing descriptions: ${missingDescs.join(", ")}`, `Add a 'description' field to each property in your inputSchema. Example: { "properties": { "field": { "type": "string", "description": "What this field contains" } } }`);
3336
+ }
3337
+ }
3217
3338
  if (Object.keys(data).length === 0) {
3218
- throw new MutagentError("MISSING_ARGUMENTS", "No update data provided", "Use --data, --file, --raw-file, --name, --raw, --system/--human, or --messages");
3339
+ throw new MutagentError("MISSING_ARGUMENTS", "No update data provided", "Use --data, --file, --raw-file, --name, --raw, --system/--human, --messages, --input-schema, or --output-schema");
3219
3340
  }
3220
3341
  const promptContent = data.rawPrompt ?? data.systemPrompt ?? data.humanPrompt ?? "";
3221
3342
  if (promptContent && !isJson) {
@@ -3386,6 +3507,9 @@ ${chalk7.dim("Note: --file and -d are mutually exclusive. Provide one or the oth
3386
3507
  if (datasetResult.itemCount !== undefined && datasetResult.itemCount > 0) {
3387
3508
  output.info(`Items uploaded: ${String(datasetResult.itemCount)}`);
3388
3509
  }
3510
+ if (datasetResult.missingExpectedOutputCount !== undefined && datasetResult.missingExpectedOutputCount > 0) {
3511
+ output.warn(`${String(datasetResult.missingExpectedOutputCount)} of ${String(datasetResult.itemCount ?? 0)} items have no expectedOutput. Optimization may fail without expected outputs.`);
3512
+ }
3389
3513
  const hints = formatCreationHints({
3390
3514
  resourceType: "Dataset",
3391
3515
  id: datasetResult.id,
@@ -3460,8 +3584,8 @@ Examples:
3460
3584
  ${chalk7.dim("$")} mutagent prompts evaluation create <prompt-id> --name "Full Eval" --file criteria.json --dataset <dataset-id>
3461
3585
  ${chalk7.dim("$")} mutagent prompts evaluation create <prompt-id> --name "QA" --description "Quality assurance eval" --json
3462
3586
 
3463
- Criteria file format (--file or --data):
3464
- ${chalk7.dim('{ "name": "...", "evalConfig": { "criteria": [...] }, "llmConfig": { "model": "gpt-4" } }')}
3587
+ Criteria format (each criterion needs: name, description, evaluationParameter):
3588
+ ${chalk7.dim('{ "name": "...", "evalConfig": { "criteria": [{ "name": "...", "description": "...", "evaluationParameter": "outputField" }] } }')}
3465
3589
 
3466
3590
  ${chalk7.dim("Note: --data and --file are mutually exclusive. CLI flags (--name, --description) override --data fields.")}
3467
3591
  ${chalk7.dim("Tip: Use --guided for an interactive walkthrough of criteria creation.")}
@@ -3549,6 +3673,32 @@ ${chalk7.dim("Get prompt IDs: mutagent prompts list | Get dataset IDs: mutagent
3549
3673
  evalData.name = options.name;
3550
3674
  if (options.description)
3551
3675
  evalData.description = options.description;
3676
+ const criteria = evalData.evalConfig?.criteria;
3677
+ if (!criteria || !Array.isArray(criteria) || criteria.length === 0) {
3678
+ throw new MutagentError("VALIDATION_ERROR", "Evaluation criteria are required. Provide criteria via --data, --file, or use --guided mode.", `Each criterion needs: name, description, evaluationParameter.
3679
+
3680
+ Example JSON (--data flag):
3681
+ --data '{"evalConfig":{"criteria":[{"name":"Accuracy","description":"Score 1.0 if output matches expected, 0.0 otherwise","evaluationParameter":"classification"}]}}'
3682
+
3683
+ Or use --guided for interactive creation: mutagent prompts evaluation create <id> --guided`);
3684
+ }
3685
+ for (const c of criteria) {
3686
+ const hasDescription = c.description ?? c.scoringRubric;
3687
+ const hasEvalParam = c.evaluationParameter ?? c.targetField;
3688
+ if (!c.name || !hasDescription || !hasEvalParam) {
3689
+ const cName = typeof c.name === "string" ? c.name : "unnamed";
3690
+ throw new MutagentError("VALIDATION_ERROR", `Criterion "${cName}" is missing required fields. Need: name, description (or scoringRubric), evaluationParameter (or targetField).`, 'evaluationParameter maps to the output field to evaluate (e.g., "classification", "riskLevel"). Use --guided for interactive creation.');
3691
+ }
3692
+ if (c.scoringRubric && !c.description) {
3693
+ c.description = c.scoringRubric;
3694
+ delete c.scoringRubric;
3695
+ }
3696
+ if (c.targetField && !c.evaluationParameter) {
3697
+ const tf = c.targetField;
3698
+ c.evaluationParameter = tf.startsWith("output.") ? tf.slice("output.".length) : tf.startsWith("input.") ? tf.slice("input.".length) : tf;
3699
+ delete c.targetField;
3700
+ }
3701
+ }
3552
3702
  if (options.dataset) {
3553
3703
  evalData.datasetId = parseInt(options.dataset, 10);
3554
3704
  if (isNaN(evalData.datasetId)) {
@@ -3618,6 +3768,38 @@ ${chalk7.dim("Monitor progress with: mutagent prompts optimize status <job-id>")
3618
3768
  const output = new OutputFormatter(isJson ? "json" : "table");
3619
3769
  try {
3620
3770
  const client = getSDKClient();
3771
+ if (!isJson) {
3772
+ output.info("Running pre-flight checks...");
3773
+ const prompt = await client.getPrompt(promptId);
3774
+ if (isSchemaEmpty(prompt.outputSchema)) {
3775
+ throw new MutagentError("MISSING_OUTPUT_SCHEMA", "Prompt is missing outputSchema — required for optimization", `Update your prompt: mutagent prompts update ${promptId} -d '{"outputSchema":{"type":"object","properties":{"result":{"type":"string"}}}}'`);
3776
+ }
3777
+ if (isSchemaEmpty(prompt.inputSchema)) {
3778
+ output.warn("Prompt has no inputSchema. Optimization works best with defined input variables.");
3779
+ }
3780
+ try {
3781
+ const evals = await client.listEvaluations(promptId);
3782
+ if (evals.length === 0) {
3783
+ throw new MutagentError("MISSING_EVALUATION", "No evaluations found for this prompt — required for optimization", `Create an evaluation: mutagent prompts evaluation create ${promptId} --guided`);
3784
+ }
3785
+ const validEvals = evals.filter((e) => {
3786
+ const config = e.evalConfig;
3787
+ const criteria = config?.criteria;
3788
+ if (!criteria || criteria.length === 0)
3789
+ return false;
3790
+ return criteria.some((c) => c.evaluationParameter ?? c.targetField);
3791
+ });
3792
+ if (validEvals.length === 0) {
3793
+ output.warn(`Evaluations exist but none have evaluationParameter set. Optimization works best with criteria targeting specific output fields. Re-create: mutagent prompts evaluation create ${promptId} --guided`);
3794
+ } else {
3795
+ output.info(`Found ${String(validEvals.length)} evaluation(s) with proper criteria.`);
3796
+ }
3797
+ } catch (e) {
3798
+ if (e instanceof MutagentError)
3799
+ throw e;
3800
+ output.warn("Could not validate evaluations. Optimization will use default evaluation.");
3801
+ }
3802
+ }
3621
3803
  const job = await client.startOptimization(promptId, options.dataset, {
3622
3804
  maxIterations: options.maxIterations ? parseInt(options.maxIterations, 10) : undefined,
3623
3805
  targetScore: options.targetScore ? parseFloat(options.targetScore) : undefined,
@@ -3629,27 +3811,55 @@ ${chalk7.dim("Monitor progress with: mutagent prompts optimize status <job-id>")
3629
3811
  output.output({
3630
3812
  ...job,
3631
3813
  _links: {
3632
- dashboard: optimizerLink(job.jobId),
3633
- api: `/api/prompts/${promptId}/optimizations/${job.jobId}`
3814
+ dashboard: optimizerLink(job.id),
3815
+ api: `/api/prompts/${promptId}/optimizations/${job.id}`
3634
3816
  }
3635
3817
  });
3636
3818
  } else {
3637
- output.success(`Started optimization job: ${job.jobId}`);
3819
+ output.success(`Started optimization job: ${job.id}`);
3638
3820
  const hints = formatCreationHints({
3639
3821
  resourceType: "Optimization",
3640
- id: job.jobId,
3641
- dashboardUrl: optimizerLink(job.jobId),
3642
- apiPath: `/api/prompts/${promptId}/optimizations/${job.jobId}`
3822
+ id: job.id,
3823
+ dashboardUrl: optimizerLink(job.id),
3824
+ apiPath: `/api/prompts/${promptId}/optimizations/${job.id}`
3643
3825
  });
3644
3826
  console.log(hints);
3645
3827
  }
3646
3828
  } catch (error) {
3647
3829
  if (error instanceof ApiError) {
3648
3830
  const messages = parseValidationErrors(error);
3831
+ const errorText = messages.join(" ");
3832
+ const suggestions = [];
3833
+ if (errorText.includes("Output Schema is not present") || errorText.includes("outputSchema")) {
3834
+ suggestions.push(`Update prompt: mutagent prompts update ${promptId} -d '{"outputSchema":{"type":"object","properties":{...}}}'`);
3835
+ }
3836
+ if (errorText.includes("Outputs are not valid") || errorText.includes("Parameters Mismatch")) {
3837
+ suggestions.push("Dataset items may not match the prompt schema. Check expectedOutput fields in your dataset.");
3838
+ }
3839
+ if (errorText.includes("Inputs are not valid")) {
3840
+ suggestions.push("Dataset item inputs don't match the prompt's inputSchema. Verify field names and types.");
3841
+ }
3842
+ if (errorText.includes("has no items") || errorText.includes("Dataset") && errorText.includes("not found")) {
3843
+ suggestions.push(`Upload data: mutagent prompts dataset add ${promptId} --file data.json`);
3844
+ }
3845
+ if (errorText.includes("Evaluations are not present")) {
3846
+ suggestions.push(`Create evaluation: mutagent prompts evaluation create ${promptId} --guided`);
3847
+ }
3848
+ if (errorText.includes("Trial") && errorText.includes("limit")) {
3849
+ suggestions.push("Trial optimization limit reached. Contact support to upgrade.");
3850
+ }
3649
3851
  if (!isJson) {
3650
- console.error(chalk7.red("Optimization failed. Missing requirements:"));
3852
+ console.error(chalk7.red(`
3853
+ Optimization failed:`));
3651
3854
  for (const msg of messages) {
3652
- console.error(chalk7.red(` - ${msg}`));
3855
+ console.error(chalk7.red(` ${msg}`));
3856
+ }
3857
+ if (suggestions.length > 0) {
3858
+ console.error(chalk7.yellow(`
3859
+ Suggested fixes:`));
3860
+ for (const s of suggestions) {
3861
+ console.error(chalk7.yellow(` → ${s}`));
3862
+ }
3653
3863
  }
3654
3864
  console.error("");
3655
3865
  console.error(PREREQUISITES_TEXT);
@@ -3894,216 +4104,20 @@ ${chalk8.dim("Exports to stdout by default. Use --output to save to a file.")}
3894
4104
  init_config();
3895
4105
  import { Command as Command5 } from "commander";
3896
4106
  import chalk9 from "chalk";
3897
- import { writeFileSync as writeFileSync3, existsSync as existsSync11 } from "fs";
4107
+ import { writeFileSync as writeFileSync3, existsSync as existsSync9 } from "fs";
3898
4108
  import { execSync } from "child_process";
3899
4109
  init_errors();
3900
4110
 
3901
- // src/lib/integrations/mastra.ts
3902
- import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
3903
- function renderPrerequisites(config) {
3904
- const keyPreview = config.apiKey.slice(0, 8) + "..." + config.apiKey.slice(-4);
3905
- return `✓ MUTAGENT_API_KEY: ${keyPreview}
3906
- ✓ MUTAGENT_ENDPOINT: ${config.endpoint}
3907
- ✓ API Connection: Verified`;
3908
- }
3909
- var mastraIntegration = {
3910
- name: "mastra",
3911
- description: "Mastra AI framework",
3912
- async detect() {
3913
- const files = ["mastra.config.ts", "mastra.config.js"];
3914
- const found = [];
3915
- for (const file of files) {
3916
- if (existsSync5(file)) {
3917
- found.push(file);
3918
- }
3919
- }
3920
- let hasMastraDep = false;
3921
- if (existsSync5("package.json")) {
3922
- try {
3923
- const pkg = JSON.parse(readFileSync5("package.json", "utf-8"));
3924
- const deps = { ...pkg.dependencies, ...pkg.devDependencies };
3925
- hasMastraDep = "@mastra/core" in deps;
3926
- } catch {}
3927
- }
3928
- return {
3929
- detected: found.length > 0 || hasMastraDep,
3930
- confidence: found.length > 0 ? 0.95 : hasMastraDep ? 0.7 : 0,
3931
- files: found
3932
- };
3933
- },
3934
- async generate(config) {
3935
- return `---
3936
- name: mutagent-mastra-integration
3937
- description: Integrate MutagenT with Mastra framework for prompt optimization and trace observability
3938
- framework: mastra
3939
- version: 1.0.0
3940
- ---
3941
-
3942
- # MutagenT + Mastra Integration
3943
-
3944
- ## Prerequisites Verification
3945
-
3946
- ${renderPrerequisites(config)}
3947
-
3948
- ## Installation
3949
-
3950
- \`\`\`bash
3951
- bun add @mutagent/sdk
3952
- # or
3953
- npm install @mutagent/sdk
3954
- \`\`\`
3955
-
3956
- ## Configuration
3957
-
3958
- ### 1. Environment Variables
3959
-
3960
- Add to your \`.env\` file:
3961
-
3962
- \`\`\`env
3963
- MUTAGENT_API_KEY=${config.apiKey}
3964
- MUTAGENT_ENDPOINT=${config.endpoint}
3965
- \`\`\`
3966
-
3967
- ### 2. Mastra Config Integration
3968
-
3969
- Update \`mastra.config.ts\`:
3970
-
3971
- \`\`\`typescript
3972
- import { defineConfig } from '@mastra/core';
3973
- import { MutagentObserver } from '@mutagent/sdk/mastra';
3974
-
3975
- export default defineConfig({
3976
- observers: [
3977
- new MutagentObserver({
3978
- apiKey: process.env.MUTAGENT_API_KEY!,
3979
- endpoint: process.env.MUTAGENT_ENDPOINT,
3980
- // Optional: auto-capture all agent traces
3981
- captureTraces: true,
3982
- })
3983
- ],
3984
- });
3985
- \`\`\`
3986
-
3987
- ### 3. Per-Agent Configuration
3988
-
3989
- For specific agents only:
3990
-
3991
- \`\`\`typescript
3992
- import { Agent } from '@mastra/core';
3993
- import { withMutagent } from '@mutagent/sdk/mastra';
3994
-
3995
- const agent = new Agent({
3996
- name: 'support-agent',
3997
- instructions: '...',
3998
- });
3999
-
4000
- // Wrap with MutagenT observability
4001
- export default withMutagent(agent, {
4002
- promptId: 'support-template',
4003
- autoOptimize: true,
4004
- });
4005
- \`\`\`
4006
-
4007
- ## Usage
4008
-
4009
- ### Trace Collection (Replaces Langfuse)
4010
-
4011
- All agent calls are automatically traced to MutagenT:
4012
-
4013
- \`\`\`typescript
4014
- const result = await agent.generate('How do I reset my password?');
4015
- // Trace automatically captured with latency, tokens, input/output
4016
- \`\`\`
4017
-
4018
- ### Prompt Optimization
4019
-
4020
- \`\`\`typescript
4021
- import { optimizePrompt } from '@mutagent/sdk';
4022
-
4023
- // Run optimization for a prompt
4024
- const optimized = await optimizePrompt({
4025
- promptId: 'support-template',
4026
- datasetId: 'support-tickets',
4027
- metric: 'response_quality',
4028
- });
4029
-
4030
- // Update agent with optimized prompt
4031
- agent.instructions = optimized.content;
4032
- \`\`\`
4033
-
4034
- ### Manual Tracing
4035
-
4036
- For custom traces:
4037
-
4038
- \`\`\`typescript
4039
- import { trace } from '@mutagent/sdk';
4040
-
4041
- const span = trace.start({
4042
- name: 'custom-operation',
4043
- promptId: 'my-prompt',
4044
- });
4045
-
4046
- try {
4047
- const result = await doSomething();
4048
- span.end({ output: result });
4049
- } catch (error) {
4050
- span.error(error);
4051
- }
4052
- \`\`\`
4053
-
4054
- ## Migration from Langfuse
4055
-
4056
- Replace Langfuse imports:
4057
-
4058
- \`\`\`typescript
4059
- // Before
4060
- import { Langfuse } from 'langfuse';
4061
-
4062
- // After
4063
- import { MutagentObserver } from '@mutagent/sdk/mastra';
4064
- \`\`\`
4065
-
4066
- ## Verification
4067
-
4068
- Run this to verify your integration:
4069
-
4070
- \`\`\`bash
4071
- mutagent integrate mastra --verify
4072
- \`\`\`
4073
-
4074
- ## Next Steps
4075
-
4076
- 1. Create your first prompt: \`mutagent prompts create --interactive\`
4077
- 2. Add a dataset: \`mutagent prompts datasets:add <prompt-id> --file data.jsonl\`
4078
- 3. Run optimization: \`mutagent prompts optimize <prompt-id> --dataset <dataset-id>\`
4079
- 4. View traces: \`mutagent traces list --prompt <prompt-id>\`
4080
-
4081
- ## CLI Commands Reference
4082
-
4083
- \`\`\`bash
4084
- # List prompts
4085
- mutagent prompts list
4086
-
4087
- # Get prompt with traces
4088
- mutagent prompts get <id> --with-datasets
4089
-
4090
- # Analyze traces
4091
- mutagent traces analyze <prompt-id>
4092
- \`\`\`
4093
- `;
4094
- }
4095
- };
4096
-
4097
4111
  // src/lib/integrations/langchain.ts
4098
- import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
4112
+ import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
4099
4113
  var langchainIntegration = {
4100
4114
  name: "langchain",
4101
4115
  description: "LangChain framework",
4102
4116
  async detect() {
4103
4117
  let hasLangchain = false;
4104
- if (existsSync6("package.json")) {
4118
+ if (existsSync5("package.json")) {
4105
4119
  try {
4106
- const pkg = JSON.parse(readFileSync6("package.json", "utf-8"));
4120
+ const pkg = JSON.parse(readFileSync5("package.json", "utf-8"));
4107
4121
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
4108
4122
  hasLangchain = "langchain" in deps || "@langchain/core" in deps;
4109
4123
  } catch {}
@@ -4235,15 +4249,15 @@ mutagent traces analyze <prompt-id>
4235
4249
  };
4236
4250
 
4237
4251
  // src/lib/integrations/langgraph.ts
4238
- import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
4252
+ import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
4239
4253
  var langgraphIntegration = {
4240
4254
  name: "langgraph",
4241
4255
  description: "LangGraph agent workflow framework",
4242
4256
  async detect() {
4243
4257
  let hasLanggraph = false;
4244
- if (existsSync7("package.json")) {
4258
+ if (existsSync6("package.json")) {
4245
4259
  try {
4246
- const pkg = JSON.parse(readFileSync7("package.json", "utf-8"));
4260
+ const pkg = JSON.parse(readFileSync6("package.json", "utf-8"));
4247
4261
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
4248
4262
  hasLanggraph = "@langchain/langgraph" in deps;
4249
4263
  } catch {}
@@ -4259,7 +4273,7 @@ var langgraphIntegration = {
4259
4273
  name: mutagent-langgraph-integration
4260
4274
  description: Integrate MutagenT with LangGraph for agent workflow observability
4261
4275
  framework: langgraph
4262
- version: 1.0.0
4276
+ version: 2.0.0
4263
4277
  ---
4264
4278
 
4265
4279
  # MutagenT + LangGraph Integration
@@ -4270,33 +4284,51 @@ version: 1.0.0
4270
4284
  - MUTAGENT_ENDPOINT: ${config.endpoint}
4271
4285
  - API Connection: Verified
4272
4286
 
4287
+ > **Note**: LangGraph is built on LangChain. The same \`MutagentCallbackHandler\` from
4288
+ > \`@mutagent/langchain\` works for both LangChain and LangGraph — no separate package needed.
4289
+
4273
4290
  ## Installation
4274
4291
 
4275
4292
  \`\`\`bash
4276
- # The @mutagent/langgraph package was installed automatically
4277
- # If you need to install manually:
4278
- bun add @mutagent/langgraph
4293
+ bun add @mutagent/langchain @mutagent/sdk
4279
4294
  # or
4280
- npm install @mutagent/langgraph
4295
+ npm install @mutagent/langchain @mutagent/sdk
4281
4296
  \`\`\`
4282
4297
 
4283
- ## Configuration
4298
+ > **Deprecation Notice**: The \`@mutagent/langgraph\` package is deprecated.
4299
+ > Use \`@mutagent/langchain\` instead — it supports both LangChain and LangGraph.
4284
4300
 
4285
- ### Graph with MutagenT Tracer
4301
+ ## Integration
4286
4302
 
4287
4303
  \`\`\`typescript
4288
- import { StateGraph, Annotation } from '@langchain/langgraph';
4289
- import { MutagentGraphTracer } from '@mutagent/langgraph';
4304
+ import { MutagentCallbackHandler } from '@mutagent/langchain';
4290
4305
  import { initTracing } from '@mutagent/sdk/tracing';
4291
4306
 
4292
- // Initialize tracing (or set MUTAGENT_API_KEY env var for auto-init)
4293
- initTracing({
4294
- apiKey: process.env.MUTAGENT_API_KEY!,
4295
- endpoint: process.env.MUTAGENT_ENDPOINT,
4307
+ // Initialize tracing (once at app startup)
4308
+ initTracing({ apiKey: process.env.MUTAGENT_API_KEY! });
4309
+
4310
+ // Create the handler
4311
+ const handler = new MutagentCallbackHandler({
4312
+ sessionId: 'my-session', // optional
4313
+ userId: 'user-123', // optional
4296
4314
  });
4297
4315
 
4298
- // Create tracer (no args needed — uses SDK tracing)
4299
- const tracer = new MutagentGraphTracer();
4316
+ // Pass to any LangGraph invoke/stream call
4317
+ const result = await graph.invoke(input, { callbacks: [handler] });
4318
+ \`\`\`
4319
+
4320
+ ## Full Graph Example
4321
+
4322
+ \`\`\`typescript
4323
+ import { StateGraph, Annotation } from '@langchain/langgraph';
4324
+ import { ChatOpenAI } from '@langchain/openai';
4325
+ import { MutagentCallbackHandler } from '@mutagent/langchain';
4326
+ import { initTracing } from '@mutagent/sdk/tracing';
4327
+
4328
+ // Initialize tracing (once at app startup)
4329
+ initTracing({ apiKey: process.env.MUTAGENT_API_KEY! });
4330
+
4331
+ const handler = new MutagentCallbackHandler();
4300
4332
 
4301
4333
  // Define your graph as usual
4302
4334
  const StateAnnotation = Annotation.Root({
@@ -4310,29 +4342,24 @@ const graph = new StateGraph(StateAnnotation)
4310
4342
  .addEdge('__start__', 'agent')
4311
4343
  .compile();
4312
4344
 
4313
- // Use lifecycle methods for tracing
4314
- tracer.handleGraphStart('agent-workflow', { input: 'Hello' });
4315
- const result = await graph.invoke({ input: 'Hello' });
4316
- tracer.handleGraphEnd({ output: result.output });
4345
+ // All nodes, edges, and LLM calls are automatically traced
4346
+ const result = await graph.invoke(
4347
+ { input: 'Hello' },
4348
+ { callbacks: [handler] },
4349
+ );
4317
4350
  \`\`\`
4318
4351
 
4319
- ### Per-Node and Edge Tracing
4352
+ ## Streaming
4320
4353
 
4321
4354
  \`\`\`typescript
4322
- // Track individual nodes
4323
- tracer.handleNodeStart('agent', { query: 'Hello' });
4324
- // ... node logic ...
4325
- tracer.handleNodeEnd('agent', { result: 'response' });
4326
-
4327
- // Track edge transitions
4328
- tracer.handleEdgeTransition('agent', 'tools', {
4329
- isConditional: true,
4330
- condition: 'needsTools',
4331
- conditionResult: true,
4332
- });
4355
+ const handler = new MutagentCallbackHandler();
4333
4356
 
4334
- tracer.handleNodeStart('tools', { toolName: 'search' });
4335
- tracer.handleNodeEnd('tools', { result: 'found' });
4357
+ for await (const event of graph.stream(
4358
+ { input: 'Hello' },
4359
+ { callbacks: [handler] },
4360
+ )) {
4361
+ console.log(event);
4362
+ }
4336
4363
  \`\`\`
4337
4364
 
4338
4365
  ## Verification
@@ -4346,30 +4373,20 @@ mutagent integrate langgraph --verify
4346
4373
  - Full guide: https://docs.mutagent.io/integrations/langgraph
4347
4374
  - API Reference: https://docs.mutagent.io/sdk/tracing
4348
4375
  - Dashboard: https://app.mutagent.io
4349
-
4350
- ## CLI Commands
4351
-
4352
- \`\`\`bash
4353
- # View workflow traces
4354
- mutagent traces list --prompt <graph-id>
4355
-
4356
- # Analyze node performance
4357
- mutagent traces analyze <node-prompt-id>
4358
- \`\`\`
4359
4376
  `;
4360
4377
  }
4361
4378
  };
4362
4379
 
4363
4380
  // src/lib/integrations/vercel-ai.ts
4364
- import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
4381
+ import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
4365
4382
  var vercelAiIntegration = {
4366
4383
  name: "vercel-ai",
4367
4384
  description: "Vercel AI SDK",
4368
4385
  async detect() {
4369
4386
  let hasAiSdk = false;
4370
- if (existsSync8("package.json")) {
4387
+ if (existsSync7("package.json")) {
4371
4388
  try {
4372
- const pkg = JSON.parse(readFileSync8("package.json", "utf-8"));
4389
+ const pkg = JSON.parse(readFileSync7("package.json", "utf-8"));
4373
4390
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
4374
4391
  hasAiSdk = "ai" in deps;
4375
4392
  } catch {}
@@ -4385,7 +4402,7 @@ var vercelAiIntegration = {
4385
4402
  name: mutagent-vercel-ai-integration
4386
4403
  description: Integrate MutagenT with Vercel AI SDK for streaming and edge functions
4387
4404
  framework: vercel-ai
4388
- version: 1.0.0
4405
+ version: 2.0.0
4389
4406
  ---
4390
4407
 
4391
4408
  # MutagenT + Vercel AI SDK Integration
@@ -4399,14 +4416,52 @@ version: 1.0.0
4399
4416
  ## Installation
4400
4417
 
4401
4418
  \`\`\`bash
4402
- # The @mutagent/vercel-ai package was installed automatically
4403
- # If you need to install manually:
4404
- bun add @mutagent/vercel-ai
4419
+ bun add @mutagent/vercel-ai @mutagent/sdk
4405
4420
  # or
4406
- npm install @mutagent/vercel-ai
4421
+ npm install @mutagent/vercel-ai @mutagent/sdk
4422
+
4423
+ # For Option A (OTel SpanExporter), also install:
4424
+ bun add @opentelemetry/sdk-trace-node @opentelemetry/sdk-trace-base
4407
4425
  \`\`\`
4408
4426
 
4409
- ## Integration
4427
+ ---
4428
+
4429
+ ## Option A (Recommended): OTel SpanExporter
4430
+
4431
+ Uses Vercel AI SDK's built-in \`experimental_telemetry\` with an OpenTelemetry exporter
4432
+ that sends spans directly to MutagenT.
4433
+
4434
+ \`\`\`typescript
4435
+ import { MutagentSpanExporter } from '@mutagent/vercel-ai';
4436
+ import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
4437
+ import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
4438
+ import { initTracing } from '@mutagent/sdk/tracing';
4439
+ import { generateText } from 'ai';
4440
+ import { openai } from '@ai-sdk/openai';
4441
+
4442
+ // Initialize MutagenT tracing
4443
+ initTracing({ apiKey: process.env.MUTAGENT_API_KEY! });
4444
+
4445
+ // Set up OTel with MutagenT exporter
4446
+ const provider = new NodeTracerProvider();
4447
+ provider.addSpanProcessor(
4448
+ new SimpleSpanProcessor(new MutagentSpanExporter())
4449
+ );
4450
+ provider.register();
4451
+
4452
+ // Use Vercel AI SDK normally with telemetry enabled
4453
+ const result = await generateText({
4454
+ model: openai('gpt-4'),
4455
+ prompt: 'Hello!',
4456
+ experimental_telemetry: { isEnabled: true },
4457
+ });
4458
+ \`\`\`
4459
+
4460
+ ---
4461
+
4462
+ ## Option B (Alternative): Middleware
4463
+
4464
+ Uses the Vercel AI SDK \`wrapLanguageModel\` middleware pattern.
4410
4465
 
4411
4466
  \`\`\`typescript
4412
4467
  // app/api/chat/route.ts
@@ -4415,13 +4470,10 @@ import { openai } from '@ai-sdk/openai';
4415
4470
  import { createMutagentMiddleware } from '@mutagent/vercel-ai';
4416
4471
  import { initTracing } from '@mutagent/sdk/tracing';
4417
4472
 
4418
- // Initialize tracing (or set MUTAGENT_API_KEY env var for auto-init)
4419
- initTracing({
4420
- apiKey: process.env.MUTAGENT_API_KEY!,
4421
- endpoint: process.env.MUTAGENT_ENDPOINT,
4422
- });
4473
+ // Initialize tracing (once at app startup)
4474
+ initTracing({ apiKey: process.env.MUTAGENT_API_KEY! });
4423
4475
 
4424
- // Create middleware (no args needed — uses SDK tracing)
4476
+ // Create middleware
4425
4477
  const middleware = createMutagentMiddleware();
4426
4478
 
4427
4479
  // Wrap your model with MutagenT middleware
@@ -4467,30 +4519,20 @@ mutagent integrate vercel-ai --verify
4467
4519
  - Full guide: https://docs.mutagent.io/integrations/vercel-ai
4468
4520
  - API Reference: https://docs.mutagent.io/sdk/tracing
4469
4521
  - Dashboard: https://app.mutagent.io
4470
-
4471
- ## CLI Commands
4472
-
4473
- \`\`\`bash
4474
- # View streaming traces
4475
- mutagent traces list --prompt <prompt-id>
4476
-
4477
- # Export for analysis
4478
- mutagent traces export --prompt <prompt-id> --format json
4479
- \`\`\`
4480
4522
  `;
4481
4523
  }
4482
4524
  };
4483
4525
 
4484
4526
  // src/lib/integrations/openai.ts
4485
- import { readFileSync as readFileSync9, existsSync as existsSync9 } from "fs";
4527
+ import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
4486
4528
  var openaiIntegration = {
4487
4529
  name: "openai",
4488
4530
  description: "OpenAI SDK integration with automatic tracing",
4489
4531
  async detect() {
4490
4532
  let hasOpenAI = false;
4491
- if (existsSync9("package.json")) {
4533
+ if (existsSync8("package.json")) {
4492
4534
  try {
4493
- const pkg = JSON.parse(readFileSync9("package.json", "utf-8"));
4535
+ const pkg = JSON.parse(readFileSync8("package.json", "utf-8"));
4494
4536
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
4495
4537
  hasOpenAI = "openai" in deps;
4496
4538
  } catch {}
@@ -4506,7 +4548,7 @@ var openaiIntegration = {
4506
4548
  name: mutagent-openai-integration
4507
4549
  description: Integrate MutagenT with OpenAI SDK for automatic tracing
4508
4550
  framework: openai
4509
- version: 1.0.0
4551
+ version: 2.0.0
4510
4552
  ---
4511
4553
 
4512
4554
  # MutagenT + OpenAI SDK Integration
@@ -4520,41 +4562,28 @@ version: 1.0.0
4520
4562
  ## Installation
4521
4563
 
4522
4564
  \`\`\`bash
4523
- # The @mutagent/openai package was installed automatically
4524
- # If you need to install manually:
4525
- bun add @mutagent/openai
4565
+ bun add @mutagent/openai @mutagent/sdk
4526
4566
  # or
4527
- npm install @mutagent/openai
4567
+ npm install @mutagent/openai @mutagent/sdk
4528
4568
  \`\`\`
4529
4569
 
4530
- ## Configuration
4531
-
4532
- ### 1. Environment Variables
4533
-
4534
- \`\`\`env
4535
- MUTAGENT_API_KEY=${config.apiKey}
4536
- MUTAGENT_ENDPOINT=${config.endpoint}
4537
- OPENAI_API_KEY=your-openai-api-key
4538
- \`\`\`
4539
-
4540
- ### 2. Traced OpenAI Client
4570
+ ## Integration
4541
4571
 
4542
4572
  \`\`\`typescript
4543
- import { MutagentOpenAI } from '@mutagent/openai';
4573
+ import OpenAI from 'openai';
4574
+ import { observeOpenAI } from '@mutagent/openai';
4544
4575
  import { initTracing } from '@mutagent/sdk/tracing';
4545
4576
 
4546
- // Initialize tracing (or set MUTAGENT_API_KEY env var for auto-init)
4547
- initTracing({
4548
- apiKey: process.env.MUTAGENT_API_KEY!,
4549
- endpoint: process.env.MUTAGENT_ENDPOINT,
4550
- });
4577
+ // Initialize tracing (once at app startup)
4578
+ initTracing({ apiKey: process.env.MUTAGENT_API_KEY! });
4551
4579
 
4552
- // Create a traced OpenAI client (drop-in replacement for OpenAI)
4553
- const openai = new MutagentOpenAI({
4554
- apiKey: process.env.OPENAI_API_KEY,
4580
+ // Wrap the OpenAI client ALL methods are automatically traced
4581
+ const openai = observeOpenAI(new OpenAI(), {
4582
+ sessionId: 'my-session', // optional
4583
+ userId: 'user-123', // optional
4555
4584
  });
4556
4585
 
4557
- // All calls are automatically traced
4586
+ // Use exactly as normal — chat, embeddings, images, audio all work
4558
4587
  const completion = await openai.chat.completions.create({
4559
4588
  model: 'gpt-4o',
4560
4589
  messages: [{ role: 'user', content: 'Hello!' }],
@@ -4563,21 +4592,12 @@ const completion = await openai.chat.completions.create({
4563
4592
  console.log(completion.choices[0].message.content);
4564
4593
  \`\`\`
4565
4594
 
4566
- ## Usage Examples
4595
+ ALL OpenAI SDK methods are preserved and traced automatically.
4596
+ No API changes — just wrap your client and everything is observed.
4567
4597
 
4568
- ### Chat Completion
4598
+ ## Streaming
4569
4599
 
4570
- \`\`\`typescript
4571
- const response = await openai.chat.completions.create({
4572
- model: 'gpt-4o',
4573
- messages: [
4574
- { role: 'system', content: 'You are a helpful assistant.' },
4575
- { role: 'user', content: 'What is TypeScript?' },
4576
- ],
4577
- });
4578
- \`\`\`
4579
-
4580
- ### Streaming
4600
+ Streaming works out of the box with no extra configuration:
4581
4601
 
4582
4602
  \`\`\`typescript
4583
4603
  const stream = await openai.chat.completions.create({
@@ -4591,299 +4611,39 @@ for await (const chunk of stream) {
4591
4611
  }
4592
4612
  \`\`\`
4593
4613
 
4594
- ## Verification
4595
-
4596
- \`\`\`bash
4597
- mutagent integrate openai --verify
4598
- \`\`\`
4599
-
4600
- ## Documentation
4601
-
4602
- - Full guide: https://docs.mutagent.io/integrations/openai
4603
- - API Reference: https://docs.mutagent.io/sdk/tracing
4604
- - Dashboard: https://app.mutagent.io
4605
-
4606
- ## CLI Reference
4607
-
4608
- \`\`\`bash
4609
- # View traces
4610
- mutagent traces list --prompt <prompt-id>
4611
-
4612
- # Analyze performance
4613
- mutagent traces analyze <prompt-id>
4614
-
4615
- # Export traces
4616
- mutagent traces export --format json
4617
- \`\`\`
4618
- `;
4619
- }
4620
- };
4621
-
4622
- // src/lib/integrations/claude-code.ts
4623
- import { readFileSync as readFileSync10, existsSync as existsSync10 } from "fs";
4624
- var claudeCodeIntegration = {
4625
- name: "claude-code",
4626
- description: "Claude Code SDK",
4627
- async detect() {
4628
- let hasClaudeCode = false;
4629
- if (existsSync10("package.json")) {
4630
- try {
4631
- const pkg = JSON.parse(readFileSync10("package.json", "utf-8"));
4632
- const deps = { ...pkg.dependencies, ...pkg.devDependencies };
4633
- hasClaudeCode = "@anthropic-ai/claude-code" in deps || "@anthropic-ai/sdk" in deps;
4634
- } catch {}
4635
- }
4636
- return {
4637
- detected: hasClaudeCode,
4638
- confidence: hasClaudeCode ? 0.85 : 0,
4639
- files: hasClaudeCode ? ["package.json"] : []
4640
- };
4641
- },
4642
- async generate(config) {
4643
- return `---
4644
- name: mutagent-claude-code-integration
4645
- description: Integrate MutagenT with Claude Code SDK
4646
- framework: claude-code
4647
- version: 1.0.0
4648
- ---
4649
-
4650
- # MutagenT + Claude Code SDK Integration
4651
-
4652
- ## Prerequisites Verification
4653
-
4654
- ✓ MUTAGENT_API_KEY: ${config.apiKey.slice(0, 8)}...${config.apiKey.slice(-4)}
4655
- ✓ MUTAGENT_ENDPOINT: ${config.endpoint}
4656
- ✓ API Connection: Verified
4657
-
4658
- ## Installation
4659
-
4660
- \`\`\`bash
4661
- bun add @mutagent/sdk
4662
- \`\`\`
4663
-
4664
- ## Basic Integration
4614
+ ## Embeddings
4665
4615
 
4666
4616
  \`\`\`typescript
4667
- import Anthropic from '@anthropic-ai/sdk';
4668
- import { MutagentTracer } from '@mutagent/sdk/claude';
4669
-
4670
- const tracer = new MutagentTracer({
4671
- apiKey: process.env.MUTAGENT_API_KEY!,
4672
- endpoint: process.env.MUTAGENT_ENDPOINT,
4673
- promptId: 'claude-prompt',
4674
- });
4675
-
4676
- const anthropic = new Anthropic({
4677
- apiKey: process.env.ANTHROPIC_API_KEY!,
4617
+ const embedding = await openai.embeddings.create({
4618
+ model: 'text-embedding-3-small',
4619
+ input: 'Hello world',
4678
4620
  });
4679
-
4680
- // Wrap API calls
4681
- const response = await tracer.wrap(
4682
- () => anthropic.messages.create({
4683
- model: 'claude-3-5-sonnet-20241022',
4684
- max_tokens: 1024,
4685
- messages: [{ role: 'user', content: 'Hello!' }],
4686
- })
4687
- );
4688
- \`\`\`
4689
-
4690
- ## With Optimized Prompts
4691
-
4692
- \`\`\`typescript
4693
- import { getOptimizedPrompt } from '@mutagent/sdk';
4694
-
4695
- const optimized = await getOptimizedPrompt('my-template');
4696
-
4697
- const response = await tracer.wrap(
4698
- () => anthropic.messages.create({
4699
- model: 'claude-3-5-sonnet-20241022',
4700
- system: optimized,
4701
- messages,
4702
- })
4703
- );
4704
- \`\`\`
4705
-
4706
- ## MCP Server Integration
4707
-
4708
- For Claude Desktop / MCP:
4709
-
4710
- \`\`\`json
4711
- {
4712
- "mcpServers": {
4713
- "mutagent": {
4714
- "command": "npx",
4715
- "args": ["-y", "@mutagent/mcp-server"],
4716
- "env": {
4717
- "MUTAGENT_API_KEY": "${config.apiKey}"
4718
- }
4719
- }
4720
- }
4721
- }
4722
- \`\`\`
4723
-
4724
- ## Verification
4725
-
4726
- \`\`\`bash
4727
- mutagent integrate claude-code --verify
4728
- \`\`\`
4729
-
4730
- ## CLI Commands
4731
-
4732
- \`\`\`bash
4733
- # View Claude traces
4734
- mutagent traces list --prompt <prompt-id>
4735
-
4736
- # Optimize Claude prompts
4737
- mutagent prompts optimize <prompt-id> --dataset <dataset-id>
4738
- \`\`\`
4739
- `;
4740
- }
4741
- };
4742
-
4743
- // src/lib/integrations/generic.ts
4744
- var genericIntegration = {
4745
- name: "generic",
4746
- description: "Generic OpenAI-compatible integration",
4747
- async detect() {
4748
- return {
4749
- detected: false,
4750
- confidence: 0,
4751
- files: []
4752
- };
4753
- },
4754
- async generate(config) {
4755
- return `---
4756
- name: mutagent-generic-integration
4757
- description: Generic OpenAI-compatible API integration
4758
- framework: generic
4759
- version: 1.0.0
4760
- ---
4761
-
4762
- # MutagenT + Generic (OpenAI-compatible) Integration
4763
-
4764
- ## Prerequisites Verification
4765
-
4766
- ✓ MUTAGENT_API_KEY: ${config.apiKey.slice(0, 8)}...${config.apiKey.slice(-4)}
4767
- ✓ MUTAGENT_ENDPOINT: ${config.endpoint}
4768
- ✓ API Connection: Verified
4769
-
4770
- ## Installation
4771
-
4772
- \`\`\`bash
4773
- bun add @mutagent/sdk
4774
- \`\`\`
4775
-
4776
- ## Fetch-based Integration
4777
-
4778
- \`\`\`typescript
4779
- import { trace } from '@mutagent/sdk';
4780
-
4781
- async function callLLM(prompt: string) {
4782
- const span = trace.start({
4783
- name: 'llm-call',
4784
- promptId: 'my-prompt',
4785
- input: { prompt },
4786
- });
4787
-
4788
- const start = Date.now();
4789
-
4790
- try {
4791
- const response = await fetch('https://api.openai.com/v1/chat/completions', {
4792
- method: 'POST',
4793
- headers: {
4794
- 'Authorization': \`Bearer \${process.env.OPENAI_API_KEY}\`,
4795
- 'Content-Type': 'application/json',
4796
- },
4797
- body: JSON.stringify({
4798
- model: 'gpt-4o',
4799
- messages: [{ role: 'user', content: prompt }],
4800
- }),
4801
- });
4802
-
4803
- const data = await response.json();
4804
- const latency = Date.now() - start;
4805
-
4806
- span.end({
4807
- output: data,
4808
- latency,
4809
- tokens: {
4810
- input: data.usage?.prompt_tokens || 0,
4811
- output: data.usage?.completion_tokens || 0,
4812
- },
4813
- });
4814
-
4815
- return data;
4816
- } catch (error) {
4817
- span.error(error);
4818
- throw error;
4819
- }
4820
- }
4821
- \`\`\`
4822
-
4823
- ## With Optimized Prompts
4824
-
4825
- \`\`\`typescript
4826
- import { getOptimizedPrompt } from '@mutagent/sdk';
4827
-
4828
- const optimized = await getOptimizedPrompt('template-id');
4829
- const result = await callLLM(optimized);
4830
- \`\`\`
4831
-
4832
- ## OpenAI SDK Wrapper
4833
-
4834
- \`\`\`typescript
4835
- import OpenAI from 'openai';
4836
- import { wrapOpenAI } from '@mutagent/sdk/openai';
4837
-
4838
- const openai = wrapOpenAI(
4839
- new OpenAI({ apiKey: process.env.OPENAI_API_KEY }),
4840
- {
4841
- mutagentApiKey: process.env.MUTAGENT_API_KEY!,
4842
- promptId: 'default',
4843
- }
4844
- );
4845
-
4846
- // All calls are traced
4847
- const completion = await openai.chat.completions.create({...});
4621
+ // Embedding call is traced automatically
4848
4622
  \`\`\`
4849
4623
 
4850
4624
  ## Verification
4851
4625
 
4852
4626
  \`\`\`bash
4853
- mutagent integrate generic --verify
4627
+ mutagent integrate openai --verify
4854
4628
  \`\`\`
4855
4629
 
4856
- ## CLI Commands
4857
-
4858
- \`\`\`bash
4859
- # View traces
4860
- mutagent traces list --prompt <prompt-id>
4630
+ ## Documentation
4861
4631
 
4862
- # Run evaluation
4863
- mutagent prompts evals:run <prompt-id> --dataset <dataset-id>
4864
- \`\`\`
4632
+ - Full guide: https://docs.mutagent.io/integrations/openai
4633
+ - API Reference: https://docs.mutagent.io/sdk/tracing
4634
+ - Dashboard: https://app.mutagent.io
4865
4635
  `;
4866
4636
  }
4867
4637
  };
4868
4638
 
4869
4639
  // src/lib/integrations/registry.ts
4870
4640
  var frameworkRegistry = new Map([
4871
- ["mastra", mastraIntegration],
4872
4641
  ["langchain", langchainIntegration],
4873
4642
  ["langgraph", langgraphIntegration],
4874
4643
  ["vercel-ai", vercelAiIntegration],
4875
- ["openai", openaiIntegration],
4876
- ["claude-code", claudeCodeIntegration],
4877
- ["generic", genericIntegration]
4644
+ ["openai", openaiIntegration]
4878
4645
  ]);
4879
4646
  var frameworkMetadata = [
4880
- {
4881
- name: "mastra",
4882
- displayName: "Mastra",
4883
- description: "Modern AI agent framework with observability built-in",
4884
- npmPackage: "@mastra/core",
4885
- website: "https://mastra.ai"
4886
- },
4887
4647
  {
4888
4648
  name: "langchain",
4889
4649
  displayName: "LangChain",
@@ -4897,7 +4657,7 @@ var frameworkMetadata = [
4897
4657
  displayName: "LangGraph",
4898
4658
  description: "Agent workflow framework built on LangChain",
4899
4659
  npmPackage: "@langchain/langgraph",
4900
- mutagentPackage: "@mutagent/langgraph",
4660
+ mutagentPackage: "@mutagent/langchain",
4901
4661
  website: "https://langchain-ai.github.io/langgraphjs/"
4902
4662
  },
4903
4663
  {
@@ -4915,20 +4675,6 @@ var frameworkMetadata = [
4915
4675
  npmPackage: "openai",
4916
4676
  mutagentPackage: "@mutagent/openai",
4917
4677
  website: "https://platform.openai.com"
4918
- },
4919
- {
4920
- name: "claude-code",
4921
- displayName: "Claude Code SDK",
4922
- description: "Native Anthropic integration for Claude",
4923
- npmPackage: "@anthropic-ai/claude-code",
4924
- website: "https://docs.anthropic.com"
4925
- },
4926
- {
4927
- name: "generic",
4928
- displayName: "Generic (OpenAI-compatible)",
4929
- description: "Any OpenAI-compatible API endpoint",
4930
- npmPackage: "openai",
4931
- website: "https://platform.openai.com"
4932
4678
  }
4933
4679
  ];
4934
4680
  function getFramework(name) {
@@ -4940,16 +4686,16 @@ function getFrameworkMetadata(name) {
4940
4686
 
4941
4687
  // src/commands/integrate.ts
4942
4688
  function detectPackageManager() {
4943
- if (existsSync11("bun.lockb") || existsSync11("bun.lock")) {
4689
+ if (existsSync9("bun.lockb") || existsSync9("bun.lock")) {
4944
4690
  return "bun";
4945
4691
  }
4946
- if (existsSync11("pnpm-lock.yaml")) {
4692
+ if (existsSync9("pnpm-lock.yaml")) {
4947
4693
  return "pnpm";
4948
4694
  }
4949
- if (existsSync11("yarn.lock")) {
4695
+ if (existsSync9("yarn.lock")) {
4950
4696
  return "yarn";
4951
4697
  }
4952
- if (existsSync11("package-lock.json")) {
4698
+ if (existsSync9("package-lock.json")) {
4953
4699
  return "npm";
4954
4700
  }
4955
4701
  try {
@@ -4978,8 +4724,6 @@ AI AGENT: Please determine the framework by:
4978
4724
  - \`@langchain/langgraph\` -> use \`mutagent integrate langgraph\`
4979
4725
  - \`ai\` (vercel) -> use \`mutagent integrate vercel-ai\`
4980
4726
  - \`openai\` -> use \`mutagent integrate openai\`
4981
- - \`@mastra/core\` -> use \`mutagent integrate mastra\`
4982
- - \`@anthropic-ai/claude-code\` -> use \`mutagent integrate claude-code\`
4983
4727
 
4984
4728
  ### Option 2: Ask the user
4985
4729
  "Which AI framework are you using?"
@@ -4987,9 +4731,6 @@ AI AGENT: Please determine the framework by:
4987
4731
  - LangGraph
4988
4732
  - Vercel AI SDK
4989
4733
  - OpenAI SDK
4990
- - Mastra
4991
- - Claude Code
4992
- - Generic (OpenAI-compatible)
4993
4734
 
4994
4735
  ### Next Steps
4995
4736
  1. Once determined, run: \`mutagent integrate <framework>\`
@@ -5006,12 +4747,12 @@ Examples:
5006
4747
  ${chalk9.dim("$")} mutagent integrate langchain --output ./INTEGRATION.md
5007
4748
  ${chalk9.dim("$")} mutagent integrate --list # List available frameworks
5008
4749
 
5009
- Frameworks: mastra, langchain, langgraph, vercel-ai, openai, claude-code, generic
4750
+ Frameworks: langchain, langgraph, vercel-ai, openai
5010
4751
 
5011
4752
  This is a SKILL LOADER for AI coding agents (Claude Code, Cursor, etc.).
5012
4753
  It returns INSTRUCTIONS that AI agents execute - it does NOT auto-install packages.
5013
4754
  `);
5014
- integrate.argument("[framework]", "Framework name (mastra, langchain, langgraph, vercel-ai, openai, claude-code, generic)").option("-o, --output <path>", "Save instructions to file").option("--raw", "Output raw markdown (no formatting)").option("--verify", "Verify integration after setup").action(async (frameworkArg, options) => {
4755
+ integrate.argument("[framework]", "Framework name (langchain, langgraph, vercel-ai, openai)").option("-o, --output <path>", "Save instructions to file").option("--raw", "Output raw markdown (no formatting)").option("--verify", "Verify integration after setup").action(async (frameworkArg, options) => {
5015
4756
  const isJson = getJsonFlag(integrate);
5016
4757
  const output = new OutputFormatter(isJson ? "json" : "table");
5017
4758
  try {
@@ -5109,7 +4850,7 @@ AI AGENT: Execute these steps using Bash for install, Write/Edit for code change
5109
4850
  init_sdk_client();
5110
4851
  import { Command as Command6 } from "commander";
5111
4852
  import chalk10 from "chalk";
5112
- import { readFileSync as readFileSync11 } from "fs";
4853
+ import { readFileSync as readFileSync9 } from "fs";
5113
4854
  init_errors();
5114
4855
  function createAgentsCommand() {
5115
4856
  const agents = new Command6("agents").description("Manage AI agents").addHelpText("after", `
@@ -5233,7 +4974,7 @@ ${chalk10.dim("Required: --name, --slug, and --system-prompt (or --file).")}
5233
4974
  try {
5234
4975
  let data;
5235
4976
  if (options.file) {
5236
- const content = readFileSync11(options.file, "utf-8");
4977
+ const content = readFileSync9(options.file, "utf-8");
5237
4978
  data = JSON.parse(content);
5238
4979
  } else if (options.name && options.slug && options.systemPrompt) {
5239
4980
  data = {
@@ -5267,7 +5008,7 @@ Examples:
5267
5008
  try {
5268
5009
  let data = {};
5269
5010
  if (options.file) {
5270
- const content = readFileSync11(options.file, "utf-8");
5011
+ const content = readFileSync9(options.file, "utf-8");
5271
5012
  data = JSON.parse(content);
5272
5013
  } else {
5273
5014
  if (options.name)
@@ -5562,7 +5303,7 @@ ${chalk11.dim("Persists organization ID for org-scoped API keys.")}
5562
5303
  init_sdk_client();
5563
5304
  import { Command as Command8 } from "commander";
5564
5305
  import chalk12 from "chalk";
5565
- import { readFileSync as readFileSync12 } from "fs";
5306
+ import { readFileSync as readFileSync10 } from "fs";
5566
5307
  init_errors();
5567
5308
  function parseSSELine(line) {
5568
5309
  if (!line || line.startsWith(":")) {
@@ -5724,7 +5465,7 @@ function parsePromptStyleInput(options) {
5724
5465
  function getInputJson(options) {
5725
5466
  if (options.file) {
5726
5467
  try {
5727
- return readFileSync12(options.file, "utf-8");
5468
+ return readFileSync10(options.file, "utf-8");
5728
5469
  } catch (err) {
5729
5470
  throw new MutagentError("FILE_READ_ERROR", `Failed to read input file: ${options.file}`, err instanceof Error ? err.message : "Check the file path and permissions");
5730
5471
  }
@@ -6077,7 +5818,7 @@ init_config();
6077
5818
  import { Command as Command11 } from "commander";
6078
5819
  import inquirer3 from "inquirer";
6079
5820
  import chalk15 from "chalk";
6080
- import { existsSync as existsSync12, readFileSync as readFileSync13, writeFileSync as writeFileSync4 } from "fs";
5821
+ import { existsSync as existsSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "fs";
6081
5822
  import { execSync as execSync2 } from "child_process";
6082
5823
  import { join as join5 } from "path";
6083
5824
  init_errors();
@@ -6130,16 +5871,16 @@ var FRAMEWORK_DETECTION_MAP = {
6130
5871
  }
6131
5872
  };
6132
5873
  function detectPackageManager2(cwd = process.cwd()) {
6133
- if (existsSync12(join5(cwd, "bun.lockb")) || existsSync12(join5(cwd, "bun.lock"))) {
5874
+ if (existsSync10(join5(cwd, "bun.lockb")) || existsSync10(join5(cwd, "bun.lock"))) {
6134
5875
  return "bun";
6135
5876
  }
6136
- if (existsSync12(join5(cwd, "pnpm-lock.yaml"))) {
5877
+ if (existsSync10(join5(cwd, "pnpm-lock.yaml"))) {
6137
5878
  return "pnpm";
6138
5879
  }
6139
- if (existsSync12(join5(cwd, "yarn.lock"))) {
5880
+ if (existsSync10(join5(cwd, "yarn.lock"))) {
6140
5881
  return "yarn";
6141
5882
  }
6142
- if (existsSync12(join5(cwd, "package-lock.json"))) {
5883
+ if (existsSync10(join5(cwd, "package-lock.json"))) {
6143
5884
  return "npm";
6144
5885
  }
6145
5886
  try {
@@ -6161,12 +5902,12 @@ function getInstallCommand2(pm, packages) {
6161
5902
  }
6162
5903
  function detectFrameworkFromPackageJson(cwd = process.cwd()) {
6163
5904
  const pkgPath = join5(cwd, "package.json");
6164
- if (!existsSync12(pkgPath)) {
5905
+ if (!existsSync10(pkgPath)) {
6165
5906
  return null;
6166
5907
  }
6167
5908
  let pkg;
6168
5909
  try {
6169
- pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
5910
+ pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
6170
5911
  } catch {
6171
5912
  return null;
6172
5913
  }
@@ -6182,7 +5923,7 @@ function detectFrameworkFromPackageJson(cwd = process.cwd()) {
6182
5923
  return null;
6183
5924
  }
6184
5925
  function hasRcConfig(cwd = process.cwd()) {
6185
- return existsSync12(join5(cwd, ".mutagentrc.json"));
5926
+ return existsSync10(join5(cwd, ".mutagentrc.json"));
6186
5927
  }
6187
5928
  function writeRcConfig(config, cwd = process.cwd()) {
6188
5929
  const rcPath = join5(cwd, ".mutagentrc.json");
@@ -6478,7 +6219,7 @@ Scanning ${scanPath}...
6478
6219
  // src/commands/skills.ts
6479
6220
  import { Command as Command13 } from "commander";
6480
6221
  import chalk17 from "chalk";
6481
- import { existsSync as existsSync13, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
6222
+ import { existsSync as existsSync11, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
6482
6223
  import { join as join6 } from "path";
6483
6224
  var SKILL_FRONTMATTER = `---
6484
6225
  name: mutagent-cli
@@ -6585,7 +6326,7 @@ that teaches coding agents how to use the MutagenT CLI effectively.
6585
6326
  const output = new OutputFormatter(isJson ? "json" : "table");
6586
6327
  const skillDir = join6(process.cwd(), SKILL_DIR);
6587
6328
  const skillPath = join6(skillDir, SKILL_FILE);
6588
- if (!existsSync13(skillDir)) {
6329
+ if (!existsSync11(skillDir)) {
6589
6330
  mkdirSync3(skillDir, { recursive: true });
6590
6331
  }
6591
6332
  const content = `${SKILL_FRONTMATTER}
@@ -6613,12 +6354,16 @@ ${SKILL_BODY}
6613
6354
  // src/bin/cli.ts
6614
6355
  init_config();
6615
6356
  var cliVersion = "0.1.1";
6616
- try {
6617
- const __dirname2 = dirname(fileURLToPath(import.meta.url));
6618
- const pkgPath = join7(__dirname2, "..", "..", "package.json");
6619
- const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
6620
- cliVersion = pkg.version ?? cliVersion;
6621
- } catch {}
6357
+ if (process.env.CLI_VERSION) {
6358
+ cliVersion = process.env.CLI_VERSION;
6359
+ } else {
6360
+ try {
6361
+ const __dirname2 = dirname(fileURLToPath(import.meta.url));
6362
+ const pkgPath = join7(__dirname2, "..", "..", "package.json");
6363
+ const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
6364
+ cliVersion = pkg.version ?? cliVersion;
6365
+ } catch {}
6366
+ }
6622
6367
  var program = new Command14;
6623
6368
  program.name("mutagent").description(`MutagenT CLI - AI-native prompt optimization platform
6624
6369
 
@@ -6656,7 +6401,7 @@ ${chalk18.yellow("Workflows:")}
6656
6401
  program.addHelpText("after", `
6657
6402
  ${chalk18.cyan("┌─ AI AGENT INTEGRATION HINT ────────────────────────────────────────────────┐")}
6658
6403
  ${chalk18.cyan("│")} ${chalk18.cyan("│")}
6659
- ${chalk18.cyan("│")} Frameworks: mastra, langchain, langgraph, vercel-ai, claude-code, generic ${chalk18.cyan("│")}
6404
+ ${chalk18.cyan("│")} Frameworks: langchain, langgraph, vercel-ai, openai ${chalk18.cyan("│")}
6660
6405
  ${chalk18.cyan("│")} ${chalk18.cyan("│")}
6661
6406
  ${chalk18.cyan("│")} Get integration guide: mutagent integrate <framework> ${chalk18.cyan("│")}
6662
6407
  ${chalk18.cyan("│")} Verify setup: mutagent integrate <framework> --verify ${chalk18.cyan("│")}
@@ -6695,5 +6440,5 @@ program.addCommand(createExploreCommand());
6695
6440
  program.addCommand(createSkillsCommand());
6696
6441
  program.parse();
6697
6442
 
6698
- //# debugId=769CE1E3092A705664756E2164756E21
6443
+ //# debugId=8F5D422F7273E03E64756E2164756E21
6699
6444
  //# sourceMappingURL=cli.js.map