@kindgi/cli 0.2.0 → 0.3.0-rc.0

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.
Files changed (154) hide show
  1. package/README.md +12 -5
  2. package/dist/cli.js +4 -3
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/agents.d.ts.map +1 -1
  5. package/dist/commands/agents.js +75 -19
  6. package/dist/commands/agents.js.map +1 -1
  7. package/dist/commands/approval-wait.d.ts +90 -0
  8. package/dist/commands/approval-wait.d.ts.map +1 -0
  9. package/dist/commands/approval-wait.js +154 -0
  10. package/dist/commands/approval-wait.js.map +1 -0
  11. package/dist/commands/artifacts.d.ts.map +1 -1
  12. package/dist/commands/artifacts.js +131 -14
  13. package/dist/commands/artifacts.js.map +1 -1
  14. package/dist/commands/auth.d.ts.map +1 -1
  15. package/dist/commands/auth.js +48 -5
  16. package/dist/commands/auth.js.map +1 -1
  17. package/dist/commands/deploy.js +7 -3
  18. package/dist/commands/deploy.js.map +1 -1
  19. package/dist/commands/deployments.d.ts.map +1 -1
  20. package/dist/commands/deployments.js +36 -13
  21. package/dist/commands/deployments.js.map +1 -1
  22. package/dist/commands/doctor.d.ts +3 -2
  23. package/dist/commands/doctor.d.ts.map +1 -1
  24. package/dist/commands/doctor.js +47 -14
  25. package/dist/commands/doctor.js.map +1 -1
  26. package/dist/commands/eval-runs.d.ts.map +1 -1
  27. package/dist/commands/eval-runs.js +21 -9
  28. package/dist/commands/eval-runs.js.map +1 -1
  29. package/dist/commands/helpers.d.ts +31 -1
  30. package/dist/commands/helpers.d.ts.map +1 -1
  31. package/dist/commands/helpers.js +45 -2
  32. package/dist/commands/helpers.js.map +1 -1
  33. package/dist/commands/init.js +5 -4
  34. package/dist/commands/init.js.map +1 -1
  35. package/dist/commands/mail-triggers.d.ts.map +1 -1
  36. package/dist/commands/mail-triggers.js +27 -3
  37. package/dist/commands/mail-triggers.js.map +1 -1
  38. package/dist/commands/promote.d.ts.map +1 -1
  39. package/dist/commands/promote.js +133 -11
  40. package/dist/commands/promote.js.map +1 -1
  41. package/dist/commands/provenance.d.ts.map +1 -1
  42. package/dist/commands/provenance.js +13 -5
  43. package/dist/commands/provenance.js.map +1 -1
  44. package/dist/commands/providers.d.ts.map +1 -1
  45. package/dist/commands/providers.js +47 -4
  46. package/dist/commands/providers.js.map +1 -1
  47. package/dist/commands/schedules.d.ts.map +1 -1
  48. package/dist/commands/schedules.js +25 -9
  49. package/dist/commands/schedules.js.map +1 -1
  50. package/dist/commands/skills.d.ts +16 -0
  51. package/dist/commands/skills.d.ts.map +1 -1
  52. package/dist/commands/skills.js +122 -36
  53. package/dist/commands/skills.js.map +1 -1
  54. package/dist/commands/webhooks.d.ts.map +1 -1
  55. package/dist/commands/webhooks.js +21 -5
  56. package/dist/commands/webhooks.js.map +1 -1
  57. package/dist/config.d.ts +8 -0
  58. package/dist/config.d.ts.map +1 -1
  59. package/dist/config.js +11 -0
  60. package/dist/config.js.map +1 -1
  61. package/dist/context.d.ts +7 -3
  62. package/dist/context.d.ts.map +1 -1
  63. package/dist/context.js +1 -0
  64. package/dist/context.js.map +1 -1
  65. package/dist/dev/runtime-image.d.ts +1 -1
  66. package/dist/dev/runtime-image.d.ts.map +1 -1
  67. package/dist/dev/runtime-image.js +1 -1
  68. package/dist/dev/runtime-image.js.map +1 -1
  69. package/dist/errors.d.ts.map +1 -1
  70. package/dist/errors.js +14 -1
  71. package/dist/errors.js.map +1 -1
  72. package/dist/exports/plan.d.ts.map +1 -1
  73. package/dist/exports/plan.js +50 -0
  74. package/dist/exports/plan.js.map +1 -1
  75. package/dist/init/augment-scaffolder.d.ts +1 -1
  76. package/dist/init/augment-scaffolder.js +9 -8
  77. package/dist/init/augment-scaffolder.js.map +1 -1
  78. package/dist/init/java-augment.d.ts.map +1 -1
  79. package/dist/init/java-augment.js +7 -6
  80. package/dist/init/java-augment.js.map +1 -1
  81. package/dist/init/python-augment.d.ts.map +1 -1
  82. package/dist/init/python-augment.js +7 -6
  83. package/dist/init/python-augment.js.map +1 -1
  84. package/dist/init/scala-augment.js +7 -6
  85. package/dist/init/scala-augment.js.map +1 -1
  86. package/dist/main.d.ts +3 -0
  87. package/dist/main.d.ts.map +1 -1
  88. package/dist/main.js +1 -0
  89. package/dist/main.js.map +1 -1
  90. package/dist/providers/presets/anthropic.json +15 -3
  91. package/dist/providers/presets/azure-openai.json +10 -2
  92. package/dist/providers/presets/bedrock.json +6 -2
  93. package/dist/providers/presets/gemini-api.json +6 -2
  94. package/dist/providers/presets/openai.json +15 -3
  95. package/dist/sdk-skills/kindgi-authoring-agents/SKILL.md +21 -9
  96. package/dist/sdk-skills/kindgi-authoring-flows/SKILL.md +5 -3
  97. package/dist/sdk-skills/kindgi-authoring-guardrails/SKILL.md +202 -68
  98. package/dist/sdk-skills/kindgi-authoring-mcp-servers/SKILL.md +12 -188
  99. package/dist/sdk-skills/kindgi-authoring-mcp-servers/common-mistakes.md +44 -0
  100. package/dist/sdk-skills/kindgi-authoring-mcp-servers/how-it-works.md +41 -0
  101. package/dist/sdk-skills/kindgi-authoring-mcp-servers/other-clients.md +19 -0
  102. package/dist/sdk-skills/kindgi-authoring-mcp-servers/postgres.md +45 -0
  103. package/dist/sdk-skills/kindgi-authoring-mcp-servers/several-servers.md +32 -0
  104. package/dist/sdk-skills/kindgi-authoring-providers/SKILL.md +49 -906
  105. package/dist/sdk-skills/kindgi-authoring-providers/bedrock.md +64 -0
  106. package/dist/sdk-skills/kindgi-authoring-providers/common-mistakes.md +125 -0
  107. package/dist/sdk-skills/kindgi-authoring-providers/keys-and-registration.md +58 -0
  108. package/dist/sdk-skills/kindgi-authoring-providers/kindgi-cloud.md +36 -0
  109. package/dist/sdk-skills/kindgi-authoring-providers/path-a-anthropic.md +216 -0
  110. package/dist/sdk-skills/kindgi-authoring-providers/path-b-openai-compat.md +127 -0
  111. package/dist/sdk-skills/kindgi-authoring-providers/path-c-onnx.md +97 -0
  112. package/dist/sdk-skills/kindgi-authoring-providers/path-d-vertex.md +95 -0
  113. package/dist/sdk-skills/kindgi-authoring-providers/router.md +113 -0
  114. package/dist/sdk-skills/kindgi-authoring-tools/SKILL.md +12 -387
  115. package/dist/sdk-skills/kindgi-authoring-tools/common-mistakes.md +135 -0
  116. package/dist/sdk-skills/kindgi-authoring-tools/declarative-http.md +34 -0
  117. package/dist/sdk-skills/kindgi-authoring-tools/imperative-handler.md +65 -0
  118. package/dist/sdk-skills/kindgi-authoring-tools/iterating-and-testing.md +45 -0
  119. package/dist/sdk-skills/kindgi-authoring-tools/secrets-and-connections.md +79 -0
  120. package/dist/sdk-skills/kindgi-authoring-tools/tool-flags.md +45 -0
  121. package/dist/sdk-skills/kindgi-fix-corrections/SKILL.md +13 -178
  122. package/dist/sdk-skills/kindgi-fix-corrections/make-the-change.md +25 -0
  123. package/dist/sdk-skills/kindgi-fix-corrections/publish-and-promote.md +76 -0
  124. package/dist/sdk-skills/kindgi-fix-corrections/pull-corrections.md +48 -0
  125. package/dist/sdk-skills/kindgi-fix-corrections/worked-example.md +27 -0
  126. package/dist/sdk-skills/kindgi-framework-feedback/SKILL.md +10 -180
  127. package/dist/sdk-skills/kindgi-framework-feedback/common-mistakes.md +19 -0
  128. package/dist/sdk-skills/kindgi-framework-feedback/editing-feedback-file.md +33 -0
  129. package/dist/sdk-skills/kindgi-framework-feedback/fields-and-entry-shape.md +53 -0
  130. package/dist/sdk-skills/kindgi-framework-feedback/hearing-back.md +24 -0
  131. package/dist/sdk-skills/kindgi-framework-feedback/sending.md +50 -0
  132. package/dist/sdk-skills/kindgi-getting-started/SKILL.md +24 -21
  133. package/dist/sdk-skills/kindgi-java-authoring-agents/SKILL.md +12 -4
  134. package/dist/sdk-skills/kindgi-java-authoring-flows/SKILL.md +6 -4
  135. package/dist/sdk-skills/kindgi-java-authoring-guardrails/SKILL.md +33 -23
  136. package/dist/sdk-skills/kindgi-java-authoring-tools/SKILL.md +19 -12
  137. package/dist/sdk-skills/kindgi-java-getting-started/SKILL.md +16 -16
  138. package/dist/sdk-skills/kindgi-python-authoring-agents/SKILL.md +18 -6
  139. package/dist/sdk-skills/kindgi-python-authoring-flows/SKILL.md +6 -4
  140. package/dist/sdk-skills/kindgi-python-authoring-guardrails/SKILL.md +39 -30
  141. package/dist/sdk-skills/kindgi-python-authoring-tools/SKILL.md +19 -9
  142. package/dist/sdk-skills/kindgi-python-getting-started/SKILL.md +24 -21
  143. package/dist/sdk-skills/kindgi-scala-authoring-agents/SKILL.md +12 -4
  144. package/dist/sdk-skills/kindgi-scala-authoring-flows/SKILL.md +6 -4
  145. package/dist/sdk-skills/kindgi-scala-authoring-guardrails/SKILL.md +34 -23
  146. package/dist/sdk-skills/kindgi-scala-authoring-tools/SKILL.md +15 -9
  147. package/dist/sdk-skills/kindgi-scala-getting-started/SKILL.md +16 -16
  148. package/dist/sdk-skills/kindgi-using/SKILL.md +11 -11
  149. package/dist/templates/sample/README.md.tmpl +8 -7
  150. package/dist/templates/sample/agents/echo-agent/index.ts.tmpl +1 -1
  151. package/dist/templates/sample/kindgi.config.ts.tmpl +1 -1
  152. package/dist/templates/sample/package.json.tmpl +1 -1
  153. package/dist/templates/woocommerce/README.md.tmpl +9 -3
  154. package/package.json +13 -13
