pantheon-opencode 1.6.0-beta.10 → 1.6.0-beta.11
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/AGENTS.global.md +42 -18
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +24 -0
- package/README.md +66 -21
- package/bin/pantheon-init.mjs +44 -1
- package/package.json +4 -4
- package/plugin.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/build-agents-md.mjs +60 -6
- package/scripts/install/backup.mjs +475 -0
- package/scripts/install/cli-ui.mjs +6 -1
- package/scripts/install/exit-codes.mjs +26 -0
- package/scripts/install/interactive.mjs +15 -1
- package/scripts/install/migrate.mjs +41 -22
- package/scripts/install/opencode.mjs +562 -50
- package/scripts/install/plan.mjs +287 -0
- package/scripts/install/plugin.mjs +22 -8
- package/scripts/install/shared.mjs +89 -55
- package/scripts/install/strings.mjs +20 -0
- package/scripts/install/venv.mjs +13 -3
- package/scripts/install/vision-prompt.mjs +11 -1
- package/scripts/mcp_persistence.py +50 -15
- package/scripts/prune.mjs +9 -3
- package/scripts/restore.mjs +222 -0
- package/skills-lock.json +1 -1
- package/src/agents/iris.md +6 -0
- package/src/agents/zeus.md +19 -62
- package/src/instructions/agent-return-format.instructions.md +17 -15
- package/src/instructions/memory-protocol.instructions.md +3 -2
- package/src/instructions/test-economy.instructions.md +21 -0
- package/src/instructions/zeus-anti-stall.instructions.md +6 -6
- package/src/instructions/zeus-council-synthesis.instructions.md +10 -11
- package/src/instructions/zeus-memory-operations.instructions.md +10 -6
- package/src/instructions/zeus-timeout-retry.instructions.md +28 -9
- package/src/mcp/mcp_persistence.py +50 -15
- package/src/pantheon/cost-command.ts +5 -2
- package/src/pantheon/model-agents.ts +19 -0
- package/src/pantheon/model-command.ts +218 -56
- package/src/pantheon/v2-model-overrides.ts +275 -0
- package/src/pantheon/v2-tools.ts +18 -29
- package/src/plugin-v2.ts +13 -0
- package/src/plugins/tui/dist/tui-v2.js +2 -2
- package/src/plugins/tui/dist/tui.js +1 -1
- package/src/plugins/tui/package-lock.json +2 -2
- package/src/plugins/tui/package.json +1 -1
- package/src/skills/auto-continue/SKILL.md +14 -6
|
@@ -40,7 +40,7 @@ the complete plan in the current conversation before requesting approval.
|
|
|
40
40
|
|
|
41
41
|
## Council Specialist Response Format
|
|
42
42
|
|
|
43
|
-
When responding to a `/pantheon` council synthesis invocation, specialists MUST return this structured format
|
|
43
|
+
When responding to a `/pantheon` council synthesis invocation, specialists MUST return this structured format. First-round specialists receive independent prompts without peer responses, whether dispatch is parallel or synchronous/sequential; they therefore cannot know actual peer positions. Do not guess them, claim agreement/disagreement with unseen peers, or self-reference in agreement signals. Omit `agreement_signals` or write `none` in the first round. In a rebuttal round, signals may reference only peer responses included in that round's prompt. Zeus derives agreement and disagreement during synthesis by comparing actual responses.
|
|
44
44
|
|
|
45
45
|
```
|
|
46
46
|
## specialist_response
|
|
@@ -49,8 +49,8 @@ When responding to a `/pantheon` council synthesis invocation, specialists MUST
|
|
|
49
49
|
**trade_offs:** <what's gained vs lost, specific>
|
|
50
50
|
**risks:** <what could go wrong, max 3 items>
|
|
51
51
|
**confidence:** High | Medium | Low
|
|
52
|
-
**agreement_signals:**
|
|
53
|
-
**specific_claims:** <
|
|
52
|
+
**agreement_signals:** <omit or `none` in first round; rebuttal may cite only visible peer responses>
|
|
53
|
+
**specific_claims:** <optional self-reported count; advisory only, not evidence>
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
### Field Rules
|
|
@@ -62,26 +62,28 @@ When responding to a `/pantheon` council synthesis invocation, specialists MUST
|
|
|
62
62
|
| trade_offs | ✅ | At least one gain and one loss, specific to context |
|
|
63
63
|
| risks | ✅ | Max 3 bullet points |
|
|
64
64
|
| confidence | ✅ | One of: High, Medium, Low |
|
|
65
|
-
| agreement_signals | Optional |
|
|
66
|
-
| specific_claims |
|
|
65
|
+
| agreement_signals | Optional | Omit or use `none` in the first round. In rebuttal, reference only peer responses visible in the prompt; never speculate or self-reference. Zeus derives synthesis positions from actual responses, not these signals. |
|
|
66
|
+
| specific_claims | Optional | Self-reported integer count only; advisory and not independently validated. Do not treat the count alone as evidence or proof of confidence. |
|
|
67
67
|
|
|
68
68
|
### Confidence Guidelines
|
|
69
69
|
|
|
70
|
-
- **High**: Position backed by 3
|
|
71
|
-
- **Medium**: Position backed by 1
|
|
70
|
+
- **High**: Position backed by at least 3 verifiable claims supported by evidence in the response; a self-reported count alone does not qualify
|
|
71
|
+
- **Medium**: Position backed by at least 1 verifiable claim supported by evidence in the response
|
|
72
72
|
- **Low**: Position is opinion-based or speculative
|
|
73
73
|
|
|
74
|
+
Equal self-reported counts (for example, several specialists each reporting 7) do not by themselves prove fabrication; assess whether the actual response contains verifiable, supported claims.
|
|
75
|
+
|
|
74
76
|
### Example
|
|
75
77
|
```
|
|
76
78
|
## specialist_response
|
|
77
|
-
**position:**
|
|
78
|
-
**reasoning:** The
|
|
79
|
-
**trade_offs:** Gain:
|
|
80
|
-
**risks:**
|
|
81
|
-
**confidence:**
|
|
82
|
-
**agreement_signals:**
|
|
83
|
-
**specific_claims:**
|
|
79
|
+
**position:** Use a bounded local cache for the read-heavy endpoint.
|
|
80
|
+
**reasoning:** The endpoint repeatedly reads the same reference data. A bounded cache reduces repeated lookups, while a short TTL limits staleness.
|
|
81
|
+
**trade_offs:** Gain: fewer repeated reads. Lose: results may remain stale until the TTL expires.
|
|
82
|
+
**risks:** Cache invalidation may lag after updates.
|
|
83
|
+
**confidence:** Medium
|
|
84
|
+
**agreement_signals:** none
|
|
85
|
+
**specific_claims:** 2 (self-reported; advisory)
|
|
84
86
|
```
|
|
85
87
|
|
|
86
88
|
## Memory Context
|
|
87
|
-
If memory affected the result, state the takeaway briefly; do not repeat the entry or task context.
|
|
89
|
+
If memory affected the result, state the takeaway briefly; do not repeat the entry or task context. If persistence was expected but no write tool was exposed or a write failed, state that it was not persisted; never imply a successful store without confirmation.
|
|
@@ -16,8 +16,9 @@ These rules apply to all agents; each agent file may add domain-specific rules.
|
|
|
16
16
|
- Use a targeted query (`top_k=2`); do not search the whole prompt by default. Missing or irrelevant results never block current work.
|
|
17
17
|
|
|
18
18
|
### Persistence
|
|
19
|
-
-
|
|
20
|
-
-
|
|
19
|
+
- A memory write is optional and conditional on a write tool being exposed and permitted in the active session. Search permission does not imply write permission; in the reported Beta 10 Zeus root, `memory_store` is not exposed/granted.
|
|
20
|
+
- Store at most one concise, reusable top-level result; never persist routine child summaries, phase updates, test logs, or temporary state. Confirm a successful write before claiming persistence.
|
|
21
|
+
- If no write tool is available or the write did not succeed, say that the information was not persisted. Do not imply automatic memory storage or recovery. Add ADRs to the memory bank only when explicitly requested.
|
|
21
22
|
|
|
22
23
|
### Relevance and permanent records
|
|
23
24
|
Ignore weak matches; routine summaries do not belong in durable memory.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Test economy — write smaller, focused suites; heavy install/E2E suites are opt-in, never per-phase."
|
|
3
|
+
name: "Test Economy"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Write the smallest test that proves the behavior: one behavior → one focused
|
|
7
|
+
test, never the same coverage duplicated across suites or files.
|
|
8
|
+
|
|
9
|
+
- Do NOT add E2E, full-install, or network-dependent tests unless the change
|
|
10
|
+
actually alters that end-to-end path. Prefer unit or integration tests.
|
|
11
|
+
- Do not assert on copy/format strings redundantly, and do not write
|
|
12
|
+
assertions that only restate the implementation ("test the test").
|
|
13
|
+
- Heavy or slow suites (e.g. real install/E2E) MUST be opt-in via a separate
|
|
14
|
+
script/tier. Never run them per edit or per phase; run only the affected
|
|
15
|
+
subset.
|
|
16
|
+
- Respect a per-phase validation time budget: if a suite takes minutes,
|
|
17
|
+
justify running it and prefer the targeted subset. Reserve the full heavy
|
|
18
|
+
suites for release gates.
|
|
19
|
+
- Fixing a bug: add one targeted regression test, not a broad new suite.
|
|
20
|
+
- This economy rule does NOT weaken stronger gates: auth, security,
|
|
21
|
+
data-integrity, and required coverage thresholds stay mandatory.
|
|
@@ -16,18 +16,18 @@ You MUST self-monitor for these stall conditions:
|
|
|
16
16
|
| Symptom | Detection Rule | Recovery Action |
|
|
17
17
|
|---------|---------------|-----------------|
|
|
18
18
|
| Silent loop | 3+ consecutive turns with no tool call AND no visible progress | Output `[STALL_DETECTED]` and re-read your task definition. If still stuck, escalate to user with: "I appear to be stuck on [task]. Options: (1) retry with different approach, (2) delegate to specialist, (3) simplify scope." |
|
|
19
|
-
| Delegation black hole |
|
|
19
|
+
| Delegation black hole | No result or host completion notification after the applicable timeout | Stop dependent work; do not call an unavailable cancel/status tool. Follow `## ⏱️ Timeout & Retry Enforcement`, report uncertainty, and retry/reroute only under that policy |
|
|
20
20
|
| Circular delegation | Same specialist re-dispatched for same task 2+ times without progress | Break cycle: dispatch to different specialist OR escalate to user |
|
|
21
21
|
| Idle after completion | All background tasks completed but no synthesis/next step for 2+ turns | Force synthesis: summarize all completed results and propose next action |
|
|
22
22
|
| Context thrash | Re-reading same files repeatedly without new action | Stop re-reading. State: "Already have context on [file]. Proceeding with [action]." |
|
|
23
23
|
|
|
24
24
|
## Phase Reminder
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
1.
|
|
28
|
-
2.
|
|
29
|
-
3. Continue orchestration
|
|
30
|
-
4. If nothing independent remains, briefly report what was
|
|
26
|
+
Use the root `subagent` dispatch observed in the Beta 10 runtime; `task()` is host/API terminology, and the exact signature/background options depend on the active runtime. Prefer synchronous delegation unless the visible schema supports background and the host exposes a way to observe completion. For asynchronous work:
|
|
27
|
+
1. Do not invoke `task_status`, `cancel_task`, or board methods unless a corresponding tool is actually exposed (none was exposed in the reported Beta 10 root catalog).
|
|
28
|
+
2. Do not advance dependent work until a result or host-provided completion notification arrives.
|
|
29
|
+
3. Continue orchestration only on non-overlapping independent work.
|
|
30
|
+
4. If nothing independent remains, briefly report what was dispatched and wait for host notification; do not claim job tracking or recovery.
|
|
31
31
|
|
|
32
32
|
Self-check every 3 turns: "Am I waiting on a delegate? Have I polled without need? Is there independent work I can do?"
|
|
33
33
|
|
|
@@ -13,19 +13,18 @@ Use an inline specialist council for material trade-offs, architecture/security
|
|
|
13
13
|
|
|
14
14
|
1. **Precedent:** Run the separate `council_decisions` search defined in `## Memory Protocol`. Apply its age/score rules; if no fast-path decision applies, continue.
|
|
15
15
|
2. **Research (optional):** For `/pantheon --research <question>`, ask @apollo for a 30s pre-scan and pass findings as `shared_context` to every specialist.
|
|
16
|
-
3. **
|
|
17
|
-
4. **
|
|
18
|
-
5. **
|
|
19
|
-
6. **
|
|
20
|
-
7. **
|
|
21
|
-
8. **
|
|
22
|
-
9. **Persist:** Store the decision using the `council_decisions` write format in `## Memory Protocol`, then call `board.markReconciled(task_id)`.
|
|
16
|
+
3. **Select and dispatch:** Choose at most 3 agents using the domain map below. Dispatch through the root `subagent` tool observed in the Beta 10 runtime. `task()` is host/API terminology; signature, background mode, and parallel dispatch depend on the active runtime schema. Keep first-round prompts independent: do not include other specialists' responses. Dispatch in parallel when the observed tool/runtime supports it; synchronous or sequential dispatch is also valid if each first-round prompt excludes prior first-round responses. Specialists therefore cannot know actual peer positions in the first round: do not ask them to guess, signal agreement/disagreement, or refer to themselves/peers speculatively. First-round `agreement_signals` must be omitted or set to `none`.
|
|
17
|
+
4. **Collect:** Use returned subagent results or host-provided completion notifications. Do not call `task_status` or claim job tracking/recovery when unavailable. Note timeouts and missing responses explicitly. Partial responses are acceptable only from read-only @apollo or @gaia.
|
|
18
|
+
5. **Validate confidence:** High requires at least 3 verifiable claims; otherwise downgrade to Medium and state why. Medium requires at least 1 claim; Low needs no minimum. Opinions alone are not specific claims. Assess the claims and evidence actually present in each response; a self-reported `specific_claims` count is advisory, not evidence or proof of confidence.
|
|
19
|
+
6. **Resolve divergence:** After all initial responses arrive, Zeus groups their actual substantive positions by issue and derives agreement from those positions, not from speculative or self-reported `agreement_signals`. For each comparable issue, compare every unordered pair of specialists who provided a comparable substantive position on that issue. A pair agrees only when its substantive positions are compatible; every pair whose positions are not aligned counts as divergent. For an issue with `n` specialists providing comparable positions, include `n*(n-1)/2` pairs in `total_comparable_pairs`; sum this across included issues. Exclude issues with fewer than two comparable positions and state that they were excluded. Calculate `agreement_rate = agreeing_pairs / total_comparable_pairs`: unanimity is 100%, all pairs in divergence is 0%, and non-aligned pairs are divergences. If the denominator is zero, the rate is indeterminate/has no basis; never substitute an artificial zero or trigger rebuttal from an undefined rate. Below 50%, and only if no agent timed out, run one rebuttal round with all responses and the current synthesis draft. In that round, signals may refer only to peer responses visible in the rebuttal prompt; treat revised responses as final and recompute the rate from their actual positions. If the defined rate remains below 50%, research factual divergence points with official docs, benchmarks, or issues (max 3 searches; seek 2 independent sources per point when possible). Skip research for subjective-only disagreements. Send responses and a cited evidence brief to @themis as moderator; request verdicts, overall direction, confidence, and unresolved issues. Low confidence or unresolved points remain explicit in the synthesis. Moderator and audit roles are separate.
|
|
20
|
+
7. **Synthesize and audit:** Use the output format below, then ask @themis to compare raw responses with the synthesis. Check representation of every specialist, preserved divergences, accurate attribution, and confidence specificity. Fix any issue before delivery.
|
|
21
|
+
8. **Persist (conditional):** Store the decision only if a memory-write tool is explicitly exposed and permitted in the active root tool list; require its success result before saying it was saved. Otherwise say the decision was not persisted. The `BackgroundJobBoard` is internal and has no root-callable board tool in the reported runtime.
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
The `BackgroundJobBoard` is internal bookkeeping, not a tool available to Zeus root; do not call `board.registerLaunch`, `markReconciled`, `recoverRunningJobs`, or `formatForPrompt`, and do not assume crash recovery. If context is lost, continue only from results still present in the conversation or a host handoff; otherwise report the missing context and ask how to proceed.
|
|
25
24
|
|
|
26
25
|
## Specialist Response Format
|
|
27
26
|
|
|
28
|
-
Require `## specialist_response` from `## Agent Return Format
|
|
27
|
+
Require `## specialist_response` from `## Agent Return Format`. The first round must not prompt specialists to infer other agents' views; agreement signals are omitted or `none` until actual peer responses are visible.
|
|
29
28
|
|
|
30
29
|
## Domain Map
|
|
31
30
|
|
|
@@ -53,7 +52,7 @@ Question / date / response rate / timed-out agents / precedent / research contex
|
|
|
53
52
|
- Points shared by multiple specialists
|
|
54
53
|
|
|
55
54
|
### Divergences
|
|
56
|
-
| Issue |
|
|
55
|
+
| Issue | Specialist positions (attribute each side to its agent) | Resolution |
|
|
57
56
|
|
|
58
57
|
### Evidence & Moderation (when used)
|
|
59
58
|
Research points, evidence, moderator verdict, cited sources, unresolved issues
|
|
@@ -68,4 +67,4 @@ Themis approved, or issues corrected
|
|
|
68
67
|
Confidence adjusted for response rate
|
|
69
68
|
```
|
|
70
69
|
|
|
71
|
-
|
|
70
|
+
Initial agreement signals remain omitted/`none`; consensus and agreements are derived by Zeus from compared substantive positions and presented in the synthesis. Preserve actual specialist timeout or unresolved-tie details in the response. The user invokes this flow with `/pantheon <question>`; `--research` enables the Apollo pre-scan.
|
|
@@ -18,9 +18,13 @@ Before a council, search separately from the task-level lookup only when a past
|
|
|
18
18
|
Use a recent, directly matching decision only after checking current context;
|
|
19
19
|
otherwise treat it as background, never as authority to skip a needed review.
|
|
20
20
|
|
|
21
|
-
Persist only reusable, material decisions
|
|
22
|
-
|
|
23
|
-
`
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
Persist only reusable, material decisions, and only if a memory-write tool is
|
|
22
|
+
explicitly exposed and permitted in the active root tool list. The reported Beta
|
|
23
|
+
10 Zeus root has `memory_search` but no `memory_store` grant/tool; search access
|
|
24
|
+
does not imply write access. If a write tool is available, use
|
|
25
|
+
`key="council:<yyyy-mm-dd>:<slug>"`, JSON-stringify both `value` and `metadata`,
|
|
26
|
+
and confirm success before claiming persistence. Otherwise tell the user the
|
|
27
|
+
decision was not persisted. Keep any saved record concise: question, recommendation,
|
|
28
|
+
specialists, confidence, unresolved trade-off, and timestamp. Do not store routine
|
|
29
|
+
subtask summaries or status updates. Use the memory bank for ADRs only when
|
|
30
|
+
explicitly requested.
|
|
@@ -9,6 +9,13 @@ fallback: shared
|
|
|
9
9
|
|
|
10
10
|
When a delegated agent does not respond in time, enforce the timeout policy from `routing.yml`.
|
|
11
11
|
|
|
12
|
+
Use the root `subagent` dispatch observed in the Beta 10 runtime. `task()` is
|
|
13
|
+
host/API terminology; the active runtime determines the callable schema and any
|
|
14
|
+
background options. Do not assume root `task_status`, `cancel_task`, or board
|
|
15
|
+
tracking/recovery tools. Prefer synchronous dispatch unless background completion
|
|
16
|
+
is observable through the host, and keep any retry list in the current context
|
|
17
|
+
only; do not claim persistent job tracking.
|
|
18
|
+
|
|
12
19
|
## Timeout Behavior by Agent Role
|
|
13
20
|
|
|
14
21
|
| Agent Role | Timeout | Retry Policy | Partial Results OK? | Reasoning Effort |
|
|
@@ -43,14 +50,18 @@ at most once, and an exhausted chain is never restarted automatically.
|
|
|
43
50
|
|
|
44
51
|
For a domain/scope refusal, do not retry with a rephrased prompt. Correct the
|
|
45
52
|
route once only when the right specialist is clear; otherwise stop and ask.
|
|
46
|
-
Record one `DelegationCacheDecision` telemetry item
|
|
47
|
-
|
|
53
|
+
Record one `DelegationCacheDecision` telemetry item only when telemetry recording
|
|
54
|
+
is actually exposed; otherwise keep the corrected route in the current handoff
|
|
55
|
+
and do not claim telemetry was persisted. Include `reroute_from`, `reroute_to`,
|
|
56
|
+
and `delegation_id` when available.
|
|
48
57
|
|
|
49
58
|
### Escalation Protocol
|
|
50
59
|
When all fallbacks fail, report the tried agents and errors, offer a different approach/simpler scope/manual fix, and stop. Never retry the same chain automatically.
|
|
51
60
|
|
|
52
61
|
### Session Reuse Check
|
|
53
|
-
|
|
62
|
+
Reuse a prior specialist session only when the active host exposes that capability;
|
|
63
|
+
otherwise dispatch through `subagent` with necessary context. Treat `session_max`
|
|
64
|
+
as policy context, not as a claim that Zeus can enumerate sessions.
|
|
54
65
|
|
|
55
66
|
---
|
|
56
67
|
|
|
@@ -65,19 +76,23 @@ Use the lightest path that safely meets the request. A multi-file but bounded lo
|
|
|
65
76
|
### Subtask Decision Tree (run BEFORE every delegation)
|
|
66
77
|
|
|
67
78
|
```
|
|
68
|
-
□ Is the scope clear, bounded, and
|
|
69
|
-
□ Does it avoid auth/security, data/schema, and
|
|
70
|
-
□ Is there no required Themis/audit handoff for this change?
|
|
79
|
+
□ Is the scope clear, bounded, reversible, and low-uncertainty? [YES→continue | NO→clarify/plan]
|
|
80
|
+
□ Does it avoid auth/security, data/schema, destructive, broad/material, and user-visible API risk? [YES→continue | NO→relevant gates]
|
|
81
|
+
□ Is there no required Themis/audit handoff for this change? [YES→continue | NO→preserve that review]
|
|
71
82
|
|
|
72
|
-
ALL YES →
|
|
83
|
+
ALL YES → one correct domain specialist; they inspect needed context, implement, and verify; no routine plan/artifact, separate discovery, council, or review
|
|
73
84
|
ANY NO → add only the planning, artifact, specialist review, and approval gates the risk requires
|
|
74
85
|
```
|
|
75
86
|
|
|
76
87
|
### Safety Rules
|
|
77
88
|
1. **Bounded scope** — can be a small multi-file change or a read-only investigation
|
|
78
|
-
2. **Low risk** — no security implications,
|
|
89
|
+
2. **Low risk and uncertainty** — no security implications, data loss, breaking/user-visible API impact, broad material scope, or unresolved high uncertainty
|
|
79
90
|
3. **No required Themis dependency** — sensitive/material output retains its review gate
|
|
80
91
|
|
|
92
|
+
The selected specialist, not a routine Apollo discovery pass, inspects the relevant
|
|
93
|
+
local context for a lightweight implementation. Keep specialist roles available for
|
|
94
|
+
on-demand routing; do not remove an agent based on one task or one overhead observation.
|
|
95
|
+
|
|
81
96
|
## Subtask Return Format
|
|
82
97
|
Return the required `## subtask_summary` fields defined in `## Agent Return Format`; include `memory_context` when memory was used.
|
|
83
98
|
|
|
@@ -89,4 +104,8 @@ Only agents marked ✅ in the Timeout Behavior table above may return partial re
|
|
|
89
104
|
|
|
90
105
|
# 📊 TIMEOUT TRACKING
|
|
91
106
|
|
|
92
|
-
|
|
107
|
+
Keep only an in-context list of active delegations and already-tried agents when
|
|
108
|
+
needed. Use results returned by `subagent` or host completion notifications; do
|
|
109
|
+
not poll, cancel, or write a timeout log unless the corresponding tool is exposed.
|
|
110
|
+
Report any timeout and the retry/fallback taken in the user-facing handoff; do
|
|
111
|
+
not claim persistent tracking or recovery.
|
|
@@ -914,15 +914,35 @@ def _validate_delegations(delegations: object) -> None:
|
|
|
914
914
|
|
|
915
915
|
def _validate_tail(tail: object, payload_bytes: int | None = None) -> list[str]:
|
|
916
916
|
"""Validate bounded serialized tail lines."""
|
|
917
|
-
if not isinstance(tail, list)
|
|
918
|
-
raise ValueError("tail
|
|
917
|
+
if not isinstance(tail, list):
|
|
918
|
+
raise ValueError("tail must be an array")
|
|
919
|
+
if len(tail) > MAX_TAIL_ITEMS:
|
|
920
|
+
raise ValueError(
|
|
921
|
+
f"tail has {len(tail)} items; maximum is {MAX_TAIL_ITEMS}; "
|
|
922
|
+
"remove tail entries or omit tail"
|
|
923
|
+
)
|
|
919
924
|
for line in tail:
|
|
920
|
-
if not isinstance(line, str)
|
|
921
|
-
raise ValueError("tail entries
|
|
925
|
+
if not isinstance(line, str):
|
|
926
|
+
raise ValueError("tail entries must be strings")
|
|
927
|
+
line_bytes = len(line.encode())
|
|
928
|
+
if line_bytes > MAX_TAIL_LINE_LENGTH:
|
|
929
|
+
raise ValueError(
|
|
930
|
+
f"tail entries are {line_bytes:,} UTF-8 bytes; maximum is "
|
|
931
|
+
f"{MAX_TAIL_LINE_LENGTH:,}; remove or shorten tail entries, "
|
|
932
|
+
"or omit tail"
|
|
933
|
+
)
|
|
922
934
|
if payload_bytes is not None and payload_bytes > MAX_CONTEXT_CONTENT_BYTES:
|
|
923
|
-
raise ValueError(
|
|
924
|
-
|
|
925
|
-
|
|
935
|
+
raise ValueError(
|
|
936
|
+
f"tail payload is {payload_bytes:,} UTF-8 bytes; maximum is "
|
|
937
|
+
f"{MAX_CONTEXT_CONTENT_BYTES:,}; remove tail entries or omit tail"
|
|
938
|
+
)
|
|
939
|
+
tail_bytes = sum(len(line.encode()) for line in tail)
|
|
940
|
+
if tail_bytes > MAX_CONTEXT_CONTENT_BYTES:
|
|
941
|
+
raise ValueError(
|
|
942
|
+
f"tail contains {tail_bytes:,} UTF-8 bytes across strings; maximum "
|
|
943
|
+
f"is {MAX_CONTEXT_CONTENT_BYTES:,} bytes; remove tail entries or "
|
|
944
|
+
"omit tail"
|
|
945
|
+
)
|
|
926
946
|
return tail
|
|
927
947
|
|
|
928
948
|
|
|
@@ -1020,8 +1040,14 @@ def _collect_context_content_errors(
|
|
|
1020
1040
|
if not isinstance(content, str):
|
|
1021
1041
|
errors.shape(prefix, "a string", content)
|
|
1022
1042
|
return
|
|
1023
|
-
|
|
1024
|
-
|
|
1043
|
+
content_bytes = len(content.encode())
|
|
1044
|
+
if content_bytes > MAX_CONTEXT_CONTENT_BYTES:
|
|
1045
|
+
errors.add(
|
|
1046
|
+
prefix,
|
|
1047
|
+
f"is {content_bytes:,} UTF-8 bytes; maximum is "
|
|
1048
|
+
f"{MAX_CONTEXT_CONTENT_BYTES:,} bytes. Reduce content or omit "
|
|
1049
|
+
"optional tail if it contributes",
|
|
1050
|
+
)
|
|
1025
1051
|
return
|
|
1026
1052
|
try:
|
|
1027
1053
|
parsed = json.loads(content)
|
|
@@ -1030,11 +1056,10 @@ def _collect_context_content_errors(
|
|
|
1030
1056
|
# it as a checkpoint. It is still bounded above.
|
|
1031
1057
|
return
|
|
1032
1058
|
if isinstance(parsed, list) and key == "tail":
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
errors.add(f"{prefix}.tail", "exceeds its size limit")
|
|
1059
|
+
try:
|
|
1060
|
+
_validate_tail(parsed)
|
|
1061
|
+
except ValueError as exc:
|
|
1062
|
+
errors.reroot(prefix, str(exc))
|
|
1038
1063
|
return
|
|
1039
1064
|
if not isinstance(parsed, dict):
|
|
1040
1065
|
# The message already names 'content': do not prepend the path again.
|
|
@@ -1164,6 +1189,11 @@ def _upsert_context_entry(
|
|
|
1164
1189
|
name="context_save",
|
|
1165
1190
|
description="Save a context checkpoint for a session/phase. "
|
|
1166
1191
|
"Stores structured JSON in persistence KV with a key-specific TTL. "
|
|
1192
|
+
"The serialized content is limited to 65,536 UTF-8 bytes. An included "
|
|
1193
|
+
"tail may contain at most 100 strings, each at most 4,096 UTF-8 bytes, "
|
|
1194
|
+
"with at most 65,536 UTF-8 bytes across all tail strings. Oversized "
|
|
1195
|
+
"content or tail is rejected, never truncated; remove or omit optional "
|
|
1196
|
+
"tail data when applicable. "
|
|
1167
1197
|
"content is a JSON STRING; when it parses to an object, 'goal', 'phase', "
|
|
1168
1198
|
"'delegations' and 'heartbeat' must each be JSON OBJECTS and 'tail' must "
|
|
1169
1199
|
"be a JSON ARRAY. 'phase' is an object {current,total,name} — NOT a phase "
|
|
@@ -1180,7 +1210,12 @@ async def context_save(
|
|
|
1180
1210
|
str,
|
|
1181
1211
|
Field(
|
|
1182
1212
|
description=(
|
|
1183
|
-
"JSON checkpoint string
|
|
1213
|
+
"JSON checkpoint string, limited to 65,536 UTF-8 bytes. An "
|
|
1214
|
+
"included 'tail' may contain at most 100 strings, each at "
|
|
1215
|
+
"most 4,096 UTF-8 bytes, with at most 65,536 UTF-8 bytes "
|
|
1216
|
+
"across all tail strings. Oversized input is rejected, never "
|
|
1217
|
+
"truncated; remove or omit optional 'tail' when applicable. "
|
|
1218
|
+
"When it parses to an object, 'goal', "
|
|
1184
1219
|
"'phase', 'delegations' and 'heartbeat' must be objects and "
|
|
1185
1220
|
"'tail' must be an array; all are optional. 'phase' is an "
|
|
1186
1221
|
"object {current,total,name}, not a counter. Example: "
|
|
@@ -129,7 +129,7 @@ const costArgs = {
|
|
|
129
129
|
.min(1)
|
|
130
130
|
.max(365)
|
|
131
131
|
.optional()
|
|
132
|
-
.describe('Number of days of
|
|
132
|
+
.describe('Number of rolling 24-hour days of history to include (default 7).'),
|
|
133
133
|
} satisfies z.ZodRawShape
|
|
134
134
|
|
|
135
135
|
/** The XDG state directory every real host installation writes its ledger to. */
|
|
@@ -459,6 +459,9 @@ function renderMarkdown(query: CostQuery, days: number): string {
|
|
|
459
459
|
const header = `## Token usage by agent and phase (last ${days} days)`
|
|
460
460
|
const footer = [
|
|
461
461
|
formatCoverage(coverage, days),
|
|
462
|
+
'Window: rolling 24-hour days from query time (not calendar days or session boundaries).',
|
|
463
|
+
'Aggregation: per agent and phase; phase may be unknown on V2.',
|
|
464
|
+
'Limits: not grouped by session, task, model, or provider; tokens only (no dollar costs), so this cannot establish model-specific savings or deltas.',
|
|
462
465
|
`Source: opencode.db (read-only) — table families: ${coverage.sources.join(' + ')} — ${coverage.assistantRows} assistant row(s) scanned`,
|
|
463
466
|
].join('\n')
|
|
464
467
|
if (rows.length === 0) {
|
|
@@ -823,7 +826,7 @@ export function createCostCommand(options?: CostCommandOptions): CostCommand {
|
|
|
823
826
|
return {
|
|
824
827
|
pantheon_cost: {
|
|
825
828
|
description:
|
|
826
|
-
'Report input, output, and total token usage by agent and phase
|
|
829
|
+
'Report input, output, and total token usage by agent and phase in a rolling N × 24-hour window from query time (read-only, no monetary values). It is not grouped by session, task, model, or provider; phase may be unknown on V2, so it cannot establish model-specific savings or deltas. The report states the coverage window it actually covers.',
|
|
827
830
|
args: costArgs,
|
|
828
831
|
execute,
|
|
829
832
|
},
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Canonical agent IDs shared by model routing and V2 override validation. */
|
|
2
|
+
export const KNOWN_AGENTS = [
|
|
3
|
+
'zeus',
|
|
4
|
+
'athena',
|
|
5
|
+
'apollo',
|
|
6
|
+
'hermes',
|
|
7
|
+
'aphrodite',
|
|
8
|
+
'demeter',
|
|
9
|
+
'themis',
|
|
10
|
+
'prometheus',
|
|
11
|
+
'hephaestus',
|
|
12
|
+
'nyx',
|
|
13
|
+
'gaia',
|
|
14
|
+
'iris',
|
|
15
|
+
'mnemosyne',
|
|
16
|
+
'talos',
|
|
17
|
+
] as const
|
|
18
|
+
|
|
19
|
+
export type KnownAgent = (typeof KNOWN_AGENTS)[number]
|