pantheon-opencode 1.4.1 → 1.4.3

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.
@@ -150,7 +150,7 @@ async function resolvePresetForTui(
150
150
  }
151
151
 
152
152
  /* ─── Version Detection ────────────────────────────────────
153
- * 100% dinâmico — zero fallback hardcoded.
153
+ * 100% dinâmico — fallback embutido em build (__PANTHEON_VERSION__).
154
154
  * Se falhar, retorna null e a View omite a versão.
155
155
  *
156
156
  * Try order:
@@ -159,7 +159,12 @@ async function resolvePresetForTui(
159
159
  * 1. api.client.file.read package.json
160
160
  * 2. git describe --tags
161
161
  * 3. opencode --version
162
- * 4. null */
162
+ * 4. __PANTHEON_VERSION__ (tsdown define — build-time embed)
163
+ * 5. null */
164
+
165
+ // Build-time embedded version (tsdown `define` in tsdown.config.ts). Injected
166
+ // only into the bundled dist/tui.js; the raw dist/tui.tsx copy falls through.
167
+ declare const __PANTHEON_VERSION__: string | undefined
163
168
 
164
169
  async function detectVersion(api: TuiPluginApi): Promise<string | null> {
165
170
  // Try 0a: installed location (2 levels: dist/tui.js → pantheon-tui/package.json)
@@ -223,6 +228,12 @@ async function detectVersion(api: TuiPluginApi): Promise<string | null> {
223
228
  /* fall through */
224
229
  }
225
230
 
231
+ // Try 4: build-time embedded version (tsdown define) — last-resort fallback
232
+ // so the sidebar ALWAYS shows a version even when every probe above fails.
233
+ if (typeof __PANTHEON_VERSION__ !== 'undefined' && __PANTHEON_VERSION__) {
234
+ return __PANTHEON_VERSION__
235
+ }
236
+
226
237
  return null // sem fallback — versão não aparece
227
238
  }
228
239
 
