@mutagent/cli 0.1.227 → 0.1.229

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
@@ -344,6 +344,91 @@ function buildCreateProviderBody(data) {
344
344
  return body;
345
345
  }
346
346
 
347
+ // src/lib/sdk-mappers.ts
348
+ import { Provider as SDKProviderEnum } from "@mutagent/sdk/models";
349
+ function isProviderType(value) {
350
+ return PROVIDER_TYPES.includes(value);
351
+ }
352
+ function narrowProviderType(value) {
353
+ return isProviderType(value) ? value : value;
354
+ }
355
+ function toIsoString(value) {
356
+ if (value === null || value === undefined)
357
+ return null;
358
+ return value instanceof Date ? value.toISOString() : value;
359
+ }
360
+ function toAgent(sdk) {
361
+ return {
362
+ id: sdk.id,
363
+ name: sdk.name,
364
+ slug: sdk.slug,
365
+ description: sdk.description,
366
+ systemPrompt: sdk.systemPrompt,
367
+ model: sdk.model,
368
+ maxTurns: sdk.maxTurns,
369
+ permissionMode: sdk.permissionMode,
370
+ allowedTools: sdk.allowedTools,
371
+ disallowedTools: sdk.disallowedTools,
372
+ status: sdk.status,
373
+ isPublic: sdk.isPublic,
374
+ metadata: sdk.metadata,
375
+ tags: sdk.tags,
376
+ createdBy: sdk.createdBy,
377
+ createdAt: toIsoString(sdk.createdAt),
378
+ updatedAt: toIsoString(sdk.updatedAt)
379
+ };
380
+ }
381
+ function toAgentList(sdk) {
382
+ return sdk.map(toAgent);
383
+ }
384
+ function toWorkspace(sdk) {
385
+ return {
386
+ id: sdk.id,
387
+ name: sdk.name,
388
+ description: sdk.description,
389
+ slug: sdk.slug,
390
+ isDefault: sdk.isDefault,
391
+ metadata: sdk.metadata,
392
+ createdBy: sdk.createdBy,
393
+ createdAt: toIsoString(sdk.createdAt),
394
+ updatedAt: toIsoString(sdk.updatedAt)
395
+ };
396
+ }
397
+ function toWorkspaceList(sdk) {
398
+ return sdk.map(toWorkspace);
399
+ }
400
+ function toProvider(sdk) {
401
+ return {
402
+ id: sdk.id,
403
+ name: sdk.name,
404
+ provider: narrowProviderType(sdk.provider),
405
+ hostedFamily: sdk.hostedFamily ?? null,
406
+ baseUrl: sdk.baseUrl,
407
+ isActive: sdk.isActive,
408
+ metadata: sdk.metadata,
409
+ createdBy: sdk.createdBy,
410
+ createdAt: toIsoString(sdk.createdAt),
411
+ updatedAt: toIsoString(sdk.updatedAt)
412
+ };
413
+ }
414
+ function toProviderList(sdk) {
415
+ return sdk.map(toProvider);
416
+ }
417
+ function toProviderTestResult(sdk) {
418
+ return {
419
+ success: sdk.success,
420
+ provider: sdk.provider ?? undefined,
421
+ latencyMs: sdk.latencyMs ?? undefined,
422
+ message: sdk.message,
423
+ error: sdk.error ?? undefined,
424
+ models: sdk.models ?? undefined
425
+ };
426
+ }
427
+ var PROVIDER_TYPES;
428
+ var init_sdk_mappers = __esm(() => {
429
+ PROVIDER_TYPES = Object.values(SDKProviderEnum);
430
+ });
431
+
347
432
  // src/lib/sdk-client.ts
348
433
  var exports_sdk_client = {};
349
434
  __export(exports_sdk_client, {
@@ -467,7 +552,7 @@ class SDKClientWrapper {
467
552
  status: filters?.status
468
553
  });
469
554
  return {
470
- data: response.result.data,
555
+ data: toAgentList(response.result.data),
471
556
  total: response.result.total
472
557
  };
473
558
  } catch (error) {
@@ -479,7 +564,7 @@ class SDKClientWrapper {
479
564
  const response = await this.sdk.agents.getAgent({
480
565
  id: parseInt(id, 10)
481
566
  });
482
- return response;
567
+ return toAgent(response);
483
568
  } catch (error) {
484
569
  this.handleError(error);
485
570
  }
@@ -501,7 +586,7 @@ class SDKClientWrapper {
501
586
  metadata: data.metadata ?? undefined,
502
587
  tags: data.tags ?? undefined
503
588
  });
