pantheon-opencode 1.4.1 → 1.4.2
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/README.md +166 -50
- package/bin/pantheon-init.mjs +7 -0
- package/commands/pantheon-model.md +34 -0
- package/package.json +2 -2
- package/scripts/generate-preset-docs.mjs +239 -0
- package/scripts/install/model-picker.mjs +367 -2
- package/scripts/install/opencode.mjs +150 -137
- package/src/pantheon/delegation.ts +36 -26
- package/src/pantheon/model-command.ts +858 -0
- package/src/pantheon/presets.mjs +30 -33
- package/src/pantheon/zeus-delegate-with-retry.ts +9 -4
- package/src/plugin.ts +4 -0
- package/src/plugins/tui/dist/tui.d.ts.map +1 -1
- package/src/plugins/tui/dist/tui.js +1 -1
- package/src/plugins/tui/dist/tui.tsx +13 -2
- package/src/plugins/tui/package.json +1 -1
- package/src/plugins/tui/src/index.tsx +13 -2
- package/src/plugins/tui/tsdown.config.ts +11 -0
- package/src/routing.yml +71 -123
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<h1 align="center">Pantheon</h1>
|
|
3
3
|
|
|
4
4
|
<p align="center">
|
|
5
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-v1.4.
|
|
5
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-v1.4.2-blue" alt="Version"></a>
|
|
6
6
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="License"></a>
|
|
7
7
|
<a href="docs/agents/README.md"><img src="https://img.shields.io/badge/agents-14-purple" alt="Agents"></a>
|
|
8
8
|
<a href="src/skills/README.md"><img src="https://img.shields.io/badge/skills-21-orange" alt="Skills"></a>
|
|
@@ -225,7 +225,7 @@ via three delegation tools, tracked on a persistent job board
|
|
|
225
225
|
|
|
226
226
|
| Tool | Signature | Behavior |
|
|
227
227
|
|------|-----------|----------|
|
|
228
|
-
| `pantheon_delegate` | `{prompt, agent, description?, read_only?}` | Creates a child session (parentID = caller), registers it on the job board, arms a 15-minute timeout, and
|
|
228
|
+
| `pantheon_delegate` | `{prompt, agent, description?, read_only?, model?}` | Creates a child session (parentID = caller), registers it on the job board, arms a 15-minute timeout, and sends `promptAsync` to the child. `model` is optional and uses `provider/model-id`. Returns the readable alias (e.g. `apo-1`). Only root sessions may delegate (sub-sessions are rejected by the depth guard). |
|
|
229
229
|
| `pantheon_delegation_read` | `{id}` | Blocks (`waitForTerminal`, up to 15 min) until the delegation reaches a terminal state, returns the report markdown, and marks the job reconciled. Resolves by alias or task ID. |
|
|
230
230
|
| `pantheon_delegation_list` | `{}` | Lists the current session's delegations with `[unread]` on finished, unreconciled jobs. |
|
|
231
231
|
|
|
@@ -277,6 +277,22 @@ agent in `background_delegation.read_only_agents` (`apollo`, `gaia`), registers
|
|
|
277
277
|
the child session as read-only — the `tool.execute.before` guard denies
|
|
278
278
|
`edit`/`write`/`bash`/`task` inside that session.
|
|
279
279
|
|
|
280
|
+
**Delegated model resolution:** the optional child model is resolved in this
|
|
281
|
+
order: (1) explicit `model` on `pantheon_delegate`; (2) the target agent's
|
|
282
|
+
model in the active preset; (3) the current model of the parent session; (4)
|
|
283
|
+
no model, allowing OpenCode's native inheritance. `small_model` is never used
|
|
284
|
+
for delegates. When a model resolves, the same `provider/model-id` is sent as
|
|
285
|
+
`{providerID, id}` to both `session.create` and `promptAsync`, including the
|
|
286
|
+
single safe bootstrap retry; the retry does not select a different model. If
|
|
287
|
+
the resolution lookup yields no model, the model field is omitted and the
|
|
288
|
+
delegation continues with native inheritance.
|
|
289
|
+
|
|
290
|
+
Model availability is not inferred from the string. The provider must exist in
|
|
291
|
+
OpenCode and the referenced model must be available through that provider's
|
|
292
|
+
account, subscription, or configured endpoint; otherwise the child host may
|
|
293
|
+
reject startup. An active preset supplies provider configuration and model
|
|
294
|
+
mappings, but does not make an unavailable provider or model available.
|
|
295
|
+
|
|
280
296
|
**R1 — Per-error-type retry + provider cooldown (LiteLLM pattern):**
|
|
281
297
|
`retry_policy` in `src/routing.yml` maps an error class (`auth`, `rate_limit`,
|
|
282
298
|
`timeout`, `other`) to max retries before escalating — `auth` is never retried
|
|
@@ -641,112 +657,211 @@ on demand to perform specialized tasks. Skills are organized into domains:
|
|
|
641
657
|
## Model Tiers & Presets
|
|
642
658
|
|
|
643
659
|
Pantheon agents declare abstract model tiers (`fast` / `default` / `coding` / `premium`) rather than
|
|
644
|
-
hardcoded model names. The actual model resolved for each tier depends on your
|
|
645
|
-
|
|
660
|
+
hardcoded model names. The actual model resolved for each tier depends on your chosen **preset**
|
|
661
|
+
and is pinned to concrete `provider/model` IDs in [src/routing.yml](src/routing.yml).
|
|
646
662
|
|
|
647
|
-
| Tier | Purpose | Agents | Typical Models |
|
|
663
|
+
| Tier | Purpose | Agents | Typical Models (2026) |
|
|
648
664
|
|------|---------|--------|----------------|
|
|
649
|
-
| `premium` | Deep reasoning, critical | Zeus, Athena, Themis |
|
|
650
|
-
| `default` | Balanced quality/speed | Hermes, Aphrodite, Demeter, Prometheus, Hephaestus, Gaia |
|
|
651
|
-
| `coding` | Heavy coding tasks | Hermes, Aphrodite, Demeter, Prometheus, Hephaestus, Talos |
|
|
652
|
-
| `fast` | Quick, cheap ops | Apollo, Iris, Mnemosyne, Talos, Nyx |
|
|
665
|
+
| `premium` | Deep reasoning, critical | Zeus, Athena, Themis | gpt-5.6-sol, qwen3.8-max, deepseek-v4-pro |
|
|
666
|
+
| `default` | Balanced quality/speed | Hermes, Aphrodite, Demeter, Prometheus, Hephaestus, Gaia | gpt-5.6-terra, kimi-k3, deepseek-v4-flash |
|
|
667
|
+
| `coding` | Heavy coding tasks | Hermes, Aphrodite, Demeter, Prometheus, Hephaestus, Talos | gpt-5.6-terra, deepseek-v4-flash, mimo-v2.5 |
|
|
668
|
+
| `fast` | Quick, cheap ops | Apollo, Iris, Mnemosyne, Talos, Nyx | gpt-5.6-luna-fast, mimo-v2.5-free, gpt-5.6-luna |
|
|
653
669
|
|
|
654
670
|
---
|
|
655
671
|
|
|
656
672
|
## Model Routing Presets
|
|
657
673
|
|
|
658
|
-
The abstract tiers above are pinned to concrete `provider/model` IDs by **
|
|
674
|
+
The abstract tiers above are pinned to concrete `provider/model` IDs by **4 built-in model presets**.
|
|
675
|
+
Cada preset mapeia os 14 agentes para um modelo específico + `reasoning_effort` por papel (planners/reviewers, implementers, scouts).
|
|
676
|
+
|
|
677
|
+
> **Default = herdar do chat (sem `active-preset.json`)** — sem preset ativo, os delegates **herdam nativamente** o modelo do chat pai ([herança nativa](src/pantheon/delegation.ts)). O instalador **não grava** `active-preset.json` quando você escolhe `0`/`inherit` no wizard (ou não seleciona preset via `--preset`). A resolução do modelo delegado segue: `explicit model` em `pantheon_delegate` > modelo do agente-alvo no preset ativo > modelo atual da sessão pai > herança nativa (sem `model`, sem `small_model`). `small_model` nunca é usado para delegates.
|
|
678
|
+
|
|
679
|
+
Tabelas abaixo são **geradas a partir de [src/routing.yml](src/routing.yml)** — rode `node scripts/generate-preset-docs.mjs` para regenerar. Nenhum segredo é hardcoded: apenas nomes de env vars (`PANTHEON_OPENCODE_API_KEY`, `OPENAI_API_KEY`) e `baseURL`s.
|
|
680
|
+
|
|
681
|
+
<!-- Generated from src/routing.yml — run: node scripts/generate-preset-docs.mjs -->
|
|
682
|
+
### Presets — resumo (provider / baseURL / key / pricing / vision)
|
|
659
683
|
|
|
660
|
-
|
|
684
|
+
| Preset | Provider / BaseURL | Key env (nome) | Pricing 2026 | Vision (fallback) | Papéis / Modelos |
|
|
685
|
+
|---|---|---|---|---|---|
|
|
686
|
+
| `go-free` | `opencode` `https://opencode.ai/zen/v1` (env: `PANTHEON_OPENCODE_API_KEY`) | `PANTHEON_OPENCODE_API_KEY` | Gratuito — Zen free, sem custo, quota limitada, só modelos `-free` | `opencode/mimo-v2.5-free` [low] 👁️ vision | zeus: `opencode/big-pickle` [medium]<br>athena: `opencode/nemotron-3-super-free` [high]<br>themis: `opencode/qwen3.6-plus-free` [high]<br>hermes,aphrodite,demeter,prometheus,hephaestus: `opencode/deepseek-v4-flash-free` [medium]<br>apollo,nyx,gaia,iris,mnemosyne,talos: `opencode/mimo-v2.5-free` [low] |
|
|
687
|
+
| `go-fast` | `opencode-go` `https://opencode.ai/zen/go/v1` (env: `PANTHEON_OPENCODE_API_KEY`) | `PANTHEON_OPENCODE_API_KEY` | Baixo custo — Go gateway, baixa latência (kimi-k2.7-code / glm-5.3-flash) | `opencode-go/mimo-v2.5` [low] 👁️ vision | athena: `opencode-go/kimi-k2.7-code` [high]<br>themis: `opencode-go/glm-5.3-flash` [high]<br>zeus: `opencode-go/kimi-k2.7-code` [medium]<br>hermes,prometheus: `opencode-go/deepseek-v4-flash` [medium]<br>aphrodite,hephaestus: `opencode-go/mimo-v2.5` [low]<br>demeter: `opencode-go/gpt-5.6-luna` [low]<br>apollo,nyx,gaia,iris,mnemosyne,talos: `opencode-go/gpt-5.6-luna-fast` [low] |
|
|
688
|
+
| `go-premium` | `opencode-go` `https://opencode.ai/zen/go/v1` (env: `PANTHEON_OPENCODE_API_KEY`) | `PANTHEON_OPENCODE_API_KEY` | Premium — Go gateway, melhor qualidade (gpt-5.6-sol / qwen3.8-max / deepseek-v4-pro) | `opencode-go/gpt-5.6-sol` [high] 👁️ vision | zeus: `opencode-go/gpt-5.6-sol` [medium]<br>athena: `opencode-go/deepseek-v4-pro` [high]<br>themis: `opencode-go/qwen3.8-max` [high]<br>hermes,demeter,hephaestus: `opencode-go/gpt-5.6-terra` [medium]<br>aphrodite,prometheus: `opencode-go/kimi-k3` [medium]<br>apollo,nyx,gaia,iris,mnemosyne,talos: `opencode-go/gpt-5.6-luna` [low] |
|
|
689
|
+
| `openai` | `openai` `https://api.openai.com/v1` (env: `OPENAI_API_KEY`) | `OPENAI_API_KEY` | Pago (OpenAI) — Direto OpenAI, `gpt-5.6` family | `openai/gpt-5.6-sol` [high] 👁️ vision | athena,themis,zeus: `openai/gpt-5.6-sol` [high]<br>hermes,aphrodite,demeter,prometheus,hephaestus: `openai/gpt-5.6-luna` [high]<br>apollo,nyx,gaia,iris,mnemosyne,talos: `openai/gpt-5.6-luna-fast` [low] |
|
|
661
690
|
|
|
662
|
-
|
|
663
|
-
|--------|----------|--------------------|--------------|--------|
|
|
664
|
-
| `go-deepseek` | opencode (Zen) | `opencode/deepseek-v4-pro` | `opencode/deepseek-v4-flash` | `opencode/deepseek-v4-flash-free` |
|
|
665
|
-
| `go-fast` | opencode-go | `opencode-go/deepseek-v4-flash` — all 14 agents, effort `low` | | |
|
|
666
|
-
| `go-claude` | anthropic | `anthropic/claude-opus-4-8` | `anthropic/claude-sonnet-5` | `anthropic/claude-haiku-4-5` |
|
|
667
|
-
| `go-openai` | openai | `openai/gpt-5.6-sol` | `openai/gpt-5.6-terra` | `openai/gpt-5.6-luna-fast` |
|
|
668
|
-
| `go-premium` | opencode-go | GLM-5.1 (zeus), DeepSeek V4 Pro (athena), Qwen3.7 Max (themis) | MiniMax M2.7 (hermes, hephaestus), Kimi K2.6 (aphrodite), Qwen3.7 Plus (demeter), GLM-5.2 (prometheus) | DeepSeek V4 Flash (scouts) |
|
|
669
|
-
| `go-free` | opencode (Zen free, $0) | Big Pickle (zeus), Nemotron 3 Ultra Free (athena) | DeepSeek V4 Flash Free | North Mini Code Free (scouts) |
|
|
691
|
+
> **Pricing 2026 verificado** via `scripts/install/model-picker.mjs` (`PRESET_PRICE`) e `routing.yml` descrições. `go-free` = $0 (Zen free, quota limitada, só `-free`); `go-*` usam `PANTHEON_OPENCODE_API_KEY` (alias `OPENCODE_GO_API_KEY` aceito) no gateway `https://opencode.ai/zen/go/v1`; `openai` usa `OPENAI_API_KEY` em `https://api.openai.com/v1`. Custos reais dependem de conta/assinatura.
|
|
670
692
|
|
|
671
|
-
|
|
693
|
+
### 14 agentes × 4 presets — modelo + effort + vision
|
|
694
|
+
|
|
695
|
+
| Agente | `go-free` | `go-fast` | `go-premium` | `openai` |
|
|
696
|
+
|---|---|---|---|---|
|
|
697
|
+
| `zeus` | `opencode/big-pickle` [medium] · | `opencode-go/kimi-k2.7-code` [medium] · | `opencode-go/gpt-5.6-sol` [medium] 👁️ | `openai/gpt-5.6-sol` [high] 👁️ |
|
|
698
|
+
| `athena` | `opencode/nemotron-3-super-free` [high] · | `opencode-go/kimi-k2.7-code` [high] · | `opencode-go/deepseek-v4-pro` [high] · | `openai/gpt-5.6-sol` [high] 👁️ |
|
|
699
|
+
| `themis` | `opencode/qwen3.6-plus-free` [high] · | `opencode-go/glm-5.3-flash` [high] · | `opencode-go/qwen3.8-max` [high] · | `openai/gpt-5.6-sol` [high] 👁️ |
|
|
700
|
+
| `hermes` | `opencode/deepseek-v4-flash-free` [medium] · | `opencode-go/deepseek-v4-flash` [medium] · | `opencode-go/gpt-5.6-terra` [medium] 👁️ | `openai/gpt-5.6-luna` [high] 👁️ |
|
|
701
|
+
| `aphrodite` | `opencode/deepseek-v4-flash-free` [medium] · | `opencode-go/mimo-v2.5` [low] 👁️ | `opencode-go/kimi-k3` [medium] · | `openai/gpt-5.6-luna` [high] 👁️ |
|
|
702
|
+
| `demeter` | `opencode/deepseek-v4-flash-free` [medium] · | `opencode-go/gpt-5.6-luna` [low] 👁️ | `opencode-go/gpt-5.6-terra` [medium] 👁️ | `openai/gpt-5.6-luna` [high] 👁️ |
|
|
703
|
+
| `prometheus` | `opencode/deepseek-v4-flash-free` [medium] · | `opencode-go/deepseek-v4-flash` [medium] · | `opencode-go/kimi-k3` [medium] · | `openai/gpt-5.6-luna` [high] 👁️ |
|
|
704
|
+
| `hephaestus` | `opencode/deepseek-v4-flash-free` [medium] · | `opencode-go/mimo-v2.5` [low] 👁️ | `opencode-go/gpt-5.6-terra` [medium] 👁️ | `openai/gpt-5.6-luna` [high] 👁️ |
|
|
705
|
+
| `apollo` | `opencode/mimo-v2.5-free` [low] 👁️ | `opencode-go/gpt-5.6-luna-fast` [low] 👁️ | `opencode-go/gpt-5.6-luna` [low] 👁️ | `openai/gpt-5.6-luna-fast` [low] 👁️ |
|
|
706
|
+
| `nyx` | `opencode/mimo-v2.5-free` [low] 👁️ | `opencode-go/gpt-5.6-luna-fast` [low] 👁️ | `opencode-go/gpt-5.6-luna` [low] 👁️ | `openai/gpt-5.6-luna-fast` [low] 👁️ |
|
|
707
|
+
| `gaia` | `opencode/mimo-v2.5-free` [low] 👁️ | `opencode-go/gpt-5.6-luna-fast` [low] 👁️ | `opencode-go/gpt-5.6-luna` [low] 👁️ | `openai/gpt-5.6-luna-fast` [low] 👁️ |
|
|
708
|
+
| `iris` | `opencode/mimo-v2.5-free` [low] 👁️ | `opencode-go/gpt-5.6-luna-fast` [low] 👁️ | `opencode-go/gpt-5.6-luna` [low] 👁️ | `openai/gpt-5.6-luna-fast` [low] 👁️ |
|
|
709
|
+
| `mnemosyne` | `opencode/mimo-v2.5-free` [low] 👁️ | `opencode-go/gpt-5.6-luna-fast` [low] 👁️ | `opencode-go/gpt-5.6-luna` [low] 👁️ | `openai/gpt-5.6-luna-fast` [low] 👁️ |
|
|
710
|
+
| `talos` | `opencode/mimo-v2.5-free` [low] 👁️ | `opencode-go/gpt-5.6-luna-fast` [low] 👁️ | `opencode-go/gpt-5.6-luna` [low] 👁️ | `openai/gpt-5.6-luna-fast` [low] 👁️ |
|
|
711
|
+
|
|
712
|
+
`·` = text-only, `👁️` = vision (image-input) per `CAPABILITY_TABLE` em [src/pantheon/presets.mjs](src/pantheon/presets.mjs) — ex.: `mimo-v2.5`/`mimo-v2.5-free` e `gpt-5.6-*` são multimodais; `deepseek-v4-pro/flash`, `kimi-k2.7-code`, `glm-5.3-flash`, `qwen3.6-plus-free`, `big-pickle`, `nemotron-3-super-free` são text-only.
|
|
713
|
+
|
|
714
|
+
O mapeamento exato por agente (modelo + `reasoning_effort` + `vision` fallback) vive no bloco `presets:` de [src/routing.yml](src/routing.yml) e é validado por `validatePresetDefs` + `capabilityEntry` / `hasVision`.
|
|
672
715
|
|
|
673
716
|
### Requirements
|
|
674
717
|
|
|
675
|
-
- **Env vars** —
|
|
676
|
-
- `PANTHEON_OPENCODE_API_KEY` — `opencode` + `opencode-go`
|
|
677
|
-
- `
|
|
678
|
-
|
|
679
|
-
- **OpenCode
|
|
680
|
-
- **
|
|
718
|
+
- **Env vars** — checadas fail-fast (CLI e plugin) quando o preset usa o provider (sem hardcodar valores):
|
|
719
|
+
- `PANTHEON_OPENCODE_API_KEY` — `opencode` + `opencode-go` (`go-free`, `go-fast`, `go-premium`) — alias `OPENCODE_GO_API_KEY` também aceito (wizard Q2)
|
|
720
|
+
- `OPENAI_API_KEY` — `openai` provider (`openai` puro)
|
|
721
|
+
- **OpenCode Go subscription** para `go-fast` / `go-premium` (gateway `https://opencode.ai/zen/go/v1`).
|
|
722
|
+
- **OpenCode Zen free tier** para `go-free` (`https://opencode.ai/zen/v1`, só modelos `-free`, quota limitada).
|
|
723
|
+
- **Sem preset (default)**: zero-mutação — nenhum `.pantheon/active-preset.json` gravado, herança nativa do chat pai.
|
|
681
724
|
|
|
682
|
-
###
|
|
725
|
+
### Wizard — instalação interativa (3 perguntas)
|
|
683
726
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
727
|
+
Durante `npx pantheon-opencode init` (TTY, sem `--preset`/`--headless`/`-y`):
|
|
728
|
+
|
|
729
|
+
1. **Perfil (Q1)** — `0` = herdar do chat (**default**, não grava `active-preset.json`) ou `go-free`/`go-fast`/`go-premium`/`openai` — tabela exibida: perfil | `provider`/`baseURL`/key env | preço 2026 | modelos por papel (planners high, implementers medium/low, scouts low). `askQuestions` quando disponível, fallback `readline` TTY.
|
|
730
|
+
2. **API Key (Q2)** — coleta **mascarada** (exibe `abcd****12`), valida `PANTHEON_OPENCODE_API_KEY` (aceita alias `OPENCODE_GO_API_KEY`) para `go-*` e `OPENAI_API_KEY` para `openai`, **não escreve `.env`** — só seta `env` da sessão e loga `maskKey`. Se já configurada no ambiente, apenas loga mascarada e segue.
|
|
731
|
+
3. **Escopo (Q3)** — `project` (`./.pantheon/active-preset.json`, seguro, default) ou `global` (`~/.config/opencode/.pantheon/active-preset.json`). Gravação **atômica** (`tmp`+`rename`) com backup `.bak` + health-check (lê JSON e valida `preset`).
|
|
687
732
|
|
|
688
|
-
|
|
689
|
-
pantheon-opencode set-tier go-deepseek
|
|
690
|
-
pantheon-opencode set-tier go-fast --project
|
|
691
|
-
pantheon-opencode set-tier go-fast --dry-run
|
|
733
|
+
Headless / CI: use `npx pantheon-opencode init --headless` ou `--preset <name>` (pula wizard). Veja [docs/INSTALLATION.md](docs/INSTALLATION.md) para `headless` + troubleshooting de chaves.
|
|
692
734
|
|
|
693
|
-
|
|
694
|
-
pantheon-opencode set-tier none
|
|
735
|
+
### Comandos
|
|
695
736
|
|
|
696
|
-
|
|
697
|
-
|
|
737
|
+
```bash
|
|
738
|
+
# Instalação interativa (wizard 3 perguntas — Q1 default = herdar do chat)
|
|
739
|
+
npx pantheon-opencode init
|
|
740
|
+
npx pantheon-opencode init --project # escopo project-local
|
|
741
|
+
npx pantheon-opencode init --preset go-fast # pula wizard, ativa direto
|
|
742
|
+
|
|
743
|
+
# Alternar preset depois (global por padrão; --project para projeto; --dry-run para preview)
|
|
744
|
+
npx pantheon-opencode set-tier go-free
|
|
745
|
+
npx pantheon-opencode set-tier go-premium --project
|
|
746
|
+
npx pantheon-opencode set-tier openai --dry-run
|
|
747
|
+
|
|
748
|
+
# Limpar preset — volta ao default (herança nativa)
|
|
749
|
+
npx pantheon-opencode set-tier none
|
|
750
|
+
|
|
751
|
+
# Sem nome → lista presets (none, go-free, go-fast, go-premium, openai)
|
|
752
|
+
npx pantheon-opencode set-tier
|
|
753
|
+
|
|
754
|
+
# Per-agent customization (novo — sem top-level model/small_model)
|
|
755
|
+
# Lista 14 agentes com modelo/effort/origem (preset|override|env|none), sem segredos
|
|
756
|
+
/pantheon-model status # alias: show
|
|
757
|
+
/pantheon-model # sem args → wizard interativo (agente → modelo → effort → scope via askQuestions)
|
|
758
|
+
/pantheon-model set --agent hermes --model opencode-go/gpt-5.6-terra --effort medium --scope project
|
|
759
|
+
/pantheon-model set --agent apollo --model opencode/mimo-v2.5-free --effort low
|
|
760
|
+
/pantheon-model reset --agent hermes --scope project
|
|
698
761
|
```
|
|
699
762
|
|
|
700
|
-
**Env override (CI/headless)** —
|
|
763
|
+
**Env override (CI/headless)** — vence o arquivo:
|
|
701
764
|
|
|
702
765
|
```bash
|
|
703
|
-
export PANTHEON_MODEL_PRESET=go-
|
|
766
|
+
export PANTHEON_MODEL_PRESET=go-fast # ou go-free / go-premium / openai / none
|
|
767
|
+
export PANTHEON_OPENCODE_API_KEY=... # para go-* (ou OPENCODE_GO_API_KEY como alias)
|
|
768
|
+
export OPENAI_API_KEY=... # para openai puro
|
|
704
769
|
```
|
|
705
770
|
|
|
706
771
|
### How it works
|
|
707
772
|
|
|
708
|
-
-
|
|
709
|
-
- **
|
|
710
|
-
- **
|
|
711
|
-
-
|
|
712
|
-
- **Capability normalization**: requested
|
|
713
|
-
- **
|
|
773
|
+
- A seleção ativa é persistida (se não for `inherit`) em `.pantheon/active-preset.json` — `{version, preset, source, updated_at, overrides?}` — escrita atômica (`tmp`+`rename`) com backup `.bak`. Só aplica no próximo startup do OpenCode (sem hot-swap); o plugin em `hooks.config` injeta `provider`/`baseURL`/`apiKeyEnv`.
|
|
774
|
+
- **Precedência**: `PANTHEON_MODEL_PRESET` env → primeiro `.pantheon/active-preset.json` existente (project → `~/.config/opencode` → `~/.opencode`) → **none = herança nativa** (sem `active-preset.json`).
|
|
775
|
+
- **Herança nativa de delegates** (1.4.2): `src/pantheon/delegation.ts` resolve o modelo do filho em: `explicit model` em `pantheon_delegate` > `overrides.agents[agent].model` em `active-preset.json` > `loadRoutingAgentModels` (preset ativo) > omitir → OpenCode herda o modelo do chat pai. `small_model` nunca é enviado. Validação `provider/model-id` com `MODEL_REF_PATTERN`.
|
|
776
|
+
- **Partial & overrides**: um preset sobrescreve só os agentes listados; agentes não listados herdam do pai. O bloco `overrides.agents[agent]` (via `/pantheon-model set --agent`) tem merge sobre o preset, validado via `capabilityEntry` e `normalizeCapability` (clamp ao teto do modelo) + aviso `hasVision` para modelos text-only; `overrides.providers` permite `baseURL`/`apiKeyEnv` custom. Escrita atômica com lock por path + `.bak`.
|
|
777
|
+
- **Capability normalization**: `requested effort` é clamped ao teto da família em `CAPABILITY_TABLE` (`deepseek-v4-flash/-free` max `medium`; `gop-5.6-luna*`/`mimo-v2.5*` max `low`; `claude` strip; `qwen3.6-plus-free`/`big-pickle` etc. text-only).
|
|
778
|
+
- **Interactive picker / wizard**: `scripts/install/model-picker.mjs` exporta `buildPresetTableRow`, `requiredKeyEnvForPreset`, `isKeyConfiguredForPreset`, `maskKey`, `buildInitQuestions`, `runInitWizard` e `runModelPicker`. Nunca toca `opencode.json`; também expõe helper `maskKey` para logs.
|
|
714
779
|
|
|
715
780
|
### Quick smoke test
|
|
716
781
|
|
|
717
782
|
```bash
|
|
783
|
+
# 1) default (herança nativa) — sem preset
|
|
784
|
+
npx pantheon-opencode init --headless # escolha 0 no wizard interativo = inherit
|
|
785
|
+
opencode run "hello" 2>&1 | grep "Pantheon"
|
|
786
|
+
# sem log de preset → herança nativa
|
|
787
|
+
|
|
788
|
+
# 2) com preset
|
|
718
789
|
export PANTHEON_OPENCODE_API_KEY=...
|
|
719
|
-
pantheon-opencode set-tier go-fast --project
|
|
790
|
+
npx pantheon-opencode set-tier go-fast --project
|
|
720
791
|
opencode run "hello" 2>&1 | grep "Pantheon"
|
|
721
792
|
# expect: [Pantheon Plugin] Model preset active: go-fast (source: file)
|
|
793
|
+
|
|
794
|
+
# 3) override per-agent
|
|
795
|
+
# no chat OpenCode:
|
|
796
|
+
/pantheon-model status
|
|
797
|
+
/pantheon-model set --agent hermes --model openai/gpt-5.6-luna --effort high --scope project
|
|
798
|
+
# persiste em .pantheon/active-preset.json overrides.agents.hermes
|
|
722
799
|
```
|
|
723
800
|
|
|
801
|
+
|
|
724
802
|
---
|
|
725
803
|
|
|
726
804
|
## Quick Start
|
|
727
805
|
|
|
728
806
|
### 1. Install Pantheon
|
|
729
807
|
|
|
730
|
-
Pantheon runs on **OpenCode**.
|
|
808
|
+
Pantheon runs on **OpenCode**. Instalação global com **wizard 3 perguntas** (default = herdar do chat):
|
|
731
809
|
|
|
732
810
|
```bash
|
|
733
811
|
npx pantheon-opencode init
|
|
812
|
+
# Q1: perfil — 0=herdar do chat [default] (sem active-preset.json), ou go-free / go-fast / go-premium / openai
|
|
813
|
+
# tabela exibida: perfil | provider/baseURL/key | preço 2026 | modelos por papel
|
|
814
|
+
# Q2: API key — coleta mascarada (PANTHEON_OPENCODE_API_KEY alias OPENCODE_GO_API_KEY, ou OPENAI_API_KEY), não escreve .env
|
|
815
|
+
# Q3: escopo — project (./.pantheon/active-preset.json, default) ou global (~/.config/opencode/.pantheon/active-preset.json)
|
|
816
|
+
# gravação atômica tmp+rename com .bak + health-check
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
Atalhos:
|
|
820
|
+
|
|
821
|
+
```bash
|
|
822
|
+
npx pantheon-opencode init --preset go-fast --headless # pula wizard
|
|
823
|
+
npx pantheon-opencode init --project # escopo project-local
|
|
824
|
+
npx pantheon-opencode init --headless --no-mcp # minimal sem Python
|
|
734
825
|
```
|
|
735
826
|
|
|
736
|
-
|
|
827
|
+
MCP servers (memory, persistence) — opcional via:
|
|
737
828
|
|
|
738
829
|
```bash
|
|
739
830
|
npm run setup
|
|
740
831
|
```
|
|
741
832
|
|
|
833
|
+
Ou já incluído no wizard se escolher instalação completa.
|
|
834
|
+
|
|
742
835
|
### 2. Launch OpenCode
|
|
743
836
|
|
|
744
837
|
```bash
|
|
745
838
|
export OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true
|
|
746
839
|
opencode
|
|
840
|
+
# ou
|
|
841
|
+
npm run start
|
|
747
842
|
```
|
|
748
843
|
|
|
749
|
-
|
|
844
|
+
Dica: após instalar preset, `opencode run "hello" 2>&1 | grep "Pantheon"` deve mostrar `[Pantheon Plugin] Model preset active: <preset> (source: file)`; sem preset, fica em herança nativa (sem log de preset).
|
|
845
|
+
|
|
846
|
+
### 3. Customize per-agent (opcional)
|
|
847
|
+
|
|
848
|
+
No chat OpenCode:
|
|
849
|
+
|
|
850
|
+
```
|
|
851
|
+
# lista 14 agentes com modelo/effort/origem
|
|
852
|
+
/pantheon-model status
|
|
853
|
+
|
|
854
|
+
# wizard interativo (agente → modelo → effort → scope)
|
|
855
|
+
/pantheon-model
|
|
856
|
+
|
|
857
|
+
# override explícito por agente (validado via CAPABILITY_TABLE, clamp, hasVision)
|
|
858
|
+
/pantheon-model set --agent hermes --model opencode-go/gpt-5.6-terra --effort medium --scope project
|
|
859
|
+
/pantheon-model reset --agent hermes --scope project
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
Overrides vivem em `.pantheon/active-preset.json` em `overrides.agents[agent]` — sem `model`/`small_model` top-level e sem `.env`.
|
|
863
|
+
|
|
864
|
+
### 4. Run your first feature
|
|
750
865
|
|
|
751
866
|
Once agents are loaded, invoke the orchestrator:
|
|
752
867
|
|
|
@@ -778,6 +893,7 @@ Type these in the OpenCode chat:
|
|
|
778
893
|
| `/pantheon-remember` | Store in memory |
|
|
779
894
|
| `/pantheon-search` | Search memory |
|
|
780
895
|
| `/pantheon-status` | System health and agent status |
|
|
896
|
+
| `/pantheon-model` (wizard) / `status\|show\|set --agent\|reset --agent` | Herança nativa default; `status` lista 14 agentes (model/effort/origem); `set --agent X --model provider/model-id [--effort low|medium|high] [--scope project|global]` com validação CAPABILITY_TABLE + clamp + hasVision; `reset --agent X`; default scope `project`; global exige `confirm`+`authorize_global`; nunca escreve `.env` nem top-level `model`; persistência atômica `.bak` + health-check |
|
|
781
897
|
| `/pantheon-verify` | Hash edit verification |
|
|
782
898
|
|
|
783
899
|
---
|
package/bin/pantheon-init.mjs
CHANGED
|
@@ -190,6 +190,11 @@ async function main() {
|
|
|
190
190
|
const autoYes = args.includes('--yes') || args.includes('-y')
|
|
191
191
|
const presetIndex = args.indexOf('--preset')
|
|
192
192
|
const presetOpt = presetIndex >= 0 ? (args[presetIndex + 1] ?? null) : null
|
|
193
|
+
// Explicit top-level model overrides for the generated config.
|
|
194
|
+
const modelIndex = args.indexOf('--model')
|
|
195
|
+
const modelOpt = modelIndex >= 0 ? (args[modelIndex + 1] ?? null) : null
|
|
196
|
+
const smallModelIndex = args.indexOf('--small-model')
|
|
197
|
+
const smallModelOpt = smallModelIndex >= 0 ? (args[smallModelIndex + 1] ?? null) : null
|
|
193
198
|
// --version v1|v2 labels the install target (informational; the config is
|
|
194
199
|
// shared and V1-shaped under both versions). Invalid values fail fast.
|
|
195
200
|
const versionIndex = args.indexOf('--version')
|
|
@@ -218,6 +223,8 @@ async function main() {
|
|
|
218
223
|
interactive: forceInteractive,
|
|
219
224
|
headless: forceHeadless,
|
|
220
225
|
yes: autoYes,
|
|
226
|
+
model: modelOpt,
|
|
227
|
+
smallModel: smallModelOpt,
|
|
221
228
|
preset: presetOpt,
|
|
222
229
|
version: versionOpt ?? 'v1',
|
|
223
230
|
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Inspect or change per-agent model overrides in active-preset.json"
|
|
3
|
+
agent: zeus
|
|
4
|
+
---
|
|
5
|
+
# /pantheon-model — Per-agent model overrides
|
|
6
|
+
|
|
7
|
+
Use the deterministic `pantheon_model` tool for this command. Operates exclusively
|
|
8
|
+
on `active-preset.json` `overrides.agents[agent]` (project or global). Never
|
|
9
|
+
writes `.env` and never injects top-level `model`/`small_model` into `opencode.json`.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
- `/pantheon-model status` or `/pantheon-model show` — list 14 canonical agents
|
|
14
|
+
(`zeus`, `athena`, `apollo`, `hermes`, `aphrodite`, `demeter`, `themis`,
|
|
15
|
+
`prometheus`, `hephaestus`, `nyx`, `gaia`, `iris`, `mnemosyne`, `talos`)
|
|
16
|
+
with effective `model`, `effort`, and origin (`preset` | `override` | `env` | `none`)
|
|
17
|
+
and the active preset, without showing secrets.
|
|
18
|
+
- `/pantheon-model` (no args) — interactive wizard via `askQuestions`:
|
|
19
|
+
agente → modelo (`provider/model-id`) → effort (`low`/`medium`/`high`) → scope.
|
|
20
|
+
|
|
21
|
+
- `/pantheon-model set --agent <name> --model <provider/model-id> [--effort low|medium|high] [--scope project|global]`
|
|
22
|
+
— set per-agent override. Validates agent is one of the 14, `provider/model-id`
|
|
23
|
+
format, `CAPABILITY_TABLE` entry via `capabilityEntry()` and clamps effort via
|
|
24
|
+
`normalizeCapability()`; warns via `hasVision` for text-only models. Persists
|
|
25
|
+
atomically with `.bak` backup and per-path lock. Default scope is `project`.
|
|
26
|
+
|
|
27
|
+
- `/pantheon-model reset --agent <name> [--scope project|global]` — remove the
|
|
28
|
+
per-agent override from `overrides.agents[agent]`.
|
|
29
|
+
|
|
30
|
+
`--scope project|global` is supported by `set` and `reset`. Global changes require
|
|
31
|
+
explicit `confirm` and `authorize_global`. Values must use `provider/model-id`.
|
|
32
|
+
Changes are backed up (`.bak`) and written atomically; restart OpenCode after a
|
|
33
|
+
successful change. The tool never writes `.env` and never injects `model`/`small_model`
|
|
34
|
+
global keys — delegate inheritance is native (no model → inherits chat/preset model).
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon-opencode",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "Multi-agent orchestration for OpenCode — 14 specialized agents, TDD, Themis review gates.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"registry": "https://registry.npmjs.org/"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"postinstall": "node scripts/postinstall.mjs",
|
|
10
|
+
"postinstall": "node scripts/postinstall.mjs && node scripts/sync-tui.mjs",
|
|
11
11
|
"prepare": "husky",
|
|
12
12
|
"setup": "node bin/pantheon-init.mjs init",
|
|
13
13
|
"build:agents-md": "node scripts/build-agents-md.mjs",
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* generate-preset-docs.mjs — Generate markdown tables from src/routing.yml
|
|
4
|
+
*
|
|
5
|
+
* Reads routing.yml + presets.mjs + model-picker.mjs and prints:
|
|
6
|
+
* 1) Presets summary table (perfil | provider/baseURL | key env | pricing 2026 | vision | papéis)
|
|
7
|
+
* 2) 14 agents × 4 presets matrix (model + effort + vision)
|
|
8
|
+
* 3) Capability table (model prefix → maxEffort, vision)
|
|
9
|
+
*
|
|
10
|
+
* No secrets are hardcoded — only env var NAMES and baseURLs from routing.yml
|
|
11
|
+
* are emitted. Pricing labels come from model-picker PRESET_PRICE.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* node scripts/generate-preset-docs.mjs # print all
|
|
15
|
+
* node scripts/generate-preset-docs.mjs --summary # only summary
|
|
16
|
+
* node scripts/generate-preset-docs.mjs --matrix # only matrix
|
|
17
|
+
* node scripts/generate-preset-docs.mjs --json # JSON for tooling
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { readFileSync } from 'node:fs'
|
|
21
|
+
import { fileURLToPath } from 'node:url'
|
|
22
|
+
import yaml from 'js-yaml'
|
|
23
|
+
import { CAPABILITY_TABLE, hasVision, normalizeCapability } from '../src/pantheon/presets.mjs'
|
|
24
|
+
import { PRESET_PRICE } from './install/model-picker.mjs'
|
|
25
|
+
|
|
26
|
+
const routingPath = fileURLToPath(new URL('../src/routing.yml', import.meta.url))
|
|
27
|
+
const raw = readFileSync(routingPath, 'utf8')
|
|
28
|
+
const routing = yaml.load(raw)
|
|
29
|
+
const presets = routing?.presets ?? {}
|
|
30
|
+
|
|
31
|
+
const KNOWN_AGENTS_ORDER = ['zeus','athena','themis','hermes','aphrodite','demeter','prometheus','hephaestus','apollo','nyx','gaia','iris','mnemosyne','talos']
|
|
32
|
+
|
|
33
|
+
function agentSort(a,b){ const ia = KNOWN_AGENTS_ORDER.indexOf(a); const ib = KNOWN_AGENTS_ORDER.indexOf(b); if(ia===-1&&ib===-1) return a.localeCompare(b); if(ia===-1) return 1; if(ib===-1) return -1; return ia-ib; }
|
|
34
|
+
|
|
35
|
+
function safeEnvLabel(_apiKeyEnv){
|
|
36
|
+
return '`[redacted]`'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function providerLabel(def){
|
|
40
|
+
const entries = Object.entries(def.providers ?? {})
|
|
41
|
+
if(entries.length===0) return '—'
|
|
42
|
+
return entries.map(([id,p]) => `\`${id}\` \`${p.baseURL ?? ''}\` (env: ${safeEnvLabel(p.apiKeyEnv)})`).join('<br>')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function pricingLabel(name){
|
|
46
|
+
const p = PRESET_PRICE[name]
|
|
47
|
+
if(!p) return '—'
|
|
48
|
+
return `${p.label} — ${p.detail}`
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function visionLabel(def){
|
|
52
|
+
if(!def.vision) return '—'
|
|
53
|
+
const m = def.vision.model
|
|
54
|
+
let visionFlag = '—'
|
|
55
|
+
try{ visionFlag = hasVision(m) ? '👁️ vision' : 'text-only' }catch{ visionFlag = 'unknown' }
|
|
56
|
+
return `\`${m}\` [${def.vision.reasoning_effort ?? ''}] ${visionFlag}`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function capabilityBadge(model){
|
|
60
|
+
try{
|
|
61
|
+
const v = hasVision(model)
|
|
62
|
+
const cap = normalizeCapability(model, 'high')
|
|
63
|
+
// cap.variant is clamped effort for 'high'
|
|
64
|
+
// also get maxEffort via capabilityEntry
|
|
65
|
+
const entry = CAPABILITY_TABLE.find(e => model.startsWith(e.prefix) || model.slice(model.lastIndexOf('/')+1).startsWith(e.prefix) || model.slice(model.lastIndexOf('/')+1)===e.prefix)
|
|
66
|
+
// But use direct lookup via prefix matching like capabilityEntry does
|
|
67
|
+
return { vision: v, maxEffort: entry?.maxEffort ?? 'unknown', clamped: cap.variant }
|
|
68
|
+
}catch{
|
|
69
|
+
return { vision: undefined, maxEffort: 'unknown', clamped: undefined }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function buildSummaryTable(){
|
|
74
|
+
const lines=[]
|
|
75
|
+
lines.push('| Preset | Provider / BaseURL | Key env (nome) | Pricing 2026 | Vision (fallback) | Papéis / Modelos |')
|
|
76
|
+
lines.push('|---|---|---|---|---|---|')
|
|
77
|
+
for(const name of Object.keys(presets)){
|
|
78
|
+
const def = presets[name]
|
|
79
|
+
const prov = providerLabel(def)
|
|
80
|
+
// env names redacted to avoid exposing credential-related metadata
|
|
81
|
+
const envs = Object.values(def.providers ?? {}).map(p=>safeEnvLabel(p.apiKeyEnv)).join(', ') || '—'
|
|
82
|
+
// Actually use providerLabel already includes env, but separate column for key env
|
|
83
|
+
const pricing = pricingLabel(name)
|
|
84
|
+
const vision = visionLabel(def)
|
|
85
|
+
// Papéis grouped: planners/high, implementers/medium, scouts/low
|
|
86
|
+
const agents = def.agents ?? {}
|
|
87
|
+
const groups={}
|
|
88
|
+
for(const [agent,spec] of Object.entries(agents)){
|
|
89
|
+
const key = `\`${spec.model}\` [${spec.reasoning_effort ?? ''}]`
|
|
90
|
+
if(!groups[key]) groups[key]=[]
|
|
91
|
+
groups[key].push(agent)
|
|
92
|
+
}
|
|
93
|
+
const papelSummary = Object.entries(groups).map(([model,list])=>`${list.join(',')}: ${model}`).join('<br>')
|
|
94
|
+
lines.push(`| \`${name}\` | ${prov} | ${envs} | ${pricing} | ${vision} | ${papelSummary} |`)
|
|
95
|
+
}
|
|
96
|
+
return lines.join('\n')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function buildMatrixTable(){
|
|
100
|
+
const presetNames = Object.keys(presets)
|
|
101
|
+
const lines=[]
|
|
102
|
+
// header
|
|
103
|
+
lines.push(`| Agente | ${presetNames.map(n=>`\`${n}\``).join(' | ')} | Capability (vision / maxEffort) |`)
|
|
104
|
+
lines.push(`|---|${presetNames.map(()=> '---').join('|')}|---|`)
|
|
105
|
+
// collect all agents
|
|
106
|
+
const allAgents = new Set()
|
|
107
|
+
for(const def of Object.values(presets)) for(const a of Object.keys(def.agents ?? {})) allAgents.add(a)
|
|
108
|
+
const sorted = [...allAgents].sort(agentSort)
|
|
109
|
+
for(const agent of sorted){
|
|
110
|
+
const cells = presetNames.map(presetName=>{
|
|
111
|
+
const spec = presets[presetName]?.agents?.[agent]
|
|
112
|
+
if(!spec) return '—'
|
|
113
|
+
const badge = capabilityBadge(spec.model)
|
|
114
|
+
const visionIcon = badge.vision ? '👁️' : '—'
|
|
115
|
+
// don't expose raw key, just model and effort
|
|
116
|
+
return `\`${spec.model}\`<br>[${spec.reasoning_effort}] ${visionIcon}`
|
|
117
|
+
})
|
|
118
|
+
// capability column: pick first preset's model for reference, but show per-agent vision across presets is same family
|
|
119
|
+
const sampleModel = presets[presetNames[0]]?.agents?.[agent]?.model ?? ''
|
|
120
|
+
let capStr='—'
|
|
121
|
+
if(sampleModel){
|
|
122
|
+
try{
|
|
123
|
+
const v = hasVision(sampleModel)
|
|
124
|
+
capStr = v ? 'vision' : 'text-only'
|
|
125
|
+
}catch{ capStr='unknown' }
|
|
126
|
+
}
|
|
127
|
+
// Show effort clamp per preset? Instead show generic
|
|
128
|
+
lines.push(`| \`${agent}\` | ${cells.join(' | ')} | ${capStr} |`)
|
|
129
|
+
}
|
|
130
|
+
return lines.join('\n')
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function buildDetailedMatrixWithEffort(){
|
|
134
|
+
const presetNames = Object.keys(presets)
|
|
135
|
+
const lines=[]
|
|
136
|
+
lines.push(`| Agente | ${presetNames.map(n=>`\`${n}\``).join(' | ')} |`)
|
|
137
|
+
lines.push(`|---|${presetNames.map(()=> '---').join('|')}|`)
|
|
138
|
+
const allAgents = new Set()
|
|
139
|
+
for(const def of Object.values(presets)) for(const a of Object.keys(def.agents ?? {})) allAgents.add(a)
|
|
140
|
+
const sorted = [...allAgents].sort(agentSort)
|
|
141
|
+
for(const agent of sorted){
|
|
142
|
+
const cells = presetNames.map(presetName=>{
|
|
143
|
+
const spec = presets[presetName]?.agents?.[agent]
|
|
144
|
+
if(!spec) return '—'
|
|
145
|
+
let vision = '—'
|
|
146
|
+
try{ vision = hasVision(spec.model) ? '👁️' : '·' }catch{ vision='?' }
|
|
147
|
+
return `\`${spec.model}\` [${spec.reasoning_effort}] ${vision}`
|
|
148
|
+
})
|
|
149
|
+
lines.push(`| \`${agent}\` | ${cells.join(' | ')} |`)
|
|
150
|
+
}
|
|
151
|
+
return lines.join('\n')
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function buildProviderTable(){
|
|
155
|
+
const lines=[]
|
|
156
|
+
lines.push('| Preset | Provider | BaseURL | Key env |')
|
|
157
|
+
lines.push('|---|---|---|---|')
|
|
158
|
+
for(const [name,def] of Object.entries(presets)){
|
|
159
|
+
for(const [pid,prov] of Object.entries(def.providers ?? {})){
|
|
160
|
+
const keyEnvStatus = prov.apiKeyEnv ? 'configured' : 'none'
|
|
161
|
+
lines.push(`| \`${name}\` | \`${pid}\` | \`${prov.baseURL ?? ''}\` | \`${keyEnvStatus}\` |`)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return lines.join('\n')
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function buildPricingTable(){
|
|
168
|
+
const lines=[]
|
|
169
|
+
lines.push('| Preset | Pricing 2026 | Detalhe | Gateway / Custo |')
|
|
170
|
+
lines.push('|---|---|---|---|')
|
|
171
|
+
for(const name of Object.keys(presets)){
|
|
172
|
+
const p = PRESET_PRICE[name] ?? {label:'—',detail:'—'}
|
|
173
|
+
const def = presets[name]
|
|
174
|
+
const prov = Object.keys(def.providers ?? {}).join(', ')
|
|
175
|
+
const costHint = name==='go-free' ? '$0 (free-tier Zen, quota limitada)' : name==='go-fast' ? 'Baixo custo (Go gateway, baixa latência)' : name==='go-premium' ? 'Premium (Go gateway, melhor qualidade)' : 'Pago por uso (OpenAI direto)'
|
|
176
|
+
lines.push(`| \`${name}\` | ${p.label} | ${p.detail} | ${prov} — ${costHint} |`)
|
|
177
|
+
}
|
|
178
|
+
return lines.join('\n')
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function buildCapabilityTable(){
|
|
182
|
+
const lines=[]
|
|
183
|
+
lines.push('| Prefix | Max Effort | Vision | Strip Effort |')
|
|
184
|
+
lines.push('|---|---|---|---|')
|
|
185
|
+
for(const e of CAPABILITY_TABLE){
|
|
186
|
+
lines.push(`| \`${e.prefix}\` | ${e.maxEffort ?? '—'} | ${e.vision ? '👁️' : '—'} | ${e.stripEffort ? 'yes' : 'no'} |`)
|
|
187
|
+
}
|
|
188
|
+
return lines.join('\n')
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const args = process.argv.slice(2)
|
|
192
|
+
if(args.includes('--json')){
|
|
193
|
+
const out = { presets, PRESET_PRICE, CAPABILITY_TABLE }
|
|
194
|
+
console.log(JSON.stringify(out,null,2))
|
|
195
|
+
process.exit(0)
|
|
196
|
+
}
|
|
197
|
+
if(args.includes('--summary')){
|
|
198
|
+
console.log(buildSummaryTable())
|
|
199
|
+
process.exit(0)
|
|
200
|
+
}
|
|
201
|
+
if(args.includes('--matrix')){
|
|
202
|
+
console.log(buildMatrixTable())
|
|
203
|
+
process.exit(0)
|
|
204
|
+
}
|
|
205
|
+
if(args.includes('--provider')){
|
|
206
|
+
console.log(buildProviderTable())
|
|
207
|
+
process.exit(0)
|
|
208
|
+
}
|
|
209
|
+
if(args.includes('--pricing')){
|
|
210
|
+
console.log(buildPricingTable())
|
|
211
|
+
process.exit(0)
|
|
212
|
+
}
|
|
213
|
+
if(args.includes('--capability')){
|
|
214
|
+
console.log(buildCapabilityTable())
|
|
215
|
+
process.exit(0)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// default: print all
|
|
219
|
+
console.log('<!-- Generated from src/routing.yml + src/pantheon/presets.mjs + scripts/install/model-picker.mjs — do not edit manually. Run: node scripts/generate-preset-docs.mjs -->')
|
|
220
|
+
console.log('')
|
|
221
|
+
console.log('### Presets — resumo (provider / baseURL / key / pricing / vision)')
|
|
222
|
+
console.log('')
|
|
223
|
+
console.log(buildSummaryTable())
|
|
224
|
+
console.log('')
|
|
225
|
+
console.log('### Provider / BaseURL / Key env')
|
|
226
|
+
console.log('')
|
|
227
|
+
console.log(buildProviderTable())
|
|
228
|
+
console.log('')
|
|
229
|
+
console.log('### Pricing 2026')
|
|
230
|
+
console.log('')
|
|
231
|
+
console.log(buildPricingTable())
|
|
232
|
+
console.log('')
|
|
233
|
+
console.log('### 14 agentes × 4 presets — modelo + effort + vision')
|
|
234
|
+
console.log('')
|
|
235
|
+
console.log(buildDetailedMatrixWithEffort())
|
|
236
|
+
console.log('')
|
|
237
|
+
console.log('### Capability table (prefix → maxEffort, vision)')
|
|
238
|
+
console.log('')
|
|
239
|
+
console.log(buildCapabilityTable())
|