@agentskit/cli 0.13.33 → 0.13.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -106,12 +106,12 @@ var providers = {
106
106
  anthropic: {
107
107
  label: "Anthropic",
108
108
  envKeys: ["ANTHROPIC_API_KEY"],
109
- defaultModel: "claude-3-5-sonnet-latest",
109
+ defaultModel: "claude-sonnet-4-6",
110
110
  factory: (c) => adapters.anthropic(c)
111
111
  },
112
112
  gemini: {
113
113
  label: "Gemini",
114
- envKeys: ["GEMINI_API_KEY"],
114
+ envKeys: ["GEMINI_API_KEY", "GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
115
115
  defaultModel: "gemini-2.5-flash",
116
116
  factory: (c) => adapters.gemini(c)
117
117
  },
@@ -130,14 +130,26 @@ var providers = {
130
130
  grok: {
131
131
  label: "xAI Grok",
132
132
  envKeys: ["XAI_API_KEY"],
133
- requiresModel: true,
133
+ defaultModel: "grok-4.20-0309-non-reasoning",
134
134
  factory: (c) => adapters.grok(c)
135
135
  },
136
136
  kimi: {
137
137
  label: "Kimi",
138
138
  envKeys: ["KIMI_API_KEY", "MOONSHOT_API_KEY"],
139
- requiresModel: true,
139
+ defaultModel: "kimi-k2-0711-preview",
140
140
  factory: (c) => adapters.kimi(c)
141
+ },
142
+ groq: {
143
+ label: "Groq",
144
+ envKeys: ["GROQ_API_KEY"],
145
+ defaultModel: "openai/gpt-oss-120b",
146
+ factory: (c) => adapters.groq(c)
147
+ },
148
+ openrouter: {
149
+ label: "OpenRouter",
150
+ envKeys: ["OPENROUTER_API_KEY"],
151
+ defaultModel: "~anthropic/claude-haiku-latest",
152
+ factory: (c) => adapters.openrouter(c)
141
153
  }
142
154
  };
143
155
  function createDemoAdapter(provider, model) {
@@ -433,7 +445,7 @@ ${lines.join("\n")}`, "info");
433
445
  {
434
446
  name: "provider",
435
447
  description: "Switch the adapter provider.",
436
- usage: "/provider openai|anthropic|gemini|ollama|deepseek|grok|kimi|demo",
448
+ usage: "/provider openai|anthropic|gemini|ollama|deepseek|grok|kimi|groq|openrouter|demo",
437
449
  run(ctx, args) {
438
450
  const value = args.trim();
439
451
  if (!value) {
@@ -1703,17 +1715,29 @@ function registerRunCommand(program) {
1703
1715
  }
1704
1716
  });
1705
1717
  }
1718
+
1719
+ // src/init-providers.ts
1706
1720
  var PROVIDER_IMPORT = {
1707
1721
  openai: "openai",
1708
1722
  anthropic: "anthropic",
1709
1723
  gemini: "gemini",
1710
- ollama: "ollama"
1724
+ ollama: "ollama",
1725
+ deepseek: "deepseek",
1726
+ grok: "grok",
1727
+ kimi: "kimi",
1728
+ groq: "groq",
1729
+ openrouter: "openrouter"
1711
1730
  };
1712
1731
  var PROVIDER_DEFAULT_MODEL = {
1713
1732
  openai: "gpt-4o-mini",
1714
1733
  anthropic: "claude-sonnet-4-6",
1715
1734
  gemini: "gemini-2.5-flash",
1716
1735
  ollama: "llama3.1",
1736
+ deepseek: "deepseek-chat",
1737
+ grok: "grok-4.20-0309-non-reasoning",
1738
+ kimi: "kimi-k2-0711-preview",
1739
+ groq: "openai/gpt-oss-120b",
1740
+ openrouter: "~anthropic/claude-haiku-latest",
1717
1741
  demo: "demo"
1718
1742
  };
1719
1743
  var PROVIDER_ENV_KEY = {
@@ -1721,8 +1745,15 @@ var PROVIDER_ENV_KEY = {
1721
1745
  anthropic: "ANTHROPIC_API_KEY",
1722
1746
  gemini: "GEMINI_API_KEY",
1723
1747
  ollama: null,
1748
+ deepseek: "DEEPSEEK_API_KEY",
1749
+ grok: "XAI_API_KEY",
1750
+ kimi: "KIMI_API_KEY",
1751
+ groq: "GROQ_API_KEY",
1752
+ openrouter: "OPENROUTER_API_KEY",
1724
1753
  demo: null
1725
1754
  };
1755
+
1756
+ // src/init.ts
1726
1757
  function adapterCall(provider, prefix = "process.env") {
1727
1758
  const model = PROVIDER_DEFAULT_MODEL[provider];
1728
1759
  if (provider === "demo") return `demoAdapter()`;
@@ -1730,6 +1761,11 @@ function adapterCall(provider, prefix = "process.env") {
1730
1761
  const envKey = PROVIDER_ENV_KEY[provider];
1731
1762
  return `${PROVIDER_IMPORT[provider]}({ apiKey: ${prefix}.${envKey} ?? '', model: '${model}' })`;
1732
1763
  }
1764
+ function denoAdapterCall(provider) {
1765
+ if (provider === "demo") return "demoAdapter()";
1766
+ if (provider === "ollama") return `ollama({ model: '${PROVIDER_DEFAULT_MODEL[provider]}' })`;
1767
+ return `${PROVIDER_IMPORT[provider]}({ apiKey: Deno.env.get('${PROVIDER_ENV_KEY[provider]}') ?? '', model: '${PROVIDER_DEFAULT_MODEL[provider]}' })`;
1768
+ }
1733
1769
  function viteAdapterCall(provider) {
1734
1770
  if (provider === "demo") return `demoAdapter()`;
1735
1771
  if (provider === "ollama") return `ollama({ model: '${PROVIDER_DEFAULT_MODEL[provider]}' })`;
@@ -2410,7 +2446,7 @@ function cloudflareWorkersStarter(ctx) {
2410
2446
  "itty-router": "^5.0.0"
2411
2447
  };
2412
2448
  if (ctx.provider !== "demo") deps["@agentskit/adapters"] = "^0.4.0";
2413
- const adapterCallEdge = ctx.provider === "demo" ? "demoAdapter()" : ctx.provider === "ollama" ? `ollama({ model: '${PROVIDER_DEFAULT_MODEL[ctx.provider]}' })` : `${PROVIDER_IMPORT[ctx.provider]}({ apiKey: env.${PROVIDER_ENV_KEY[ctx.provider]} ?? '', model: '${PROVIDER_DEFAULT_MODEL[ctx.provider]}' })`;
2449
+ const adapterCallEdge = adapterCall(ctx.provider, "env");
2414
2450
  const adapterImport2 = buildAdapterServerImport(ctx.provider);
2415
2451
  const demoSnippet = ctx.provider === "demo" ? demoAdapterSnippet() : "";
2416
2452
  const envKey = PROVIDER_ENV_KEY[ctx.provider];
@@ -2893,7 +2929,7 @@ export const useAuth = () => useContext(AuthCtx)
2893
2929
  };
2894
2930
  }
2895
2931
  function denoDeployStarter(ctx) {
2896
- const adapterCallEdge = ctx.provider === "demo" ? "demoAdapter()" : ctx.provider === "ollama" ? `ollama({ model: '${PROVIDER_DEFAULT_MODEL[ctx.provider]}' })` : `${PROVIDER_IMPORT[ctx.provider]}({ apiKey: Deno.env.get('${PROVIDER_ENV_KEY[ctx.provider]}') ?? '', model: '${PROVIDER_DEFAULT_MODEL[ctx.provider]}' })`;
2932
+ const adapterCallEdge = denoAdapterCall(ctx.provider);
2897
2933
  const adapterImport2 = ctx.provider === "demo" ? "" : `import { ${PROVIDER_IMPORT[ctx.provider]} } from 'npm:@agentskit/adapters'
2898
2934
  `;
2899
2935
  const demoSnippet = ctx.provider === "demo" ? demoAdapterSnippet() : "";
@@ -3078,8 +3114,8 @@ ${runCmd}
3078
3114
  ## Next steps
3079
3115
 
3080
3116
  - Open the AgentsKit docs at https://www.agentskit.io/docs
3081
- - Add a custom skill: https://www.agentskit.io/docs/concepts/skill
3082
- - Wire up RAG: https://www.agentskit.io/docs/recipes/rag-chat
3117
+ - Add a custom skill: https://www.agentskit.io/docs/get-started/concepts/skill
3118
+ - Wire up RAG: https://www.agentskit.io/docs/reference/recipes/rag-chat
3083
3119
 
3084
3120
  ## License
3085
3121
 
@@ -3162,7 +3198,12 @@ ${kleur__default.default.bold().green("\u25B2")} ${kleur__default.default.bold("
3162
3198
  { name: "OpenAI", value: "openai" },
3163
3199
  { name: "Anthropic", value: "anthropic" },
3164
3200
  { name: "Gemini", value: "gemini" },
3165
- { name: "Ollama (local, no key)", value: "ollama" }
3201
+ { name: "Ollama (local, no key)", value: "ollama" },
3202
+ { name: "DeepSeek", value: "deepseek" },
3203
+ { name: "xAI Grok", value: "grok" },
3204
+ { name: "Kimi", value: "kimi" },
3205
+ { name: "Groq", value: "groq" },
3206
+ { name: "OpenRouter", value: "openrouter" }
3166
3207
  ]
3167
3208
  });
3168
3209
  let tools = [];
@@ -3261,7 +3302,7 @@ function printNextSteps(options) {
3261
3302
 
3262
3303
  // src/commands/init.ts
3263
3304
  function registerInitCommand(program) {
3264
- program.command("init").description("Generate a starter project. Run with no flags for interactive mode.").option("--template <template>", "Starter template (react|nextjs|sveltekit|nuxt|ink|vite-ink|cloudflare-workers|bun|deno-deploy|expo|angular|runtime|multi-agent)").option("--dir <directory>", "Target directory", "agentskit-app").option("--provider <provider>", "LLM provider (openai|anthropic|gemini|ollama|demo)").option("--tools <tools>", "Comma-separated tools (web_search,filesystem,shell)").option("--memory <backend>", "Memory backend (none|file|sqlite)").option("--pm <packageManager>", "Package manager (pnpm|npm|yarn|bun)").option("-y, --yes", "Skip interactive prompts; use flag values + defaults").action(async (rawOptions) => {
3305
+ program.command("init").description("Generate a starter project. Run with no flags for interactive mode.").option("--template <template>", "Starter template (react|nextjs|sveltekit|nuxt|ink|vite-ink|cloudflare-workers|bun|deno-deploy|expo|angular|runtime|multi-agent)").option("--dir <directory>", "Target directory", "agentskit-app").option("--provider <provider>", "LLM provider (openai|anthropic|gemini|ollama|deepseek|grok|kimi|groq|openrouter|demo)").option("--tools <tools>", "Comma-separated tools (web_search,filesystem,shell)").option("--memory <backend>", "Memory backend (none|file|sqlite)").option("--pm <packageManager>", "Package manager (pnpm|npm|yarn|bun)").option("-y, --yes", "Skip interactive prompts; use flag values + defaults").action(async (rawOptions) => {
3265
3306
  const isCi = !process.stdout.isTTY || rawOptions.yes || rawOptions.template;
3266
3307
  let resolved;
3267
3308
  if (isCi) {
@@ -3296,20 +3337,206 @@ function registerInitCommand(program) {
3296
3337
  }
3297
3338
  });
3298
3339
  }
3299
- var PROVIDER_ENV_KEYS = {
3300
- openai: "OPENAI_API_KEY",
3301
- anthropic: "ANTHROPIC_API_KEY",
3302
- gemini: "GEMINI_API_KEY",
3303
- deepseek: "DEEPSEEK_API_KEY",
3304
- grok: "XAI_API_KEY",
3305
- kimi: "KIMI_API_KEY"
3306
- };
3307
- var PROVIDER_REACH_URLS = {
3308
- openai: "https://api.openai.com/v1/models",
3309
- anthropic: "https://api.anthropic.com/v1/messages",
3310
- gemini: "https://generativelanguage.googleapis.com/v1beta/models",
3311
- ollama: "http://localhost:11434/api/tags"
3312
- };
3340
+
3341
+ // src/provider-registry.ts
3342
+ var PROVIDER_REGISTRY = [
3343
+ {
3344
+ id: "demo",
3345
+ label: "Demo",
3346
+ runtime: "local",
3347
+ env: { status: "not-required", reason: "Demo adapter does not use provider credentials." },
3348
+ reachability: { status: "unsupported", reason: "Demo adapter has no upstream endpoint." },
3349
+ defaultModel: { status: "known", id: "demo" }
3350
+ },
3351
+ {
3352
+ id: "openai",
3353
+ label: "OpenAI",
3354
+ runtime: "cli",
3355
+ catalogId: "openai",
3356
+ env: { status: "required", keys: ["OPENAI_API_KEY"] },
3357
+ reachability: { status: "supported", url: "https://api.openai.com/v1/models" },
3358
+ defaultModel: { status: "known", id: "gpt-4o-mini" },
3359
+ doctorDefault: true
3360
+ },
3361
+ {
3362
+ id: "anthropic",
3363
+ label: "Anthropic",
3364
+ runtime: "cli",
3365
+ catalogId: "anthropic",
3366
+ env: { status: "required", keys: ["ANTHROPIC_API_KEY"] },
3367
+ reachability: { status: "supported", url: "https://api.anthropic.com/v1/messages" },
3368
+ defaultModel: { status: "known", id: "claude-sonnet-4-6" },
3369
+ doctorDefault: true
3370
+ },
3371
+ {
3372
+ id: "gemini",
3373
+ label: "Gemini",
3374
+ runtime: "cli",
3375
+ catalogId: "google",
3376
+ env: { status: "required", keys: ["GEMINI_API_KEY", "GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"] },
3377
+ reachability: { status: "supported", url: "https://generativelanguage.googleapis.com/v1beta/models" },
3378
+ defaultModel: { status: "known", id: "gemini-2.5-flash" },
3379
+ doctorDefault: true
3380
+ },
3381
+ {
3382
+ id: "ollama",
3383
+ label: "Ollama",
3384
+ runtime: "local",
3385
+ env: { status: "not-required", reason: "Ollama runs locally and does not require an API key." },
3386
+ reachability: { status: "supported", url: "http://localhost:11434/api/tags" },
3387
+ defaultModel: { status: "known", id: "llama3.1" },
3388
+ doctorDefault: true
3389
+ },
3390
+ {
3391
+ id: "deepseek",
3392
+ label: "DeepSeek",
3393
+ runtime: "cli",
3394
+ catalogId: "deepseek",
3395
+ env: { status: "required", keys: ["DEEPSEEK_API_KEY"] },
3396
+ reachability: { status: "supported", url: "https://api.deepseek.com/models" },
3397
+ defaultModel: { status: "known", id: "deepseek-chat" }
3398
+ },
3399
+ {
3400
+ id: "grok",
3401
+ label: "xAI Grok",
3402
+ runtime: "cli",
3403
+ catalogId: "xai",
3404
+ env: { status: "required", keys: ["XAI_API_KEY"] },
3405
+ reachability: { status: "supported", url: "https://api.x.ai/v1/models" },
3406
+ defaultModel: { status: "known", id: "grok-4.20-0309-non-reasoning" }
3407
+ },
3408
+ {
3409
+ id: "kimi",
3410
+ label: "Kimi",
3411
+ runtime: "cli",
3412
+ catalogId: "moonshotai",
3413
+ env: { status: "required", keys: ["KIMI_API_KEY", "MOONSHOT_API_KEY"] },
3414
+ reachability: { status: "supported", url: "https://api.moonshot.ai/v1/models" },
3415
+ defaultModel: { status: "known", id: "kimi-k2-0711-preview" }
3416
+ },
3417
+ {
3418
+ id: "groq",
3419
+ label: "Groq",
3420
+ runtime: "cli",
3421
+ catalogId: "groq",
3422
+ env: { status: "required", keys: ["GROQ_API_KEY"] },
3423
+ reachability: { status: "supported", url: "https://api.groq.com/openai/v1/models" },
3424
+ defaultModel: { status: "known", id: "openai/gpt-oss-120b" }
3425
+ },
3426
+ {
3427
+ id: "openrouter",
3428
+ label: "OpenRouter",
3429
+ runtime: "cli",
3430
+ catalogId: "openrouter",
3431
+ env: { status: "required", keys: ["OPENROUTER_API_KEY"] },
3432
+ reachability: { status: "supported", url: "https://openrouter.ai/api/v1/models" },
3433
+ defaultModel: { status: "known", id: "~anthropic/claude-haiku-latest" }
3434
+ },
3435
+ {
3436
+ id: "mistral",
3437
+ label: "Mistral",
3438
+ runtime: "adapter-only",
3439
+ catalogId: "mistral",
3440
+ env: { status: "required", keys: ["MISTRAL_API_KEY"] },
3441
+ reachability: { status: "supported", url: "https://api.mistral.ai/v1/models" },
3442
+ defaultModel: { status: "known", id: "codestral-latest" }
3443
+ },
3444
+ {
3445
+ id: "cohere",
3446
+ label: "Cohere",
3447
+ runtime: "adapter-only",
3448
+ catalogId: "cohere",
3449
+ env: { status: "required", keys: ["COHERE_API_KEY"] },
3450
+ reachability: { status: "supported", url: "https://api.cohere.com/v1/models" },
3451
+ defaultModel: { status: "known", id: "c4ai-aya-expanse-32b" }
3452
+ },
3453
+ {
3454
+ id: "together",
3455
+ label: "Together",
3456
+ runtime: "adapter-only",
3457
+ catalogId: "togetherai",
3458
+ env: { status: "required", keys: ["TOGETHER_API_KEY"] },
3459
+ reachability: { status: "supported", url: "https://api.together.xyz/v1/models" },
3460
+ defaultModel: { status: "known", id: "deepseek-ai/DeepSeek-R1" }
3461
+ },
3462
+ {
3463
+ id: "fireworks",
3464
+ label: "Fireworks",
3465
+ runtime: "adapter-only",
3466
+ catalogId: "fireworks-ai",
3467
+ env: { status: "required", keys: ["FIREWORKS_API_KEY"] },
3468
+ reachability: { status: "supported", url: "https://api.fireworks.ai/inference/v1/models" },
3469
+ defaultModel: { status: "known", id: "accounts/fireworks/models/deepseek-v4-flash" }
3470
+ },
3471
+ {
3472
+ id: "huggingface",
3473
+ label: "Hugging Face",
3474
+ runtime: "adapter-only",
3475
+ catalogId: "huggingface",
3476
+ env: { status: "required", keys: ["HF_TOKEN"] },
3477
+ reachability: { status: "supported", url: "https://router.huggingface.co/v1/models" },
3478
+ defaultModel: { status: "known", id: "deepseek-ai/DeepSeek-R1-0528" }
3479
+ },
3480
+ {
3481
+ id: "lmstudio",
3482
+ label: "LM Studio",
3483
+ runtime: "local",
3484
+ catalogId: "lmstudio",
3485
+ env: { status: "not-required", reason: "LM Studio runs locally and does not require a provider key." },
3486
+ reachability: { status: "supported", url: "http://127.0.0.1:1234/v1/models" },
3487
+ defaultModel: { status: "known", id: "openai/gpt-oss-20b" }
3488
+ },
3489
+ {
3490
+ id: "vllm",
3491
+ label: "vLLM",
3492
+ runtime: "local",
3493
+ env: { status: "not-required", reason: "vLLM is a local server and does not require a provider key." },
3494
+ reachability: { status: "supported", url: "http://localhost:8000/v1/models" },
3495
+ defaultModel: { status: "known", id: "meta-llama/Llama-3.1-8B-Instruct" }
3496
+ },
3497
+ {
3498
+ id: "llamacpp",
3499
+ label: "llama.cpp",
3500
+ runtime: "local",
3501
+ env: { status: "not-required", reason: "llama.cpp is a local server and does not require a provider key." },
3502
+ reachability: { status: "supported", url: "http://localhost:8080/v1/models" },
3503
+ defaultModel: { status: "known", id: "local-model" }
3504
+ },
3505
+ {
3506
+ id: "cerebras",
3507
+ label: "Cerebras",
3508
+ runtime: "adapter-only",
3509
+ catalogId: "cerebras",
3510
+ env: { status: "required", keys: ["CEREBRAS_API_KEY"] },
3511
+ reachability: { status: "supported", url: "https://api.cerebras.ai/v1/models" },
3512
+ defaultModel: { status: "known", id: "gpt-oss-120b" }
3513
+ }
3514
+ ];
3515
+ var DEFAULT_DOCTOR_PROVIDERS = PROVIDER_REGISTRY.filter((entry) => "doctorDefault" in entry && entry.doctorDefault === true).map((entry) => entry.id);
3516
+ function getProviderRegistryEntry(provider) {
3517
+ return PROVIDER_REGISTRY.find((entry) => entry.id === provider.toLowerCase());
3518
+ }
3519
+ function resolveProviderRegistryEntry(provider) {
3520
+ return getProviderRegistryEntry(provider) ?? {
3521
+ id: provider,
3522
+ label: provider,
3523
+ runtime: "adapter-only",
3524
+ env: { status: "unsupported", reason: "Provider is not in the CLI doctor registry." },
3525
+ reachability: { status: "unsupported", reason: "Provider is not in the CLI doctor registry." },
3526
+ defaultModel: { status: "unsupported", reason: "Provider is not in the CLI doctor registry." }
3527
+ };
3528
+ }
3529
+
3530
+ // src/doctor.ts
3531
+ function providerReachabilityFix(entry) {
3532
+ if (entry.id === "ollama") {
3533
+ return "Start Ollama: `ollama serve` (or install from https://ollama.com)";
3534
+ }
3535
+ if (entry.runtime === "local") {
3536
+ return `Start ${entry.label} server and verify its local endpoint`;
3537
+ }
3538
+ return "Check network / firewall / VPN settings";
3539
+ }
3313
3540
  async function checkNodeVersion() {
3314
3541
  const major = Number(process.versions.node.split(".")[0]);
3315
3542
  if (Number.isNaN(major)) {
@@ -3388,17 +3615,22 @@ async function checkPackageJson() {
3388
3615
  }
3389
3616
  }
3390
3617
  async function checkProviderEnv(provider) {
3391
- const envKey = PROVIDER_ENV_KEYS[provider];
3392
- if (!envKey) {
3393
- return { status: "skip", name: `${provider} API key`, detail: "No env-key requirement for this provider" };
3618
+ const entry = resolveProviderRegistryEntry(provider);
3619
+ if (entry.env.status === "unsupported") {
3620
+ return { status: "skip", name: `${provider} API key`, detail: entry.env.reason };
3621
+ }
3622
+ if (entry.env.status === "not-required") {
3623
+ return { status: "skip", name: `${provider} API key`, detail: entry.env.reason };
3394
3624
  }
3395
- const value = process.env[envKey];
3625
+ const envKey = entry.env.keys.find((key) => process.env[key]);
3626
+ const expectedKeys = entry.env.keys.join(" or ");
3627
+ const value = envKey ? process.env[envKey] : void 0;
3396
3628
  if (!value) {
3397
3629
  return {
3398
3630
  status: "skip",
3399
3631
  name: `${provider} API key`,
3400
- detail: `${envKey} not set`,
3401
- fix: `export ${envKey}=... (only needed if you use ${provider})`
3632
+ detail: `${expectedKeys} not set`,
3633
+ fix: `export ${entry.env.keys[0]}=... (only needed if you use ${provider})`
3402
3634
  };
3403
3635
  }
3404
3636
  if (value.length < 16) {
@@ -3412,12 +3644,12 @@ async function checkProviderEnv(provider) {
3412
3644
  return { status: "pass", name: `${provider} API key`, detail: `${envKey} set (${value.length} chars)` };
3413
3645
  }
3414
3646
  async function checkProviderReachable(provider, fetchImpl = fetch, timeoutMs = 4e3) {
3415
- const url = PROVIDER_REACH_URLS[provider];
3416
- if (!url) {
3417
- return { status: "skip", name: `${provider} reachable`, detail: "No reachability check configured" };
3647
+ const entry = resolveProviderRegistryEntry(provider);
3648
+ if (entry.reachability.status === "unsupported") {
3649
+ return { status: "skip", name: `${provider} reachable`, detail: entry.reachability.reason };
3418
3650
  }
3419
- const envKey = PROVIDER_ENV_KEYS[provider];
3420
- if (envKey && !process.env[envKey]) {
3651
+ const url = entry.reachability.url;
3652
+ if (entry.env.status === "required" && !entry.env.keys.some((key) => process.env[key])) {
3421
3653
  return { status: "skip", name: `${provider} reachable`, detail: "Skipped \u2014 no API key configured" };
3422
3654
  }
3423
3655
  const controller = new AbortController();
@@ -3445,12 +3677,23 @@ async function checkProviderReachable(provider, fetchImpl = fetch, timeoutMs = 4
3445
3677
  status: "fail",
3446
3678
  name: `${provider} reachable`,
3447
3679
  detail: `${url} \u2192 ${reason}`,
3448
- fix: provider === "ollama" ? "Start Ollama: `ollama serve` (or install from https://ollama.com)" : "Check network / firewall / VPN settings"
3680
+ fix: providerReachabilityFix(entry)
3449
3681
  };
3450
3682
  } finally {
3451
3683
  clearTimeout(timer);
3452
3684
  }
3453
3685
  }
3686
+ async function checkProviderDefaultModel(provider) {
3687
+ const entry = resolveProviderRegistryEntry(provider);
3688
+ if (entry.defaultModel.status === "unsupported") {
3689
+ return { status: "skip", name: `${provider} default model`, detail: entry.defaultModel.reason };
3690
+ }
3691
+ return {
3692
+ status: "pass",
3693
+ name: `${provider} default model`,
3694
+ detail: entry.defaultModel.id
3695
+ };
3696
+ }
3454
3697
  async function checkConfig() {
3455
3698
  try {
3456
3699
  const config = await loadConfig();
@@ -3471,7 +3714,7 @@ async function checkConfig() {
3471
3714
  }
3472
3715
  }
3473
3716
  async function runDoctor(options = {}) {
3474
- const providers2 = options.providers ?? ["openai", "anthropic", "gemini", "ollama"];
3717
+ const providers2 = options.providers ?? DEFAULT_DOCTOR_PROVIDERS;
3475
3718
  const fetchImpl = options.fetchImpl ?? fetch;
3476
3719
  const checks = [
3477
3720
  checkNodeVersion(),
@@ -3481,6 +3724,7 @@ async function runDoctor(options = {}) {
3481
3724
  ];
3482
3725
  for (const provider of providers2) {
3483
3726
  checks.push(checkProviderEnv(provider));
3727
+ checks.push(checkProviderDefaultModel(provider));
3484
3728
  if (!options.noNetwork) {
3485
3729
  checks.push(checkProviderReachable(provider, fetchImpl));
3486
3730
  }
@@ -3566,7 +3810,7 @@ function renderReport(report, opts = {}) {
3566
3810
  function registerDoctorCommand(program) {
3567
3811
  program.command("doctor").description("Diagnose your AgentsKit environment.").option("--no-network", "Skip provider reachability checks").option(
3568
3812
  "--providers <providers>",
3569
- "Comma-separated providers to check (default: openai,anthropic,gemini,ollama)"
3813
+ `Comma-separated providers to check (default: ${DEFAULT_DOCTOR_PROVIDERS.join(",")})`
3570
3814
  ).option("--json", "Emit JSON instead of formatted output").action(async (options) => {
3571
3815
  const providers2 = options.providers ? options.providers.split(",").map((p) => p.trim()).filter(Boolean) : void 0;
3572
3816
  const report = await runDoctor({
@@ -5562,7 +5806,7 @@ async function tryComponentAdd(name, options) {
5562
5806
  function registerAddCommand(program) {
5563
5807
  program.command("add <name>").description(
5564
5808
  'Add a ready-made agent or UI component from the AgentsKit registry (registry.agentskit.io). Auto-detects which: a component is scanned/validated against your project and installed transactionally; an agent is copied into ./agents. You own the code. e.g. `agentskit add docs-chat` (component) or `agentskit add research --run "\u2026"` (agent).'
5565
- ).option("--out <dir>", "Directory to install into (component: the port dir; agent: ./agents)").option("-f, --force", "Overwrite existing files").option("--registry <url>", "Registry base URL override (component install)").option("--run <task>", "Run the agent on this task right after adding it").option("--provider <provider>", "Provider for --run (openai, anthropic, gemini, ollama, demo)", "demo").option("--model <model>", "Model for --run").option("--api-key <key>", "API key for --run (else read from the provider env var)").action(
5809
+ ).option("--out <dir>", "Directory to install into (component: the port dir; agent: ./agents)").option("-f, --force", "Overwrite existing files").option("--registry <url>", "Registry base URL override (component install)").option("--run <task>", "Run the agent on this task right after adding it").option("--provider <provider>", "Provider for --run (openai, anthropic, gemini, ollama, groq, openrouter, demo)", "demo").option("--model <model>", "Model for --run").option("--api-key <key>", "API key for --run (else read from the provider env var)").action(
5566
5810
  async (agent, options) => {
5567
5811
  try {
5568
5812
  const outcome = await tryComponentAdd(agent, {