504
- return response;
589
+ return toAgent(response);
505
590
  } catch (error) {
506
591
  this.handleError(error);
507
592
  }
@@ -525,7 +610,7 @@ class SDKClientWrapper {
525
610
  tags: data.tags ?? undefined
526
611
  }
527
612
  });
528
- return response;
613
+ return toAgent(response);
529
614
  } catch (error) {
530
615
  this.handleError(error);
531
616
  }
@@ -544,7 +629,7 @@ class SDKClientWrapper {
544
629
  const response = await this.sdk.workspaces.listWorkspaces({
545
630
  includeInactive: false
546
631
  });
547
- const workspaces = response.workspaces;
632
+ const workspaces = toWorkspaceList(response.workspaces);
548
633
  const offset = filters?.offset ?? 0;
549
634
  const limit = filters?.limit ?? workspaces.length;
550
635
  return {
@@ -560,7 +645,7 @@ class SDKClientWrapper {
560
645
  const response = await this.sdk.workspaces.getWorkspace({
561
646
  wsId: id
562
647
  });
563
- return response;
648
+ return toWorkspace(response);
564
649
  } catch (error) {
565
650
  this.handleError(error);
566
651
  }
@@ -571,9 +656,8 @@ class SDKClientWrapper {
571
656
  provider: filters?.type,
572
657
  includeInactive: true
573
658
  });
574
- const raw = response;
575
- const configs = raw.result?.configs ?? raw.configs ?? [];
576
- const total = raw.result?.total ?? raw.total ?? configs.length;
659
+ const configs = toProviderList(response.configs);
660
+ const total = response.total;
577
661
  const offset = filters?.offset ?? 0;
578
662
  const limit = filters?.limit ?? configs.length;
579
663
  return {
@@ -589,7 +673,7 @@ class SDKClientWrapper {
589
673
  const response = await this.sdk.providerConfigs.getProvider({
590
674
  id
591
675
  });
592
- return response;
676
+ return toProvider(response);
593
677
  } catch (error) {
594
678
  this.handleError(error);
595
679
  }
@@ -628,19 +712,19 @@ class SDKClientWrapper {
628
712
  if (this.workspaceResolution === "none" && this.organizationId) {
629
713
  try {
630
714
  const response = await this.sdk.workspaces.listWorkspaces({ includeInactive: false });
631
- const workspaces = response.workspaces;
715
+ const workspaces = toWorkspaceList(response.workspaces);
632
716
  if (workspaces.length === 1 && workspaces[0]) {
633
- this.workspaceId = String(workspaces[0].id);
717
+ this.workspaceId = workspaces[0].id;
634
718
  this.workspaceResolution = "sole";
635
719
  } else if (workspaces.length > 1) {
636
720
  const defaultWs = workspaces.find((ws) => ws.isDefault);
637
721
  if (defaultWs) {
638
- this.workspaceId = String(defaultWs.id);
722
+ this.workspaceId = defaultWs.id;
639
723
  this.workspaceResolution = "configured";
640
724
  } else {
641
725
  const first = workspaces[0] ?? undefined;
642
726
  if (first) {
643
- this.workspaceId = this.workspaceId ?? String(first.id);
727
+ this.workspaceId = this.workspaceId ?? first.id;
644
728
  this.workspaceResolution = "ambiguous";
645
729
  }
646
730
  }
@@ -665,7 +749,7 @@ class SDKClientWrapper {
665
749
  const response = await this.sdk.providerConfigs.testProvider({
666
750
  id
667
751
  });
668
- return response;
752
+ return toProviderTestResult(response);
669
753
  } catch (error) {
670
754
  this.handleError(error);
671
755
  }
@@ -696,7 +780,7 @@ class SDKClientWrapper {
696
780
  baseUrl: data.baseUrl
697
781
  }
698
782
  });
699
- return { ...response, workspaceId };
783
+ return { ...toProvider(response), workspaceId };
700
784
  } catch (error) {
701
785
  this.handleError(error);
702
786
  }
@@ -778,6 +862,7 @@ var sdkClient = null;
778
862
  var init_sdk_client = __esm(() => {
779
863
  init_errors();
780
864
  init_config();
865
+ init_sdk_mappers();
781
866
  });
782
867
 
783
868
  // src/bin/cli.ts
@@ -2253,6 +2338,442 @@ import { Provider as ProviderCatalogId } from "@mutagent/sdk/models";
2253
2338
  init_sdk_client();
2254
2339
  import chalk8 from "chalk";
2255
2340
  init_errors();
2341
+
2342
+ // src/lib/api-format.ts
2343
+ init_errors();
2344
+
2345
+ // ../mutagent/src/modules/tenancy/providers/catalog.ts
2346
+ var apiKeyField = (description) => ({
2347
+ name: "apiKey",
2348
+ label: "API key",
2349
+ required: true,
2350
+ treatment: "secret",
2351
+ validation: { rule: "non-empty-string", minLength: 8 },
2352
+ description
2353
+ });
2354
+ var baseUrlOverrideField = {
2355
+ name: "baseUrl",
2356
+ label: "Base URL override",
2357
+ required: false,
2358
+ treatment: "plain",
2359
+ validation: { rule: "https-url" },
2360
+ description: "Route requests through a proxy or a regional endpoint instead of the default one."
2361
+ };
2362
+ var modelAllowListField = {
2363
+ name: "modelAllowList",
2364
+ label: "Model allow-list",
2365
+ required: false,
2366
+ treatment: "plain",
2367
+ validation: { rule: "string-list" },
2368
+ description: "Narrow the models this configuration offers. Entries outside the provider policy are ignored."
2369
+ };
2370
+ var directApiKeyFields = (keyDescription) => [
2371
+ apiKeyField(keyDescription),
2372
+ baseUrlOverrideField,
2373
+ modelAllowListField
2374
+ ];
2375
+ var azureFields = [
2376
+ {
2377
+ name: "resourceEndpoint",
2378
+ label: "Resource endpoint",
2379
+ required: true,
2380
+ treatment: "plain",
2381
+ validation: { rule: "https-url" },
2382
+ description: "The Azure resource endpoint, e.g. https://my-resource.openai.azure.com."
2383
+ },
2384
+ apiKeyField("The key issued for the Azure resource."),
2385
+ {
2386
+ name: "deploymentName",
2387
+ label: "Deployment name",
2388
+ required: true,
2389
+ treatment: "plain",
2390
+ validation: { rule: "non-empty-string", minLength: 1 },
2391
+ description: "Azure addresses a model by the name given to its deployment, not by model id."
2392
+ },
2393
+ {
2394
+ name: "apiVersion",
2395
+ label: "API version",
2396
+ required: false,
2397
+ treatment: "plain",
2398
+ validation: {
2399
+ rule: "pattern",
2400
+ pattern: "^\\d{4}-\\d{2}-\\d{2}(-preview)?$",
2401
+ hint: "An ISO date, optionally suffixed -preview.",
2402
+ examples: ["2024-08-01-preview", "2023-06-01", "2025-01-01"],
2403
+ counterExamples: ["2024-8-1", "24-08-01", "2024-08-01-beta", "latest"]
2404
+ },
2405
+ description: "Pin the Azure API version. Defaults to the current stable version when omitted."
2406
+ }
2407
+ ];
2408
+ var vertexFields = [
2409
+ {
2410
+ name: "projectId",
2411
+ label: "Project ID",
2412
+ required: true,
2413
+ treatment: "plain",
2414
+ validation: {
2415
+ rule: "pattern",
2416
+ pattern: "^[a-z][a-z0-9-]{4,28}[a-z0-9]$",
2417
+ hint: "A Google Cloud project ID: 6 to 30 lowercase characters, starting with a letter.",
2418
+ examples: ["my-project-123", "abcdef", "my-gcp-project"],
2419
+ counterExamples: ["ab", "My-Project", "1project", "my_project"]
2420
+ },
2421
+ description: "The Google Cloud project that holds the Vertex AI entitlement."
2422
+ },
2423
+ {
2424
+ name: "region",
2425
+ label: "Region",
2426
+ required: true,
2427
+ treatment: "plain",
2428
+ validation: {
2429
+ rule: "pattern",
2430
+ pattern: "^(global|(?:us|europe|asia|australia|northamerica|southamerica|africa|me)-[a-z]+\\d+)$",
2431
+ hint: "A Vertex location: a continent prefix, a direction and an index — or `global`.",
2432
+ examples: [
2433
+ "us-central1",
2434
+ "europe-west4",
2435
+ "europe-west12",
2436
+ "asia-northeast1",
2437
+ "northamerica-northeast1",
2438
+ "southamerica-east1",
2439
+ "australia-southeast1",
2440
+ "africa-south1",
2441
+ "me-central2",
2442
+ "global"
2443
+ ],
2444
+ counterExamples: ["zz-qqqqqq9", "us-central", "US-CENTRAL1", "us_central1", "1-west1"]
2445
+ },
2446
+ description: "The Vertex location the models are served from."
2447
+ },
2448
+ {
2449
+ name: "serviceAccountKey",
2450
+ label: "Service-account credential",
2451
+ required: true,
2452
+ treatment: "secret",
2453
+ validation: { rule: "json-object" },
2454
+ description: "The service-account key JSON granting Vertex AI access to the project."
2455
+ },
2456
+ modelAllowListField
2457
+ ];
2458
+ var PROVIDER_CATALOG = [
2459
+ {
2460
+ id: "openai",
2461
+ label: "OpenAI",
2462
+ kind: "direct",
2463
+ credentialFields: directApiKeyFields("An OpenAI API key, issued from the OpenAI platform."),
2464
+ modelPolicy: {
2465
+ mode: "floor",
2466
+ floor: "5.5",
2467
+ knownMembers: ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-5.5"],
2468
+ summary: "GPT models at or above 5.5. FR-CORE-008 states the floor and then enumerates the members current at writing; the floor is the rule, the enumeration is the snapshot."
2469
+ },
2470
+ description: "GPT models served directly by OpenAI."
2471
+ },
2472
+ {
2473
+ id: "anthropic",
2474
+ label: "Anthropic",
2475
+ kind: "direct",
2476
+ credentialFields: directApiKeyFields("An Anthropic API key, issued from the Anthropic console."),
2477
+ modelPolicy: {
2478
+ mode: "explicit",
2479
+ models: [
2480
+ "claude-opus-5",
2481
+ "claude-sonnet-5",
2482
+ "claude-fable-5",
2483
+ "claude-opus-4-8",
2484
+ "claude-haiku-4-5"
2485
+ ],
2486
+ summary: "The Claude 5 family, plus Opus 4.8 and Haiku 4.5."
2487
+ },
2488
+ description: "Claude models served directly by Anthropic."
2489
+ },
2490
+ {
2491
+ id: "google",
2492
+ label: "Google Gemini",
2493
+ kind: "direct",
2494
+ credentialFields: directApiKeyFields("A Google AI Studio API key."),
2495
+ modelPolicy: {
2496
+ mode: "floor",
2497
+ floor: "3.1",
2498
+ summary: "Gemini 3.1 Pro and above. The floor is 3.1; nothing older is offered."
2499
+ },
2500
+ description: "Gemini models served directly by Google AI Studio."
2501
+ },
2502
+ {
2503
+ id: "moonshot",
2504
+ label: "Moonshot AI",
2505
+ kind: "direct",
2506
+ credentialFields: directApiKeyFields("A Moonshot AI platform API key."),
2507
+ modelPolicy: {
2508
+ mode: "explicit",
2509
+ models: ["kimi-k3"],
2510
+ summary: "Kimi K3, the 1M-context model. The 256K models are all K2-generation and are not offered."
2511
+ },
2512
+ description: "Kimi models served directly by Moonshot AI."
2513
+ },
2514
+ {
2515
+ id: "glm",
2516
+ label: "z.ai (GLM)",
2517
+ kind: "direct",
2518
+ credentialFields: directApiKeyFields("A z.ai API key."),
2519
+ modelPolicy: {
2520
+ mode: "explicit",
2521
+ models: ["glm-5.2"],
2522
+ summary: "GLM-5.2."
2523
+ },
2524
+ description: "GLM models served directly by z.ai."
2525
+ },
2526
+ {
2527
+ id: "deepseek",
2528
+ label: "DeepSeek",
2529
+ kind: "direct",
2530
+ credentialFields: directApiKeyFields("A DeepSeek platform API key."),
2531
+ modelPolicy: {
2532
+ mode: "explicit",
2533
+ models: ["deepseek-v4-flash", "deepseek-v4-pro"],
2534
+ summary: "The DeepSeek V4 pair — Flash and Pro."
2535
+ },
2536
+ description: "DeepSeek models served directly by DeepSeek."
2537
+ },
2538
+ {
2539
+ id: "xai",
2540
+ label: "xAI",
2541
+ kind: "direct",
2542
+ credentialFields: directApiKeyFields("An xAI API key."),
2543
+ modelPolicy: {
2544
+ mode: "floor",
2545
+ floor: "4.5",
2546
+ summary: "Grok 4.5 and above. The floor is 4.5; nothing older is offered."
2547
+ },
2548
+ description: "Grok models served directly by xAI."
2549
+ },
2550
+ {
2551
+ id: "azure",
2552
+ label: "Azure",
2553
+ kind: "gateway",
2554
+ hostedFamilies: ["openai", "anthropic"],
2555
+ credentialFields: azureFields,
2556
+ modelPolicy: {
2557
+ mode: "derived",
2558
+ from: ["openai", "anthropic"],
2559
+ addressing: {
2560
+ openai: {
2561
+ scheme: "deployment-name",
2562
+ pattern: "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$",
2563
+ examples: ["my-gpt-5-6-deployment", "prod_gpt", "gpt56sol"],
2564
+ counterExamples: ["gpt-5.6-sol", "claude-opus-5@20260115", "has space", ""]
2565
+ },
2566
+ anthropic: {
2567
+ scheme: "deployment-name",
2568
+ pattern: "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$",
2569
+ examples: ["my-claude-deployment", "prod_claude"],
2570
+ counterExamples: ["claude-opus-5@20260115", "gpt-5.6-sol", "has space", ""]
2571
+ }
2572
+ },
2573
+ summary: "The OpenAI and Anthropic rosters, each model addressed by the name of its Azure deployment."
2574
+ },
2575
+ description: "Azure AI Foundry, hosting OpenAI and Anthropic models. One configuration per hosted family."
2576
+ },
2577
+ {
2578
+ id: "vertex",
2579
+ label: "Google Vertex",
2580
+ kind: "gateway",
2581
+ hostedFamilies: ["gemini", "anthropic"],
2582
+ credentialFields: vertexFields,
2583
+ modelPolicy: {
2584
+ mode: "derived",
2585
+ from: ["gemini", "anthropic"],
2586
+ addressing: {
2587
+ gemini: {
2588
+ scheme: "plain",
2589
+ pattern: "^(?!.*@)[a-zA-Z0-9][a-zA-Z0-9.\\-]*$",
2590
+ examples: ["gemini-3.1-pro", "gemini-3.1-flash", "gemini-3.1-pro-preview"],
2591
+ counterExamples: [
2592
+ "gemini-3.1-pro@20260115",
2593
+ "us.anthropic.claude-opus-5-v1:0",
2594
+ "has space",
2595
+ ""
2596
+ ]
2597
+ },
2598
+ anthropic: {
2599
+ scheme: "dated",
2600
+ pattern: "^[a-zA-Z0-9][a-zA-Z0-9.\\-]*@\\d{8}$",
2601
+ examples: ["claude-opus-5@20260115", "claude-sonnet-5@20251022"],
2602
+ counterExamples: [
2603
+ "claude-opus-5",
2604
+ "claude-opus-5@",
2605
+ "claude-opus-5@2026",
2606
+ "gemini-3.1-pro"
2607
+ ]
2608
+ }
2609
+ },
2610
+ summary: "The Gemini and Anthropic rosters. Anthropic models are @-dated on Vertex; Gemini models are not."
2611
+ },
2612
+ description: "Google Vertex AI, hosting Gemini and Anthropic models. One configuration per hosted family."
2613
+ },
2614
+ {
2615
+ id: "bedrock",
2616
+ label: "AWS Bedrock",
2617
+ kind: "gateway",
2618
+ hostedFamilies: ["anthropic"],
2619
+ credentialFields: [
2620
+ {
2621
+ name: "region",
2622
+ label: "Region",
2623
+ required: true,
2624
+ treatment: "plain",
2625
+ validation: {
2626
+ rule: "pattern",
2627
+ pattern: "^[a-z]{2}(-gov)?-[a-z]+-\\d+$",
2628
+ hint: "An AWS region: a two-letter geography, a direction and an index.",
2629
+ examples: [
2630
+ "us-east-1",
2631
+ "eu-central-1",
2632
+ "ap-southeast-1",
2633
+ "sa-east-1",
2634
+ "me-south-1",
2635
+ "af-south-1",
2636
+ "il-central-1",
2637
+ "mx-central-1",
2638
+ "us-gov-west-1"
2639
+ ],
2640
+ counterExamples: ["us-east", "US-EAST-1", "useast1", "europe-west4"]
2641
+ },
2642
+ description: "The AWS region the Bedrock models are invoked in."
2643
+ },
2644
+ {
2645
+ name: "apiKey",
2646
+ label: "Bearer API key",
2647
+ required: true,
2648
+ treatment: "secret",
2649
+ validation: {
2650
+ rule: "pattern",
2651
+ pattern: "^(?!AKIA)[^\\s:]+$",
2652
+ hint: "A single opaque bearer token. Long-lived AWS access key and secret pairs are not accepted.",
2653
+ examples: ["bedrock-api-key-abc123", "ABSKQmVkcm9ja0FQSUtleQ=="],
2654
+ counterExamples: [
2655
+ "AKIAIOSFODNN7EXAMPLE",
2656
+ "AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG",
2657
+ "someid:somesecret",
2658
+ "has space"
2659
+ ]
2660
+ },
2661
+ description: "A Bedrock bearer API key. This is the only credential type Bedrock accepts here."
2662
+ },
2663
+ {
2664
+ name: "inferenceProfile",
2665
+ label: "Inference profile",
2666
+ required: false,
2667
+ treatment: "plain",
2668
+ validation: { rule: "non-empty-string", minLength: 1 },
2669
+ description: "Pin a cross-region inference profile. Defaults to the profile for the configured region."
2670
+ }
2671
+ ],
2672
+ modelPolicy: {
2673
+ mode: "derived",
2674
+ from: ["anthropic"],
2675
+ addressing: {
2676
+ anthropic: {
2677
+ scheme: "inference-profile",
2678
+ pattern: "^(us|eu|apac)\\.[a-z0-9-]+\\.[a-zA-Z0-9.\\-]+(:\\d+)?$",
2679
+ examples: [
2680
+ "us.anthropic.claude-opus-5-v1:0",
2681
+ "eu.anthropic.claude-sonnet-5-v1:0",
2682
+ "apac.anthropic.claude-haiku-4-5-v1:0"
2683
+ ],
2684
+ counterExamples: [
2685
+ "anthropic.claude-opus-5-v1:0",
2686
+ "claude-opus-5",
2687
+ "claude-opus-5@20260115"
2688
+ ]
2689
+ }
2690
+ },
2691
+ summary: "The Anthropic roster, addressed as region-prefixed inference-profile IDs."
2692
+ },
2693
+ description: "AWS Bedrock, hosting Anthropic models. Bearer API key only."
2694
+ },
2695
+ {
2696
+ id: "custom",
2697
+ label: "Custom (OpenAI or Anthropic compatible)",
2698
+ kind: "direct",
2699
+ credentialFields: [
2700
+ {
2701
+ name: "baseUrl",
2702
+ label: "Base URL",
2703
+ required: true,
2704
+ treatment: "plain",
2705
+ validation: { rule: "https-url" },
2706
+ description: "The endpoint serving the API. Pick its wire format below."
2707
+ },
2708
+ apiKeyField("The key the endpoint expects, sent as a bearer token."),
2709
+ {
2710
+ name: "wireFormat",
2711
+ label: "Wire format",
2712
+ required: false,
2713
+ treatment: "plain",
2714
+ validation: { rule: "one-of", values: ["openai", "anthropic"] },
2715
+ description: "Whether the endpoint speaks the OpenAI or the Anthropic request shape. Defaults to OpenAI when left unset — an endpoint that expects Anthropic's shape needs this set to 'anthropic'."
2716
+ },
2717
+ modelAllowListField
2718
+ ],
2719
+ modelPolicy: {
2720
+ mode: "open",
2721
+ summary: "Whatever the configured endpoint publishes."
2722
+ },
2723
+ description: "Any endpoint speaking an OpenAI-compatible or Anthropic-compatible API — self-hosted or third-party."
2724
+ }
2725
+ ];
2726
+ var CATALOG_BY_ID = new Map(PROVIDER_CATALOG.map((entry) => [entry.id, entry]));
2727
+ function getProviderCatalogEntry(id) {
2728
+ return CATALOG_BY_ID.get(id);
2729
+ }
2730
+ function getCredentialField(entry, name) {
2731
+ return entry.credentialFields.find((field) => field.name === name);
2732
+ }
2733
+ // src/lib/api-format.ts
2734
+ var API_FORMAT_WIRE_NAME = "wireFormat";
2735
+ function apiFormatValuesFor(providerType) {
2736
+ const entry = getProviderCatalogEntry(providerType);
2737
+ if (!entry)
2738
+ return;
2739
+ const field = getCredentialField(entry, API_FORMAT_WIRE_NAME);
2740
+ if (!field)
2741
+ return;
2742
+ return field.validation.rule === "one-of" ? field.validation.values : undefined;
2743
+ }
2744
+ function providerAcceptsApiFormat(providerType) {
2745
+ const entry = getProviderCatalogEntry(providerType);
2746
+ return entry !== undefined && entryAcceptsApiFormat(entry);
2747
+ }
2748
+ function entryAcceptsApiFormat(entry) {
2749
+ return getCredentialField(entry, API_FORMAT_WIRE_NAME) !== undefined;
2750
+ }
2751
+ function providersAcceptingApiFormat(catalog = PROVIDER_CATALOG) {
2752
+ return catalog.filter(entryAcceptsApiFormat).map((entry) => entry.id);
2753
+ }
2754
+ function apiFormatHelpText() {
2755
+ const accepting = providersAcceptingApiFormat();
2756
+ if (accepting.length === 0) {
2757
+ return "API format spoken by the endpoint (no catalog entry currently declares one)";
2758
+ }
2759
+ const values = [...new Set(accepting.flatMap((id) => apiFormatValuesFor(id) ?? []))];
2760
+ const scope = `${accepting.join(", ")} only`;
2761
+ return values.length > 0 ? `API format the endpoint speaks — ${scope}: ${values.join(", ")}` : `API format the endpoint speaks — ${scope}`;
2762
+ }
2763
+ function validateApiFormat(providerType, value) {
2764
+ if (!providerAcceptsApiFormat(providerType)) {
2765
+ const accepting = providersAcceptingApiFormat();
2766
+ throw new MutagentError("API_FORMAT_NOT_APPLICABLE", accepting.length > 0 ? `--api-format applies only to ${accepting.join(", ")}. '${providerType}' speaks its own API.` : `--api-format applies to no provider in the catalog. '${providerType}' speaks its own API.`, accepting.length > 0 ? `Remove --api-format, or use --provider ${accepting.join(" | ")}` : "Remove --api-format");
2767
+ }
2768
+ const values = apiFormatValuesFor(providerType);
2769
+ if (!values)
2770
+ return;
2771
+ if (!values.includes(value)) {
2772
+ throw new MutagentError("INVALID_API_FORMAT", `'${value}' is not an API format that '${providerType}' speaks.`, `${providerType} accepts: ${values.join(", ")}`);
2773
+ }
2774
+ }
2775
+
2776
+ // src/commands/providers/add.ts
2256
2777
  var GATEWAY_HOSTED_FAMILIES = {
2257
2778
  azure: ["openai", "anthropic"],
2258
2779
  vertex: ["gemini", "anthropic"],
@@ -2277,10 +2798,12 @@ function collectCredentialFields(options) {
2277
2798
  fields.projectId = options.projectId;
2278
2799
  if (options.region)
2279
2800
  fields.region = options.region;
2801
+ if (options.apiFormat)
2802
+ fields[API_FORMAT_WIRE_NAME] = options.apiFormat;
2280
2803
  return fields;
2281
2804
  }
2282
2805
  function registerAddCommand(parent) {
2283
- parent.command("add").description("Add a new provider configuration").requiredOption("-p, --provider <type>", "Provider type (openai, anthropic, azure, ...)").requiredOption("-n, --name <name>", "Display name for this provider").option("-k, --api-key <key>", "API key for the provider (every entry except Google Vertex)").option("--service-account-key <json>", "Google Vertex service-account credential JSON").option("--hosted-family <family>", `Hosted model family for gateway providers: ${HOSTED_FAMILIES.join(", ")}`).option("--base-url <url>", "Custom base URL for the provider API").option("--resource-endpoint <url>", "Azure resource endpoint").option("--deployment-name <name>", "Azure deployment name").option("--api-version <version>", "Azure API version (e.g. 2024-08-01-preview)").option("--project-id <id>", "Google Vertex project ID").option("--region <region>", "Region (Vertex location, or AWS Bedrock region)").option("--set-default", "Set as the default provider of its kind").addHelpText("after", `
2806
+ parent.command("add").description("Add a new provider configuration").requiredOption("-p, --provider <type>", "Provider type (openai, anthropic, azure, ...)").requiredOption("-n, --name <name>", "Display name for this provider").option("-k, --api-key <key>", "API key for the provider (every entry except Google Vertex)").option("--service-account-key <json>", "Google Vertex service-account credential JSON").option("--hosted-family <family>", `Hosted model family for gateway providers: ${HOSTED_FAMILIES.join(", ")}`).option("--base-url <url>", "Custom base URL for the provider API").option("--api-format <format>", apiFormatHelpText()).option("--resource-endpoint <url>", "Azure resource endpoint").option("--deployment-name <name>", "Azure deployment name").option("--api-version <version>", "Azure API version (e.g. 2024-08-01-preview)").option("--project-id <id>", "Google Vertex project ID").option("--region <region>", "Region (Vertex location, or AWS Bedrock region)").option("--set-default", "Set as the default provider of its kind").addHelpText("after", `
2284
2807
  Examples:
2285
2808
  ${chalk8.dim("$")} mutagent providers add --provider openai --name "My OpenAI" --api-key $OPENAI_API_KEY
2286
2809
  ${chalk8.dim("$")} mutagent providers add --provider azure --name "Azure GPT" --api-key $KEY \\
@@ -2288,10 +2811,16 @@ Examples:
2288
2811
  ${chalk8.dim("$")} mutagent providers add --provider bedrock --name "Bedrock Claude" --api-key $KEY \\
2289
2812
  --hosted-family anthropic --region us-east-1
2290
2813
  ${chalk8.dim("$")} mutagent providers add --provider custom --name "Ollama" --api-key none --base-url https://ollama.internal --json
2814
+ ${chalk8.dim("$")} mutagent providers add --provider custom --name "Claude-compatible" --api-key $KEY \\
2815
+ --base-url https://llm.internal --api-format anthropic
2291
2816
 
2292
2817
  Gateway providers (${[...GATEWAY_PROVIDERS].join(", ")}) serve another vendor's models and
2293
2818
  require --hosted-family. Direct providers must not set it.
2294
2819
 
2820
+ ${apiFormatHelpText()}. An endpoint speaking the Anthropic request shape needs
2821
+ --api-format anthropic; left unset, the server's default applies. Passing it to a
2822
+ provider that speaks its own API is an error, not a silent no-op.
2823
+
2295
2824
  Providers are configured for your workspace. Set the target with:
2296
2825
  ${chalk8.dim("$")} mutagent config set workspace <workspace-id>
2297
2826
 
@@ -2326,6 +2855,9 @@ AI Agent Directive:
2326
2855
  } else if (isGateway && allowedFamilies.length > 1) {
2327
2856
  throw new MutagentError("MISSING_HOSTED_FAMILY", `'${providerType}' is a gateway and needs to know which model family it serves.`, `Add --hosted-family <${allowedFamilies.join("|")}>`);
2328
2857
  }
2858
+ if (options.apiFormat) {
2859
+ validateApiFormat(providerType, options.apiFormat);
2860
+ }
2329
2861
  const client = await getSDKClient();
2330
2862
  const workspaceId = client.requireUnambiguousWorkspace();
2331
2863
  const credentialFields = collectCredentialFields(options);
@@ -2357,6 +2889,9 @@ AI Agent Directive:
2357
2889
  if (options.hostedFamily) {
2358
2890
  console.log(` Serves: ${options.hostedFamily}`);
2359
2891
  }
2892
+ if (options.apiFormat) {
2893
+ console.log(` API format: ${options.apiFormat}`);
2894
+ }
2360
2895
  console.log(` Workspace: ${workspaceId}`);
2361
2896
  console.log(` URL: ${providerLink(created.id)}`);
2362
2897
  if (options.setDefault) {
@@ -5134,5 +5669,5 @@ program.addCommand(createInstallCommand());
5134
5669
  program.addCommand(createFeedbackCommand());
5135
5670
  program.parse();
5136
5671
 
5137
- //# debugId=850D997C527DFF0A64756E2164756E21
5672
+ //# debugId=A14DCC239481ABD264756E2164756E21
5138
5673
  //# sourceMappingURL=cli.js.map