@@ -0,0 +1,97 @@
1
+ # Path C — Local via in-process ONNX (runtime from source only)
2
+
3
+ > ⚠️ **Not in the runtime image, so not under `kindgi dev`.** The adapter
4
+ > runs ONNX through `onnxruntime-node`, which ships glibc binaries only,
5
+ > and the Kindgi runtime image is Alpine (musl): the adapter can't load
6
+ > there (`Error loading shared library ld-linux-…`). `kindgi dev` runs
7
+ > that image, so this path fails under it. It works only when the
8
+ > runtime itself runs from source on macOS or a glibc Linux. **For a
9
+ > local model under `kindgi dev`, use Ollama** (`path-b-openai-compat.md`).
10
+
11
+ > ⚠️ **Dev-only.** The in-process ONNX adapter writes weights to
12
+ > `~/.cache/huggingface/hub/` — a per-machine cache with no production
13
+ > recipe (no volume-mount recipe, no image-bake pattern, no offline
14
+ > mode, no SHA pinning). Good for smoke tests and CI runners that run
15
+ > the runtime from source and keep the same disk between runs. **Do not
16
+ > ship packs that rely on this adapter to production.** Use hosted
17
+ > providers (Path A) or Ollama (Path B) instead.
18
+
19
+ No API key. No network. Bundled with the framework — the adapter ships
20
+ `smollm2-360m` by default (~273 MB weights, cached at
21
+ `~/.cache/huggingface/hub/models--HuggingFaceTB--SmolLM2-360M-Instruct/`
22
+ after `kindgi adapters prepare`).
23
+
24
+ **Not for reasoning-heavy agents.** SmolLM 360M is fine for smoke
25
+ tests, canary agents, dev/CI. Real work needs a hosted model or a
26
+ larger local model via Ollama (Path B).
27
+
28
+ **`provider.json`** (single-model):
29
+ ```json
30
+ {
31
+ "metadata": {
32
+ "id": "local-onnx",
33
+ "region": "in-process",
34
+ "models": [
35
+ {
36
+ "name": "smollm2-360m",
37
+ "contextWindow": 2048,
38
+ "features": ["tool-use"],
39
+ "cost": {
40
+ "promptUsdPer1kTokens": 0,
41
+ "completionUsdPer1kTokens": 0
42
+ }
43
+ }
44
+ ],
45
+ "description": "Local ONNX smollm2-360m — dev + smoke tests."
46
+ },
47
+ "adapter_id": "@kindgi/adapter-model-in-process"
48
+ }
49
+ ```
50
+
51
+ Multi-model variant — the in-process adapter loads each pipeline lazily,
52
+ so listing several models keeps memory low until they're actually
53
+ invoked:
54
+
55
+ ```json
56
+ {
57
+ "metadata": {
58
+ "id": "local-onnx",
59
+ "region": "in-process",
60
+ "models": [
61
+ { "name": "smollm2-135m", "contextWindow": 2048, "features": [],
62
+ "cost": { "promptUsdPer1kTokens": 0, "completionUsdPer1kTokens": 0 } },
63
+ { "name": "smollm2-360m", "contextWindow": 2048, "features": ["tool-use"],
64
+ "cost": { "promptUsdPer1kTokens": 0, "completionUsdPer1kTokens": 0 } },
65
+ { "name": "qwen3-0.6b", "contextWindow": 32768, "features": ["tool-use", "long-context"],
66
+ "cost": { "promptUsdPer1kTokens": 0, "completionUsdPer1kTokens": 0 } }
67
+ ]
68
+ },
69
+ "adapter_id": "@kindgi/adapter-model-in-process"
70
+ }
71
+ ```
72
+
73
+ No `secret_ref` needed. Register + **prepare** + run:
74
+ ```sh
75
+ kindgi providers register --spec=@provider.json
76
+ kindgi adapters prepare @kindgi/adapter-model-in-process --model=smollm2-360m
77
+ kindgi runs start --agent=<agent-id> --input='{...}'
78
+ ```
79
+
80
+ **Always `prepare` before `runs start`.** It downloads the ONNX weights
81
+ (~273 MB for smollm2-360m, ~30s on a typical connection) and streams
82
+ per-file progress. Skipping it works — the first model call downloads
83
+ lazily — but that stalls a request path on a multi-hundred-MB
84
+ fetch with no observability, which is bad in dev and unacceptable in
85
+ production. Skip only for scripted teardown where the model is already
86
+ cached (`~/.cache/huggingface/hub/models--HuggingFaceTB--SmolLM2-360M-Instruct/`).
87
+
88
+ `prepare` is idempotent: subsequent invocations are cache hits and
89
+ return almost instantly, so put it in the script that boots your
90
+ from-source runtime.
91
+
92
+ Multi-model providers: prepare each model separately.
93
+ ```sh
94
+ kindgi adapters prepare @kindgi/adapter-model-in-process --model=smollm2-135m
95
+ kindgi adapters prepare @kindgi/adapter-model-in-process --model=smollm2-360m
96
+ kindgi adapters prepare @kindgi/adapter-model-in-process --model=qwen3-0.6b
97
+ ```
@@ -0,0 +1,95 @@
1
+ # Path D — Gemini on Vertex AI
2
+
3
+ Gemini through Google Cloud's Vertex AI. No API key: the adapter uses
4
+ **Google Application Default Credentials** — your `gcloud` login on a
5
+ laptop, the attached service account on Cloud Run (and other Google Cloud
6
+ runtimes). The same registration works in both.
7
+
8
+ **Step 1 — credentials:**
9
+ ```sh
10
+ gcloud auth application-default login # once per laptop
11
+ ```
12
+ The account (locally) or the service account (deployed) needs the
13
+ **Vertex AI User** role (`roles/aiplatform.user`) in the project. Running
14
+ outside Google Cloud: put a service-account key (its JSON) in a secret
15
+ (`kindgi secrets set GEMINI_SA_KEY --env=local --scope=tenant`) and add
16
+ `"secret_ref": { "envName": "local", "name": "GEMINI_SA_KEY" }`. A runtime
17
+ with `KINDGI_TENANT_HOST_ACCESS=isolated` requires that key: it doesn't lend
18
+ its own credentials to tenant configuration.
19
+
20
+ **Step 2 — `provider.json`:**
21
+ ```json
22
+ {
23
+ "metadata": {
24
+ "id": "gemini",
25
+ "region": "global",
26
+ "models": [
27
+ {
28
+ "name": "gemini-3.8-flash",
29
+ "contextWindow": 1048576,
30
+ "features": ["tool-use", "structured-output", "long-context"],
31
+ "maxOutputTokens": 65536,
32
+ "thinking": { "mode": "adaptive", "lowest": "low" },
33
+ "cost": { "promptUsdPer1kTokens": 0.00075, "completionUsdPer1kTokens": 0.00375 }
34
+ },
35
+ {
36
+ "name": "gemini-3.5-flash-lite",
37
+ "contextWindow": 1048576,
38
+ "features": ["tool-use", "structured-output", "long-context"],
39
+ "maxOutputTokens": 65536,
40
+ "thinking": { "mode": "adaptive", "lowest": "minimal" },
41
+ "cost": { "promptUsdPer1kTokens": 0.0003, "completionUsdPer1kTokens": 0.0025 }
42
+ }
43
+ ]
44
+ },
45
+ "adapter_id": "@kindgi/adapter-model-gemini",
46
+ "adapter_config": { "project": "<your-gcp-project-id>" }
47
+ }
48
+ ```
49
+ - `adapter_config.project` is required: the Google Cloud project Vertex
50
+ bills and authorises against.
51
+ - `metadata.region` is the Vertex location: `global`, or a region such as
52
+ `us-central1` or `northamerica-northeast1` when data must stay in one
53
+ place. `unspecified` means `global`. Different locations are different
54
+ provider rows. Check that the location serves the model: Gemini 3.8 Flash
55
+ isn't served from `us-central1`.
56
+ - Don't register `gemini-2.5-pro` or `gemini-2.5-flash`: Vertex AI retires
57
+ both on 2026-10-20.
58
+ - Rates are per 1K tokens, from Google's published pricing; check them
59
+ before relying on budgets. Thinking tokens bill as output, and Gemini 3.8
60
+ Flash thinks by default. `gemini-3.8-flash`'s rates above are Google's
61
+ launch price, through 2026-12-31 ($0.0015 / $0.0075 from 2027-01-01).
62
+ `longContext` (`{ thresholdTokens, promptUsdPer1kTokens,
63
+ completionUsdPer1kTokens }` in a model's `cost`) switches the whole call
64
+ to the higher rates past the threshold; `cachedPromptMultiplier` (default 0.25) prices cached
65
+ prompt tokens.
66
+ - `thinking` is how the model thinks, as the preset has it. `lowest` is
67
+ the least level it takes, which a judge's call asks for. `levels`
68
+ (optional) are the levels it takes besides `lowest`, least first; without
69
+ them it takes `low`, `medium` and `high` (plus `minimal` when `lowest` is
70
+ `minimal`, and none below `lowest` when that's `medium` or `high`).
71
+ - To make a model think less, the agent sets `thinking` in its model
72
+ settings (`lowest`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`).
73
+ For calls that ask none, set the model's `thinking.default`:
74
+ `"thinking": { "mode": "adaptive", "lowest": "low", "default": "low" }`.
75
+ A `default` the model doesn't take is refused, naming the ones it takes.
76
+ A model without one thinks as Google sets. It needs runtime 0.3.0 or
77
+ later; an older one refuses a `thinking` with `default`.
78
+ - `adapter_config.thinkingLevels` is no longer read. A new registration
79
+ with it is refused (`adapter_config.thinkingLevels isn't read here: its
80
+ setting is metadata.models[].thinking.default.`); a stored one builds,
81
+ thinking at Google's default, and `kindgi doctor` warns. Move each
82
+ `model=level` pair into that model's `thinking.default`, unregister the
83
+ provider and register it again.
84
+
85
+ **Step 3 — register and check:**
86
+ ```sh
87
+ kindgi providers register --spec=@provider.json
88
+ kindgi providers list
89
+ ```
90
+ Or skip step 2: `kindgi providers register --preset=gemini --project=<your-gcp-project-id>`
91
+ registers both models above.
92
+ Then pin it from an agent with `preferredProvider: 'gemini'` (and a model
93
+ with `preferredModel`; in Python, `preferred_provider="gemini"` and
94
+ `preferred_model=…`; in Java, `.set("preferredProvider", "gemini")`), or let
95
+ the router pick by capability.
@@ -0,0 +1,113 @@
1
+ # How the router picks between multiple providers + models
2
+
3
+ ## Contents
4
+
5
+ - The order the router sorts (provider, model) tuples in
6
+ - Practical rule: preferences rank, they never exclude
7
+ - A/B testing a specific agent across models within one Anthropic registration
8
+ - A/B testing across vendors
9
+
10
+ When an agent turn fires, the router expands each registered provider
11
+ into one entry per model (`metadata.models[]`), filters the resulting
12
+ (provider, model) tuples against the agent's `capabilities.needs` (and
13
+ tenant policy), then sorts survivors in this order:
14
+
15
+ 1. **Preferred provider / model.** Tuples matching the agent's
16
+ `preferredProvider` and `preferredModel` are promoted to the front.
17
+ - Both set → promote the exact tuple.
18
+ - Only `preferredModel` set → promote any provider exposing that model.
19
+ - Only `preferredProvider` set → promote every model of that provider.
20
+ `defineAgent` takes both (`preferredProvider`, `preferredModel`), and
21
+ so does a Python `Agent` (`preferred_provider=`, `preferred_model=`) and
22
+ a Java `Agent.define(…)` (`set("preferredProvider", …)`).
23
+ 2. **`capability.prefer[]` weights.** If the agent's capability
24
+ declares `prefer: [{feature: 'thinking', weight: 3}, ...]`, tuples
25
+ with matching model features (or provider attributes) get higher
26
+ scores. Sorted by summed score, descending.
27
+ 3. **Deterministic tiebreak.** When scores tie, tuples sort by provider
28
+ id, then the provider's `defaultModel` before its other models, then
29
+ model name — replay-safe and stable. A provider without a
30
+ `defaultModel` falls back to its first model by name.
31
+
32
+ **Practical rule:** preferences are soft — they rank, they don't
33
+ exclude. To guarantee which model runs, make it a hard requirement in
34
+ the capability: `{ models: { allow: ['claude-sonnet-5-5'] } }` (and
35
+ `{ providers: { allow: ['anthropic'] } }` to pin the connection). If no
36
+ registered tuple satisfies it, the turn fails with
37
+ `capability-routing-failed` instead of silently using another model.
38
+
39
+ **A/B testing a specific agent across models within one Anthropic
40
+ registration:**
41
+
42
+ ```ts
43
+ // agents/weather-agent-sonnet/index.ts
44
+ defineAgent({
45
+ id: 'my-pack.weather-agent-sonnet',
46
+ // …same name, instructions, tools, retrieval and guardrails as the opus variant
47
+ capabilities: [
48
+ { needs: [{ feature: 'tool-use' }, { models: { allow: ['claude-sonnet-5-5'] } }] },
49
+ ],
50
+ preferredProvider: 'anthropic',
51
+ });
52
+
53
+ // agents/weather-agent-opus/index.ts
54
+ defineAgent({
55
+ id: 'my-pack.weather-agent-opus',
56
+ // …
57
+ capabilities: [
58
+ { needs: [{ feature: 'tool-use' }, { models: { allow: ['claude-opus-5-5'] } }] },
59
+ ],
60
+ preferredProvider: 'anthropic',
61
+ });
62
+ ```
63
+
64
+ The same pair in a Python pack (`kindgi.Agent`; module-level, one file each):
65
+
66
+ ```python
67
+ # agents/weather_agent_sonnet.py
68
+ weather_agent_sonnet = Agent(
69
+ id="my-pack.weather-agent-sonnet",
70
+ # …same version, name, instructions, tools and guardrails as the opus variant
71
+ capabilities=[
72
+ {"needs": [{"feature": "tool-use"}, {"models": {"allow": ["claude-sonnet-5-5"]}}]},
73
+ ],
74
+ preferred_provider="anthropic",
75
+ )
76
+
77
+ # agents/weather_agent_opus.py
78
+ weather_agent_opus = Agent(
79
+ id="my-pack.weather-agent-opus",
80
+ # …
81
+ capabilities=[
82
+ {"needs": [{"feature": "tool-use"}, {"models": {"allow": ["claude-opus-5-5"]}}]},
83
+ ],
84
+ preferred_provider="anthropic",
85
+ )
86
+ ```
87
+
88
+ Both agents share the tool + instructions; only the pinned model
89
+ differs. One Anthropic provider registration + one API key covers
90
+ both. Register the provider once, then invoke each agent to compare
91
+ outputs on the same inputs.
92
+
93
+ **A/B testing across vendors:**
94
+
95
+ ```ts
96
+ defineAgent({
97
+ id: 'my-pack.weather-agent-groq',
98
+ // …
99
+ capabilities: [
100
+ { needs: [{ feature: 'tool-use' }, { models: { allow: ['llama-3.3-70b-versatile'] } }] },
101
+ ],
102
+ preferredProvider: 'groq',
103
+ });
104
+
105
+ defineAgent({
106
+ id: 'my-pack.weather-agent-anthropic',
107
+ // …
108
+ capabilities: [
109
+ { needs: [{ feature: 'tool-use' }, { models: { allow: ['claude-sonnet-5-5'] } }] },
110
+ ],
111
+ preferredProvider: 'anthropic',
112
+ });
113
+ ```