pantheon-opencode 1.5.0-beta.16 → 1.5.0-beta.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +13 -25
  3. package/README.pt-BR.md +4 -5
  4. package/package.json +1 -1
  5. package/plugin.json +1 -1
  6. package/pyproject.toml +1 -1
  7. package/scripts/mcp_persistence_server.py +1 -1
  8. package/src/agents/apollo.md +1 -0
  9. package/src/agents/gaia.md +1 -0
  10. package/src/agents/zeus.md +8 -29
  11. package/src/mcp/mcp_persistence_server.py +1 -1
  12. package/src/pantheon/{delegation-compaction.ts → compaction-context.ts} +10 -100
  13. package/src/pantheon/cost-command.ts +1 -2
  14. package/src/pantheon/delegation-enforce.ts +59 -14
  15. package/src/pantheon/goal-loop.ts +1 -1
  16. package/src/pantheon/goal-store.ts +1 -1
  17. package/src/pantheon/idle-continuation.ts +4 -6
  18. package/src/pantheon/model-command.ts +1 -2
  19. package/src/pantheon/native-task-status.ts +2 -2
  20. package/src/pantheon/session-id.ts +30 -0
  21. package/src/pantheon/task-result-guard.ts +2 -3
  22. package/src/pantheon/todo-enforcer.ts +3 -3
  23. package/src/pantheon/tool-context.ts +23 -0
  24. package/src/pantheon/v2-bridge.ts +1 -4
  25. package/src/plugin-v2.ts +4 -15
  26. package/src/plugin.ts +61 -245
  27. package/src/plugins/tui/dist/tui.d.ts +49 -79
  28. package/src/plugins/tui/dist/tui.d.ts.map +1 -1
  29. package/src/plugins/tui/dist/tui.js +48 -189
  30. package/src/plugins/tui/package-lock.json +2 -2
  31. package/src/plugins/tui/package.json +1 -1
  32. package/src/plugins/tui/src/index.tsx +97 -295
  33. package/src/skills/context-compression/SKILL.md +1 -1
  34. package/src/pantheon/delegate-manager.ts +0 -851
  35. package/src/pantheon/delegation-classifier.ts +0 -306
  36. package/src/pantheon/delegation-finalize.ts +0 -468
  37. package/src/pantheon/delegation-notify.ts +0 -212
  38. package/src/pantheon/delegation-toast.ts +0 -73
  39. package/src/pantheon/delegation.ts +0 -1349
  40. package/src/pantheon/native-probe.ts +0 -234
  41. package/src/pantheon/step-cap.ts +0 -110