@@ -894,9 +905,10 @@ async function setupUsageBar(api: TuiPluginApi) {
894
905
  * board row for the same child (a child WITH a report keeps the md
895
906
  * entry, source 'md').
896
907
  *
897
- * 2. ENRICHMENT + HISTORY — markdown reports the job board persists under
898
- * `.pantheon/delegations/<sessionID>/<alias>.md` (written by
899
- * src/pantheon/delegation-finalize.ts at terminal state). Each child
908
+ * 2. ENRICHMENT + HISTORY — markdown reports under
909
+ * `.pantheon/delegations/<sessionID>/<alias>.md`. These are LEGACY files
910
+ * (the writer, src/pantheon/delegation-finalize.ts, was removed); the
911
+ * panel still reads them for history. Each child
900
912
  * is matched to its report by the `Task ID` header (== child session
901
913
  * id == board task id), which supplies the alias (apo-N), agent,
902
914
  * description and terminal duration/timedOut. No report → the child
@@ -1140,7 +1152,8 @@ export async function readDelegationEntries(dir: string): Promise<DelegationEntr
1140
1152
 
1141
1153
  /** Read delegation reports from EVERY session under
1142
1154
  * `<root>/.pantheon/delegations/<sessionID>/<alias>.md` — the panel's
1143
- * HISTORY channel. Unlike the children/live channels it does NOT depend on a
1155
+ * HISTORY channel (reads legacy files; the writer, delegation-finalize.ts,
1156
+ * was removed). Unlike the children/live channels it does NOT depend on a
1144
1157
  * resolved sessionID: with no focused session (null/placeholder), the panel
1145
1158
  * still shows the reports from all past sessions (running first, Finalized
1146
1159
  * desc — the sort applied by readDelegationEntries). Fail-open: a
@@ -1149,8 +1162,8 @@ export async function readAllDelegationEntries(root: string): Promise<Delegation
1149
1162
  return readDelegationEntries(join(root, '.pantheon', 'delegations'))
1150
1163
  }
1151
1164
 
1152
- /** Resolve the directory where the job board writes delegation md reports.
1153
- * The board writes `.pantheon/delegations` RELATIVE to the server cwd,
1165
+ /** Resolve the directory holding delegation md reports.
1166
+ * The reports live under `.pantheon/delegations` RELATIVE to the server cwd,
1154
1167
  * which the TUI exposes as `TuiState.path.directory`. `project` does NOT
1155
1168
  * exist on `TuiState.path` (the old `state?.project ?? state?.worktree`
1156
1169
  * resolution was always undefined for the first term) and `worktree` is
@@ -1,6 +1,14 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
1
4
  import solid from 'rolldown-plugin-solid'
2
5
  import { defineConfig } from 'tsdown'
3
6
 
7
+ const __dirname = fileURLToPath(new URL('.', import.meta.url))
8
+ const pkg = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf8')) as {
9
+ version: string
10
+ }
11
+
4
12
  export default defineConfig({
5
13
  entry: { tui: 'src/index.tsx', server: 'src/server.ts' },
6
14
  format: ['esm'],
@@ -8,6 +16,9 @@ export default defineConfig({
8
16
  outDir: 'dist',
9
17
  clean: true,
10
18
  outExtensions: () => ({ js: '.js' }),
19
+ define: {
20
+ __PANTHEON_VERSION__: JSON.stringify(pkg.version),
21
+ },
11
22
  plugins: [
12
23
  solid({
13
24
  solid: {
package/src/routing.yml CHANGED
@@ -1,35 +1,31 @@
1
1
  version: 1.0
2
2
  presets:
3
- go-deepseek:
4
- description: "DeepSeek tiering via OpenCode Zen: V4 Pro for planners/reviewers (free on Zen), V4 Flash for implementers, V4 Flash Free for scouts. Vision turns route to MiniMax M3 (opencode-go; Qwen3.7 Plus image input fails on the Go gateway — opencode#29956). Prices verified 2026-08."
3
+ go-free:
4
+ description: "Free-tier lineup via OpenCode Zen 2026: big-pickle orchestrator, nemotron-3-super-free planner, qwen3.6-plus-free reviewer, deepseek-v4-flash-free implementers, mimo-v2.5-free scouts. Only -free suffix models; quota, availability and pricing depend on Zen account. 2026 pricing verified."
5
5
  vision:
6
- model: opencode-go/minimax-m3
7
- reasoning_effort: medium
6
+ model: opencode/mimo-v2.5-free
7
+ reasoning_effort: low
8
8
  providers:
9
9
  opencode:
10
10
  baseURL: https://opencode.ai/zen/v1
11
11
  apiKeyEnv: PANTHEON_OPENCODE_API_KEY
12
- opencode-go:
13
- baseURL: https://opencode.ai/zen/go/v1
14
- apiKeyEnv: PANTHEON_OPENCODE_API_KEY
15
12
  agents:
16
- athena: { model: opencode/deepseek-v4-pro, reasoning_effort: high, fallback_models: [opencode/mimo-v2.5] }
17
- # themis (PR #46 W4): phase reviews run on v4-flash (cost/empty-signature fix); pro only for the FINAL gate (manual override).
18
- themis: { model: opencode/deepseek-v4-flash, reasoning_effort: high, fallback_models: [opencode/mimo-v2.5] }
19
- zeus: { model: opencode/deepseek-v4-flash, reasoning_effort: medium, fallback_models: [opencode/mimo-v2.5] }
20
- hermes: { model: opencode/deepseek-v4-flash, reasoning_effort: medium, fallback_models: [opencode/mimo-v2.5] }
21
- aphrodite: { model: opencode/deepseek-v4-flash, reasoning_effort: medium, fallback_models: [opencode/mimo-v2.5] }
22
- demeter: { model: opencode/deepseek-v4-flash, reasoning_effort: medium, fallback_models: [opencode/mimo-v2.5] }
23
- prometheus: { model: opencode/deepseek-v4-flash, reasoning_effort: medium, fallback_models: [opencode/mimo-v2.5] }
24
- hephaestus: { model: opencode/deepseek-v4-flash, reasoning_effort: medium, fallback_models: [opencode/mimo-v2.5] }
25
- apollo: { model: opencode/deepseek-v4-flash-free, reasoning_effort: low, fallback_models: [opencode/mimo-v2.5] }
26
- nyx: { model: opencode/deepseek-v4-flash-free, reasoning_effort: low, fallback_models: [opencode/mimo-v2.5] }
27
- gaia: { model: opencode/deepseek-v4-flash-free, reasoning_effort: low, fallback_models: [opencode/mimo-v2.5] }
28
- iris: { model: opencode/deepseek-v4-flash-free, reasoning_effort: low, fallback_models: [opencode/mimo-v2.5] }
29
- mnemosyne: { model: opencode/deepseek-v4-flash-free, reasoning_effort: low, fallback_models: [opencode/mimo-v2.5] }
30
- talos: { model: opencode/deepseek-v4-flash-free, reasoning_effort: low, fallback_models: [opencode/mimo-v2.5] }
13
+ zeus: { model: opencode/big-pickle, reasoning_effort: medium }
14
+ athena: { model: opencode/nemotron-3-super-free, reasoning_effort: high }
15
+ themis: { model: opencode/qwen3.6-plus-free, reasoning_effort: high }
16
+ hermes: { model: opencode/deepseek-v4-flash-free, reasoning_effort: medium }
17
+ aphrodite: { model: opencode/deepseek-v4-flash-free, reasoning_effort: medium }
18
+ demeter: { model: opencode/deepseek-v4-flash-free, reasoning_effort: medium }
19
+ prometheus: { model: opencode/deepseek-v4-flash-free, reasoning_effort: medium }
20
+ hephaestus: { model: opencode/deepseek-v4-flash-free, reasoning_effort: medium }
21
+ apollo: { model: opencode/mimo-v2.5-free, reasoning_effort: low }
22
+ nyx: { model: opencode/mimo-v2.5-free, reasoning_effort: low }
23
+ gaia: { model: opencode/mimo-v2.5-free, reasoning_effort: low }
24
+ iris: { model: opencode/mimo-v2.5-free, reasoning_effort: low }
25
+ mnemosyne: { model: opencode/mimo-v2.5-free, reasoning_effort: low }
26
+ talos: { model: opencode/mimo-v2.5-free, reasoning_effort: low }
31
27
  go-fast:
32
- description: "All 14 agents on DeepSeek V4 Flash via OpenCode Go with reasoning_effort low everywhere. Fastest tier. Vision turns route to MiniMax M2.5 (mimo-v2.5). Prices verified 2026-08."
28
+ description: "Low-latency OpenCode Go profile 2026: kimi-k2.7-code and glm-5.3-flash planners, gpt-5.6-luna / mimo-v2.5 / deepseek-v4-flash implementers, gpt-5.6-luna-fast scouts. All via Go gateway https://opencode.ai/zen/go/v1. Pricing 2026."
33
29
  vision:
34
30
  model: opencode-go/mimo-v2.5
35
31
  reasoning_effort: low
@@ -38,116 +34,68 @@ presets:
38
34
  baseURL: https://opencode.ai/zen/go/v1
39
35
  apiKeyEnv: PANTHEON_OPENCODE_API_KEY
40
36
  agents:
41
- athena: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
42
- themis: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
43
- zeus: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
44
- hermes: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
45
- aphrodite: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
46
- demeter: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
47
- prometheus: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
48
- hephaestus: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
49
- apollo: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
50
- nyx: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
51
- gaia: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
52
- iris: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
53
- mnemosyne: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
54
- talos: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
55
- go-claude:
56
- description: "Anthropic Claude tiering: Opus 4.8 for planners/reviewers, Sonnet 5 for implementers, Haiku 4.5 for scouts. Vision turns route to Sonnet 5 (native image support). Prices verified 2026-07."
57
- vision:
58
- model: anthropic/claude-sonnet-5
59
- reasoning_effort: medium
60
- providers:
61
- anthropic:
62
- baseURL: https://api.anthropic.com
63
- apiKeyEnv: PANTHEON_ANTHROPIC_API_KEY
64
- agents:
65
- athena: { model: anthropic/claude-opus-4-8, reasoning_effort: high }
66
- themis: { model: anthropic/claude-opus-4-8, reasoning_effort: high }
67
- zeus: { model: anthropic/claude-sonnet-5, reasoning_effort: medium }
68
- hermes: { model: anthropic/claude-sonnet-5, reasoning_effort: medium }
69
- aphrodite: { model: anthropic/claude-sonnet-5, reasoning_effort: medium }
70
- demeter: { model: anthropic/claude-sonnet-5, reasoning_effort: medium }
71
- prometheus: { model: anthropic/claude-sonnet-5, reasoning_effort: medium }
72
- hephaestus: { model: anthropic/claude-sonnet-5, reasoning_effort: medium }
73
- apollo: { model: anthropic/claude-haiku-4-5, reasoning_effort: low }
74
- nyx: { model: anthropic/claude-haiku-4-5, reasoning_effort: low }
75
- gaia: { model: anthropic/claude-haiku-4-5, reasoning_effort: low }
76
- iris: { model: anthropic/claude-haiku-4-5, reasoning_effort: low }
77
- mnemosyne: { model: anthropic/claude-haiku-4-5, reasoning_effort: low }
78
- talos: { model: anthropic/claude-haiku-4-5, reasoning_effort: low }
79
- go-openai:
80
- description: "OpenAI GPT-5.6 family tiering: Sol for planners/reviewers, Terra for implementers, Luna Fast for scouts. Vision turns route to GPT-5.6 Sol. Prices verified 2026-07."
81
- vision:
82
- model: openai/gpt-5.6-sol
83
- reasoning_effort: high
84
- providers:
85
- openai:
86
- baseURL: https://api.openai.com/v1
87
- apiKeyEnv: PANTHEON_OPENAI_API_KEY
88
- agents:
89
- athena: { model: openai/gpt-5.6-sol, reasoning_effort: high }
90
- themis: { model: openai/gpt-5.6-sol, reasoning_effort: high }
91
- zeus: { model: openai/gpt-5.6-terra, reasoning_effort: medium }
92
- hermes: { model: openai/gpt-5.6-terra, reasoning_effort: medium }
93
- aphrodite: { model: openai/gpt-5.6-terra, reasoning_effort: medium }
94
- demeter: { model: openai/gpt-5.6-terra, reasoning_effort: medium }
95
- prometheus: { model: openai/gpt-5.6-terra, reasoning_effort: medium }
96
- hephaestus: { model: openai/gpt-5.6-terra, reasoning_effort: medium }
97
- apollo: { model: openai/gpt-5.6-luna-fast, reasoning_effort: low }
98
- nyx: { model: openai/gpt-5.6-luna-fast, reasoning_effort: low }
99
- gaia: { model: openai/gpt-5.6-luna-fast, reasoning_effort: low }
100
- iris: { model: openai/gpt-5.6-luna-fast, reasoning_effort: low }
101
- mnemosyne: { model: openai/gpt-5.6-luna-fast, reasoning_effort: low }
102
- talos: { model: openai/gpt-5.6-luna-fast, reasoning_effort: low }
37
+ athena: { model: opencode-go/kimi-k2.7-code, reasoning_effort: high }
38
+ themis: { model: opencode-go/glm-5.3-flash, reasoning_effort: high }
39
+ zeus: { model: opencode-go/kimi-k2.7-code, reasoning_effort: medium }
40
+ hermes: { model: opencode-go/deepseek-v4-flash, reasoning_effort: medium }
41
+ aphrodite: { model: opencode-go/mimo-v2.5, reasoning_effort: low }
42
+ demeter: { model: opencode-go/gpt-5.6-luna, reasoning_effort: low }
43
+ prometheus: { model: opencode-go/deepseek-v4-flash, reasoning_effort: medium }
44
+ hephaestus: { model: opencode-go/mimo-v2.5, reasoning_effort: low }
45
+ apollo: { model: opencode-go/gpt-5.6-luna-fast, reasoning_effort: low }
46
+ nyx: { model: opencode-go/gpt-5.6-luna-fast, reasoning_effort: low }
47
+ gaia: { model: opencode-go/gpt-5.6-luna-fast, reasoning_effort: low }
48
+ iris: { model: opencode-go/gpt-5.6-luna-fast, reasoning_effort: low }
49
+ mnemosyne: { model: opencode-go/gpt-5.6-luna-fast, reasoning_effort: low }
50
+ talos: { model: opencode-go/gpt-5.6-luna-fast, reasoning_effort: low }
103
51
  go-premium:
104
- description: "Pantheon premium lineup on OpenCode Go (subscription): GLM-5.1 orchestrator, DeepSeek V4 Pro planner, Qwen3.7 Max reviewer, Kimi K2.6 designer, MiniMax M2.7 implementers, DeepSeek V4 Flash scouts. Vision turns route to MiniMax M3 (multimodal; Qwen3.7 Plus image input fails on the Go gateway — opencode#29956). Ported from Oh-My-OpenAgent 'opencode-go' preset. Requires OpenCode Go subscription. Prices verified 2026-08."
52
+ description: "Premium lineup on OpenCode Go 2026: gpt-5.6-sol / qwen3.8-max / deepseek-v4-pro planners, gpt-5.6-terra / kimi-k3 implementers, gpt-5.6-luna scouts. Vision via gpt-5.6-sol. Pricing 2026."
105
53
  vision:
106
- model: opencode-go/minimax-m3
107
- reasoning_effort: medium
54
+ model: opencode-go/gpt-5.6-sol
55
+ reasoning_effort: high
108
56
  providers:
109
57
  opencode-go:
110
58
  baseURL: https://opencode.ai/zen/go/v1
111
59
  apiKeyEnv: PANTHEON_OPENCODE_API_KEY
112
60
  agents:
113
- zeus: { model: opencode-go/glm-5.1, reasoning_effort: medium }
114
- athena: { model: opencode-go/deepseek-v4-pro, reasoning_effort: high }
115
- themis: { model: opencode-go/qwen3.7-max, reasoning_effort: high }
116
- hermes: { model: opencode-go/minimax-m2.7, reasoning_effort: medium }
117
- aphrodite: { model: opencode-go/kimi-k2.6, reasoning_effort: medium }
118
- demeter: { model: opencode-go/qwen3.7-plus, reasoning_effort: medium }
119
- prometheus: { model: opencode-go/glm-5.2, reasoning_effort: medium }
120
- hephaestus: { model: opencode-go/minimax-m2.7, reasoning_effort: medium }
121
- apollo: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
122
- nyx: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
123
- gaia: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
124
- iris: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
125
- mnemosyne: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
126
- talos: { model: opencode-go/deepseek-v4-flash, reasoning_effort: low }
127
- go-free:
128
- description: "Pantheon free lineup on OpenCode Zen free tier, $0: Big Pickle orchestrator, Nemotron 3 Ultra Free planner, North Mini Code scouts. Vision turns route to MiniMax M2.5 Free (mimo-v2.5-free, multimodal on Zen free). Ported from Oh-My-OpenAgent 'zen-free' preset. CAUTION: nemotron-3-ultra-free has known intermittent failures (opencode#38028) — switch to go-fast if flaky. Prices verified 2026-08."
61
+ zeus: { model: opencode-go/gpt-5.6-sol, reasoning_effort: medium }
62
+ athena: { model: opencode-go/deepseek-v4-pro, reasoning_effort: high }
63
+ themis: { model: opencode-go/qwen3.8-max, reasoning_effort: high }
64
+ hermes: { model: opencode-go/gpt-5.6-terra, reasoning_effort: medium }
65
+ aphrodite: { model: opencode-go/kimi-k3, reasoning_effort: medium }
66
+ demeter: { model: opencode-go/gpt-5.6-terra, reasoning_effort: medium }
67
+ prometheus: { model: opencode-go/kimi-k3, reasoning_effort: medium }
68
+ hephaestus: { model: opencode-go/gpt-5.6-terra, reasoning_effort: medium }
69
+ apollo: { model: opencode-go/gpt-5.6-luna, reasoning_effort: low }
70
+ nyx: { model: opencode-go/gpt-5.6-luna, reasoning_effort: low }
71
+ gaia: { model: opencode-go/gpt-5.6-luna, reasoning_effort: low }
72
+ iris: { model: opencode-go/gpt-5.6-luna, reasoning_effort: low }
73
+ mnemosyne: { model: opencode-go/gpt-5.6-luna, reasoning_effort: low }
74
+ talos: { model: opencode-go/gpt-5.6-luna, reasoning_effort: low }
75
+ openai:
76
+ description: "Pure OpenAI provider 2026: gpt-5.6-sol planners high, gpt-5.6-luna implementers high, gpt-5.6-luna-fast scouts low (fallback to luna low). Provider openai https://api.openai.com/v1 OPENAI_API_KEY. Pricing 2026."
129
77
  vision:
130
- model: opencode/mimo-v2.5-free
131
- reasoning_effort: low
78
+ model: openai/gpt-5.6-sol
79
+ reasoning_effort: high
132
80
  providers:
133
- opencode:
134
- baseURL: https://opencode.ai/zen/v1
135
- apiKeyEnv: PANTHEON_OPENCODE_API_KEY
81
+ openai:
82
+ baseURL: https://api.openai.com/v1
83
+ apiKeyEnv: OPENAI_API_KEY
136
84
  agents:
137
- zeus: { model: opencode/big-pickle, reasoning_effort: medium }
138
- athena: { model: opencode/nemotron-3-ultra-free, reasoning_effort: high }
139
- themis: { model: opencode/deepseek-v4-flash-free, reasoning_effort: high }
140
- hermes: { model: opencode/deepseek-v4-flash-free, reasoning_effort: medium }
141
- aphrodite: { model: opencode/deepseek-v4-flash-free, reasoning_effort: medium }
142
- demeter: { model: opencode/deepseek-v4-flash-free, reasoning_effort: medium }
143
- prometheus: { model: opencode/deepseek-v4-flash-free, reasoning_effort: medium }
144
- hephaestus: { model: opencode/deepseek-v4-flash-free, reasoning_effort: medium }
145
- apollo: { model: opencode/north-mini-code-free, reasoning_effort: low }
146
- nyx: { model: opencode/north-mini-code-free, reasoning_effort: low }
147
- gaia: { model: opencode/north-mini-code-free, reasoning_effort: low }
148
- iris: { model: opencode/north-mini-code-free, reasoning_effort: low }
149
- mnemosyne: { model: opencode/north-mini-code-free, reasoning_effort: low }
150
- talos: { model: opencode/north-mini-code-free, reasoning_effort: low }
85
+ athena: { model: openai/gpt-5.6-sol, reasoning_effort: high }
86
+ themis: { model: openai/gpt-5.6-sol, reasoning_effort: high }
87
+ zeus: { model: openai/gpt-5.6-sol, reasoning_effort: high }
88
+ hermes: { model: openai/gpt-5.6-luna, reasoning_effort: high }
89
+ aphrodite: { model: openai/gpt-5.6-luna, reasoning_effort: high }
90
+ demeter: { model: openai/gpt-5.6-luna, reasoning_effort: high }
91
+ prometheus: { model: openai/gpt-5.6-luna, reasoning_effort: high }
92
+ hephaestus: { model: openai/gpt-5.6-luna, reasoning_effort: high }
93
+ apollo: { model: openai/gpt-5.6-luna-fast, reasoning_effort: low }
94
+ nyx: { model: openai/gpt-5.6-luna-fast, reasoning_effort: low }
95
+ gaia: { model: openai/gpt-5.6-luna-fast, reasoning_effort: low }
96
+ iris: { model: openai/gpt-5.6-luna-fast, reasoning_effort: low }
97
+ mnemosyne: { model: openai/gpt-5.6-luna-fast, reasoning_effort: low }
98
+ talos: { model: openai/gpt-5.6-luna-fast, reasoning_effort: low }
151
99
  agents:
152
100
  zeus:
153
101
  role: Central orchestrator
@@ -1,307 +0,0 @@
1
- /**
2
- * Delegation Classifier — stuck-agent detection for delegation results.
3
- *
4
- * Classifies delegation results into actionable statuses:
5
- * - `content` / `success` — agent returned usable output
6
- * - `empty` (empty-mode1 / empty-mode2) — no or near-no output; retryable
7
- * - `budget-exhausted` — agent hit max_steps; partial result available
8
- * - `timeout` (timeout-with-partial / timeout-empty / timeout-exhausted)
9
- * - `error` — provider or infrastructure failure
10
- *
11
- * Integrates with the existing `dispatch-guard.ts` classification for
12
- * empty-response detection and provides a structured `DelegationResult`
13
- * that replaces raw-text returns.
14
- *
15
- * @module delegation-classifier
16
- */
17
-
18
- // ─── Types ─────────────────────────────────────────────────────────────
19
-
20
- /** Empty-response mode classification (matches dispatch-guard). */
21
- export type EmptyMode = 'empty-mode1' | 'empty-mode2'
22
-
23
- /** Timeout sub-type based on partial output and retry history. */
24
- export type TimeoutSubType = 'timeout-with-partial' | 'timeout-empty' | 'timeout-exhausted'
25
-
26
- /** Structured delegation result replacing raw-text returns. */
27
- export interface DelegationResult {
28
- status:
29
- | 'success'
30
- | 'empty'
31
- | 'budget-exhausted'
32
- | 'timeout'
33
- | 'error'
34
- | 'startup_failed'
35
- | 'bootstrap_unknown'
36
- content: string
37
- retryCount: number
38
- /** When status is 'empty', which empty mode was detected. */
39
- classification?: EmptyMode | undefined
40
- /** When status is 'timeout', the timeout sub-type. */
41
- subType?: TimeoutSubType | undefined
42
- /** Available when budget-exhausted or timeout-with-partial. */
43
- partialResult?: string | undefined
44
- /** Actionable recommendation for the orchestrator. */
45
- recommendation?: string | undefined
46
- }
47
-
48
- /** Result of empty-response classification. */
49
- export interface EmptyClassification {
50
- mode: EmptyMode | 'content'
51
- hasContent: boolean
52
- hasTokens: boolean
53
- }
54
-
55
- /** Timeout classification input. */
56
- export interface TimeoutClassifyInput {
57
- /** Report markdown (undefined if no report was written). */
58
- report: string | undefined
59
- /** Whether the child session had any messages at all. */
60
- hasMessages: boolean
61
- /** How many retries have already been attempted (0 or 1). */
62
- retryCount: number
63
- }
64
-
65
- /** Result of stuck-agent classification. */
66
- export interface StuckClassification {
67
- status: 'success' | 'budget-exhausted' | 'empty'
68
- partialResult?: string | undefined
69
- recommendation?: string | undefined
70
- }
71
-
72
- // ─── Patterns ──────────────────────────────────────────────────────────
73
-
74
- /** Matches budget-exhausted messages from the agent or step-cap system. */
75
- const BUDGET_EXHAUSTED_RE =
76
- /maximum\s+(?:steps?|step\s*budget)\s+(?:for\s+this\s+agent\s+)?(?:has|have)\s+been\s+reached|step\s*budget\s+(?:was\s+)?exhausted/i
77
-
78
- /** Output-captured marker in delegation reports. */
79
- const NO_OUTPUT_RE = /_No output captured\._/i
80
-
81
- // ─── Empty-Response Classification ────────────────────────────────────
82
-
83
- /**
84
- * Classify whether a response is empty, empty-with-tokens, or has content.
85
- * Matches the dispatch-guard classification (empty-mode1, empty-mode2).
86
- *
87
- * @param text The response text (may be null/undefined).
88
- * @param tokens Optional token counts for mode2 detection.
89
- */
90
- export function classifyEmptyResponse(
91
- text: string | null | undefined,
92
- tokens?: { tokensInput?: number; tokensOutput?: number },
93
- ): EmptyClassification {
94
- const hasContent = typeof text === 'string' && text.trim() !== ''
95
- if (hasContent) {
96
- return { mode: 'content', hasContent: true, hasTokens: hasTokens(tokens) }
97
- }
98
- const hasT = hasTokens(tokens)
99
- return {
100
- mode: hasT ? 'empty-mode2' : 'empty-mode1',
101
- hasContent: false,
102
- hasTokens: hasT,
103
- }
104
- }
105
-
106
- /** Whether token counts indicate the model actually ran. */
107
- function hasTokens(tokens?: { tokensInput?: number; tokensOutput?: number }): boolean {
108
- if (tokens === undefined) return false
109
- return (tokens.tokensInput ?? 0) > 0 || (tokens.tokensOutput ?? 0) > 0
110
- }
111
-
112
- // ─── Stuck-Agent Detection ────────────────────────────────────────────
113
-
114
- /**
115
- * Classify a report as success, budget-exhausted, or empty.
116
- * Detects max-steps patterns in the report text.
117
- *
118
- * @param report The delegation report markdown.
119
- */
120
- export function classifyStuckAgent(report: string): StuckClassification {
121
- const trimmed = report.trim()
122
-
123
- // Empty output
124
- if (NO_OUTPUT_RE.test(trimmed) || trimmed === '') {
125
- return { status: 'empty' }
126
- }
127
-
128
- // Budget-exhausted: extract content before the marker as partialResult
129
- if (BUDGET_EXHAUSTED_RE.test(trimmed)) {
130
- const outputSection = extractOutputSection(trimmed)
131
- const partialResult =
132
- outputSection !== undefined && !NO_OUTPUT_RE.test(outputSection) ? outputSection : undefined
133
-
134
- return {
135
- status: 'budget-exhausted',
136
- partialResult,
137
- recommendation:
138
- 'Agent hit step budget; partial result available. ' +
139
- 'Consider resuming with task_id or dispatching with larger budget.',
140
- }
141
- }
142
-
143
- return { status: 'success' }
144
- }
145
-
146
- /** Extract the text after "## Output" in a delegation report, or undefined. */
147
- function extractOutputSection(report: string): string | undefined {
148
- const marker = '## Output'
149
- const idx = report.indexOf(marker)
150
- if (idx === -1) return undefined
151
- const afterMarker = report.slice(idx + marker.length)
152
- // Skip the newline after "## Output"
153
- const content = afterMarker.replace(/^\n+/, '')
154
- // Stop at the next section (## or **Error**)
155
- const endIdx = content.search(/\n(?:##|\*\*Error\*\*|\[TIMEOUT)/)
156
- return endIdx === -1 ? content.trim() : content.slice(0, endIdx).trim()
157
- }
158
-
159
- // ─── Timeout Classification ───────────────────────────────────────────
160
-
161
- /**
162
- * Classify a timeout based on available output and retry history.
163
- *
164
- * - timeout-empty: no report, no messages, not yet retried → retryable
165
- * - timeout-with-partial: has report or messages → return partial
166
- * - timeout-exhausted: already retried → escalate
167
- *
168
- * @param input Report availability, message presence, and retry count.
169
- */
170
- export function classifyTimeout(input: TimeoutClassifyInput): DelegationResult {
171
- const { report, hasMessages, retryCount } = input
172
- const hasPartial =
173
- (report !== undefined && report.trim() !== '' && !NO_OUTPUT_RE.test(report)) || hasMessages
174
-
175
- // Already retried → exhausted, no more retries
176
- if (retryCount >= 1) {
177
- return {
178
- status: 'timeout',
179
- content: report ?? '',
180
- retryCount,
181
- subType: 'timeout-exhausted',
182
- partialResult: hasPartial ? (report ?? '') : undefined,
183
- recommendation:
184
- 'Agent timed out after retry. Options: ' +
185
- '(a) try different agent, (b) simplify scope, (c) manual intervention.',
186
- }
187
- }
188
-
189
- // Has partial output → return it
190
- if (hasPartial) {
191
- return {
192
- status: 'timeout',
193
- content: report ?? '',
194
- retryCount,
195
- subType: 'timeout-with-partial',
196
- partialResult: report ?? '',
197
- recommendation:
198
- 'Agent timed out but partial work exists. ' + 'Partial result is available above.',
199
- }
200
- }
201
-
202
- // No output at all → retryable
203
- return {
204
- status: 'timeout',
205
- content: report ?? '',
206
- retryCount,
207
- subType: 'timeout-empty',
208
- recommendation: 'Agent timed out with no output. Will retry once with rephrased prompt.',
209
- }
210
- }
211
-
212
- // ─── Result Helpers ───────────────────────────────────────────────────
213
-
214
- /**
215
- * Whether a delegation result is retryable (empty + retryCount < 1,
216
- * or timeout-empty + retryCount < 1).
217
- */
218
- export function isRetryableResult(result: DelegationResult): boolean {
219
- if (result.retryCount >= 1) return false
220
- if (result.status === 'empty') return true
221
- if (result.status === 'timeout' && result.subType === 'timeout-empty') return true
222
- return false
223
- }
224
-
225
- /**
226
- * Format a DelegationResult into a human-readable string for the orchestrator.
227
- * Success results are returned as-is (the raw content). Non-success results
228
- * get a structured status message.
229
- */
230
- export function formatDelegationResult(result: DelegationResult): string {
231
- if (result.status === 'success') {
232
- return result.content
233
- }
234
-
235
- const parts: string[] = []
236
-
237
- // Status header
238
- switch (result.status) {
239
- case 'empty': {
240
- const modeLabel =
241
- result.classification === 'empty-mode2'
242
- ? 'empty-mode2 (reasoning tokens present but no text output)'
243
- : 'empty-mode1 (no tokens generated)'
244
- parts.push(`[EMPTY RESULT — ${modeLabel}]`)
245
- if (result.retryCount === 0) {
246
- parts.push(
247
- 'The agent returned an empty response. ' +
248
- 'A retry with a rephrased prompt has been triggered automatically.',
249
- )
250
- } else {
251
- parts.push(
252
- 'The agent returned an empty response even after retry. ' +
253
- 'Options: (a) try different agent, (b) simplify scope, (c) manual intervention.',
254
- )
255
- }
256
- break
257
- }
258
- case 'budget-exhausted':
259
- parts.push('[BUDGET EXHAUSTED]')
260
- if (result.partialResult) {
261
- parts.push('Partial result:')
262
- parts.push(result.partialResult)
263
- }
264
- parts.push(result.recommendation ?? '')
265
- break
266
- case 'timeout': {
267
- const subLabel =
268
- result.subType === 'timeout-with-partial'
269
- ? 'with partial output'
270
- : result.subType === 'timeout-exhausted'
271
- ? 'exhausted after retry'
272
- : 'no output'
273
- parts.push(`[TIMEOUT — ${subLabel}]`)
274
- if (result.partialResult) {
275
- parts.push('Partial result:')
276
- parts.push(result.partialResult)
277
- }
278
- parts.push(result.recommendation ?? '')
279
- break
280
- }
281
- case 'error':
282
- parts.push('[ERROR]')
283
- parts.push(result.content)
284
- break
285
- case 'startup_failed':
286
- parts.push('[STARTUP FAILED]')
287
- parts.push(result.content)
288
- parts.push(
289
- result.recommendation ??
290
- 'Retry once or inspect the child session before dispatching again.',
291
- )
292
- break
293
- case 'bootstrap_unknown':
294
- parts.push('[BOOTSTRAP UNKNOWN]')
295
- parts.push(result.content)
296
- parts.push(
297
- result.recommendation ?? 'The host did not expose enough session state to verify startup.',
298
- )
299
- break
300
- }
301
-
302
- // Structured fields for non-success results
303
- parts.push(`status: ${result.status}`)
304
- parts.push(`retryCount: ${result.retryCount}`)
305
-
306
- return parts.filter((p) => p !== '').join('\n')
307
- }