@@ -1,306 +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
- * Provides empty-response detection and a structured `DelegationResult`
12
- * that replaces raw-text returns.
13
- *
14
- * @module delegation-classifier
15
- */
16
-
17
- // ─── Types ─────────────────────────────────────────────────────────────
18
-
19
- /** Empty-response mode classification (empty-mode1 / empty-mode2). */
20
- export type EmptyMode = 'empty-mode1' | 'empty-mode2'
21
-
22
- /** Timeout sub-type based on partial output and retry history. */
23
- export type TimeoutSubType = 'timeout-with-partial' | 'timeout-empty' | 'timeout-exhausted'
24
-
25
- /** Structured delegation result replacing raw-text returns. */
26
- export interface DelegationResult {
27
- status:
28
- | 'success'
29
- | 'empty'
30
- | 'budget-exhausted'
31
- | 'timeout'
32
- | 'error'
33
- | 'startup_failed'
34
- | 'bootstrap_unknown'
35
- content: string
36
- retryCount: number
37
- /** When status is 'empty', which empty mode was detected. */
38
- classification?: EmptyMode | undefined
39
- /** When status is 'timeout', the timeout sub-type. */
40
- subType?: TimeoutSubType | undefined
41
- /** Available when budget-exhausted or timeout-with-partial. */
42
- partialResult?: string | undefined
43
- /** Actionable recommendation for the orchestrator. */
44
- recommendation?: string | undefined
45
- }
46
-
47
- /** Result of empty-response classification. */
48
- export interface EmptyClassification {
49
- mode: EmptyMode | 'content'
50
- hasContent: boolean
51
- hasTokens: boolean
52
- }
53
-
54
- /** Timeout classification input. */
55
- export interface TimeoutClassifyInput {
56
- /** Report markdown (undefined if no report was written). */
57
- report: string | undefined
58
- /** Whether the child session had any messages at all. */
59
- hasMessages: boolean
60
- /** How many retries have already been attempted (0 or 1). */
61
- retryCount: number
62
- }
63
-
64
- /** Result of stuck-agent classification. */
65
- export interface StuckClassification {
66
- status: 'success' | 'budget-exhausted' | 'empty'
67
- partialResult?: string | undefined
68
- recommendation?: string | undefined
69
- }
70
-
71
- // ─── Patterns ──────────────────────────────────────────────────────────
72
-
73
- /** Matches budget-exhausted messages from the agent or step-cap system. */
74
- const BUDGET_EXHAUSTED_RE =
75
- /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
76
-
77
- /** Output-captured marker in delegation reports. */
78
- const NO_OUTPUT_RE = /_No output captured\._/i
79
-
80
- // ─── Empty-Response Classification ────────────────────────────────────
81
-
82
- /**
83
- * Classify whether a response is empty, empty-with-tokens, or has content.
84
- * Classifies empty-mode1 (no text/tokens) vs empty-mode2 (tokens, no text).
85
- *
86
- * @param text The response text (may be null/undefined).
87
- * @param tokens Optional token counts for mode2 detection.
88
- */
89
- export function classifyEmptyResponse(
90
- text: string | null | undefined,
91
- tokens?: { tokensInput?: number; tokensOutput?: number },
92
- ): EmptyClassification {
93
- const hasContent = typeof text === 'string' && text.trim() !== ''
94
- if (hasContent) {
95
- return { mode: 'content', hasContent: true, hasTokens: hasTokens(tokens) }
96
- }
97
- const hasT = hasTokens(tokens)
98
- return {
99
- mode: hasT ? 'empty-mode2' : 'empty-mode1',
100
- hasContent: false,
101
- hasTokens: hasT,
102
- }
103
- }
104
-
105
- /** Whether token counts indicate the model actually ran. */
106
- function hasTokens(tokens?: { tokensInput?: number; tokensOutput?: number }): boolean {
107
- if (tokens === undefined) return false
108
- return (tokens.tokensInput ?? 0) > 0 || (tokens.tokensOutput ?? 0) > 0
109
- }
110
-
111
- // ─── Stuck-Agent Detection ────────────────────────────────────────────
112
-
113
- /**
114
- * Classify a report as success, budget-exhausted, or empty.
115
- * Detects max-steps patterns in the report text.
116
- *
117
- * @param report The delegation report markdown.
118
- */
119
- export function classifyStuckAgent(report: string): StuckClassification {
120
- const trimmed = report.trim()
121
-
122
- // Empty output
123
- if (NO_OUTPUT_RE.test(trimmed) || trimmed === '') {
124
- return { status: 'empty' }
125
- }
126
-
127
- // Budget-exhausted: extract content before the marker as partialResult
128
- if (BUDGET_EXHAUSTED_RE.test(trimmed)) {
129
- const outputSection = extractOutputSection(trimmed)
130
- const partialResult =
131
- outputSection !== undefined && !NO_OUTPUT_RE.test(outputSection) ? outputSection : undefined
132
-
133
- return {
134
- status: 'budget-exhausted',
135
- partialResult,
136
- recommendation:
137
- 'Agent hit step budget; partial result available. ' +
138
- 'Consider resuming with task_id or dispatching with larger budget.',
139
- }
140
- }
141
-
142
- return { status: 'success' }
143
- }
144
-
145
- /** Extract the text after "## Output" in a delegation report, or undefined. */
146
- function extractOutputSection(report: string): string | undefined {
147
- const marker = '## Output'
148
- const idx = report.indexOf(marker)
149
- if (idx === -1) return undefined
150
- const afterMarker = report.slice(idx + marker.length)
151
- // Skip the newline after "## Output"
152
- const content = afterMarker.replace(/^\n+/, '')
153
- // Stop at the next section (## or **Error**)
154
- const endIdx = content.search(/\n(?:##|\*\*Error\*\*|\[TIMEOUT)/)
155
- return endIdx === -1 ? content.trim() : content.slice(0, endIdx).trim()
156
- }
157
-
158
- // ─── Timeout Classification ───────────────────────────────────────────
159
-
160
- /**
161
- * Classify a timeout based on available output and retry history.
162
- *
163
- * - timeout-empty: no report, no messages, not yet retried → retryable
164
- * - timeout-with-partial: has report or messages → return partial
165
- * - timeout-exhausted: already retried → escalate
166
- *
167
- * @param input Report availability, message presence, and retry count.
168
- */
169
- export function classifyTimeout(input: TimeoutClassifyInput): DelegationResult {
170
- const { report, hasMessages, retryCount } = input
171
- const hasPartial =
172
- (report !== undefined && report.trim() !== '' && !NO_OUTPUT_RE.test(report)) || hasMessages
173
-
174
- // Already retried → exhausted, no more retries
175
- if (retryCount >= 1) {
176
- return {
177
- status: 'timeout',
178
- content: report ?? '',
179
- retryCount,
180
- subType: 'timeout-exhausted',
181
- partialResult: hasPartial ? (report ?? '') : undefined,
182
- recommendation:
183
- 'Agent timed out after retry. Options: ' +
184
- '(a) try different agent, (b) simplify scope, (c) manual intervention.',
185
- }
186
- }
187
-
188
- // Has partial output → return it
189
- if (hasPartial) {
190
- return {
191
- status: 'timeout',
192
- content: report ?? '',
193
- retryCount,
194
- subType: 'timeout-with-partial',
195
- partialResult: report ?? '',
196
- recommendation:
197
- 'Agent timed out but partial work exists. ' + 'Partial result is available above.',
198
- }
199
- }
200
-
201
- // No output at all → retryable
202
- return {
203
- status: 'timeout',
204
- content: report ?? '',
205
- retryCount,
206
- subType: 'timeout-empty',
207
- recommendation: 'Agent timed out with no output. Will retry once with rephrased prompt.',
208
- }
209
- }
210
-
211
- // ─── Result Helpers ───────────────────────────────────────────────────
212
-
213
- /**
214
- * Whether a delegation result is retryable (empty + retryCount < 1,
215
- * or timeout-empty + retryCount < 1).
216
- */
217
- export function isRetryableResult(result: DelegationResult): boolean {
218
- if (result.retryCount >= 1) return false
219
- if (result.status === 'empty') return true
220
- if (result.status === 'timeout' && result.subType === 'timeout-empty') return true
221
- return false
222
- }
223
-
224
- /**
225
- * Format a DelegationResult into a human-readable string for the orchestrator.
226
- * Success results are returned as-is (the raw content). Non-success results
227
- * get a structured status message.
228
- */
229
- export function formatDelegationResult(result: DelegationResult): string {
230
- if (result.status === 'success') {
231
- return result.content
232
- }
233
-
234
- const parts: string[] = []
235
-
236
- // Status header
237
- switch (result.status) {
238
- case 'empty': {
239
- const modeLabel =
240
- result.classification === 'empty-mode2'
241
- ? 'empty-mode2 (reasoning tokens present but no text output)'
242
- : 'empty-mode1 (no tokens generated)'
243
- parts.push(`[EMPTY RESULT — ${modeLabel}]`)
244
- if (result.retryCount === 0) {
245
- parts.push(
246
- 'The agent returned an empty response. ' +
247
- 'A retry with a rephrased prompt has been triggered automatically.',
248
- )
249
- } else {
250
- parts.push(
251
- 'The agent returned an empty response even after retry. ' +
252
- 'Options: (a) try different agent, (b) simplify scope, (c) manual intervention.',
253
- )
254
- }
255
- break
256
- }
257
- case 'budget-exhausted':
258
- parts.push('[BUDGET EXHAUSTED]')
259
- if (result.partialResult) {
260
- parts.push('Partial result:')
261
- parts.push(result.partialResult)
262
- }
263
- parts.push(result.recommendation ?? '')
264
- break
265
- case 'timeout': {
266
- const subLabel =
267
- result.subType === 'timeout-with-partial'
268
- ? 'with partial output'
269
- : result.subType === 'timeout-exhausted'
270
- ? 'exhausted after retry'
271
- : 'no output'
272
- parts.push(`[TIMEOUT — ${subLabel}]`)
273
- if (result.partialResult) {
274
- parts.push('Partial result:')
275
- parts.push(result.partialResult)
276
- }
277
- parts.push(result.recommendation ?? '')
278
- break
279
- }
280
- case 'error':
281
- parts.push('[ERROR]')
282
- parts.push(result.content)
283
- break
284
- case 'startup_failed':
285
- parts.push('[STARTUP FAILED]')
286
- parts.push(result.content)
287
- parts.push(
288
- result.recommendation ??
289
- 'Retry once or inspect the child session before dispatching again.',
290
- )
291
- break
292
- case 'bootstrap_unknown':
293
- parts.push('[BOOTSTRAP UNKNOWN]')
294
- parts.push(result.content)
295
- parts.push(
296
- result.recommendation ?? 'The host did not expose enough session state to verify startup.',
297
- )
298
- break
299
- }
300
-
301
- // Structured fields for non-success results
302
- parts.push(`status: ${result.status}`)
303
- parts.push(`retryCount: ${result.retryCount}`)
304
-
305
- return parts.filter((p) => p !== '').join('\n')
306
- }