@aragon-agent/cli 0.6.38 → 0.6.40
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/CHANGELOG.md +263 -0
- package/README.md +544 -11
- package/dist/agent/controller.d.ts +245 -10
- package/dist/agent/controller.js +367 -22
- package/dist/agent/model-profile-settings.js +12 -1
- package/dist/agent/plan-prompt.d.ts +1 -3
- package/dist/agent/plan-prompt.js +13 -7
- package/dist/agent/reducer.d.ts +70 -2
- package/dist/agent/reducer.js +59 -6
- package/dist/agent/skill-triage-prompt.d.ts +42 -0
- package/dist/agent/skill-triage-prompt.js +74 -0
- package/dist/agent/system-prompt.d.ts +28 -2
- package/dist/agent/system-prompt.js +12 -4
- package/dist/cli.js +106 -32
- package/dist/commands/builtins.js +24 -3
- package/dist/commands/keys-command.d.ts +23 -0
- package/dist/commands/keys-command.js +38 -0
- package/dist/commands/registry.d.ts +39 -0
- package/dist/commands/skills.js +86 -1
- package/dist/commands/subagent-command.d.ts +25 -0
- package/dist/commands/subagent-command.js +242 -0
- package/dist/commands/task-command.d.ts +39 -0
- package/dist/commands/task-command.js +102 -0
- package/dist/compaction/command.js +16 -3
- package/dist/compaction/compactor.d.ts +25 -0
- package/dist/compaction/compactor.js +111 -10
- package/dist/compaction/digest.d.ts +24 -1
- package/dist/compaction/digest.js +139 -17
- package/dist/compaction/limits.d.ts +21 -0
- package/dist/compaction/limits.js +21 -0
- package/dist/compaction/reason-text.d.ts +36 -0
- package/dist/compaction/reason-text.js +78 -0
- package/dist/compaction/types.d.ts +82 -14
- package/dist/compaction/wiring.d.ts +13 -8
- package/dist/compaction/wiring.js +1 -0
- package/dist/config/cli-commands.d.ts +23 -0
- package/dist/config/cli-commands.js +36 -0
- package/dist/config/env.js +17 -4
- package/dist/config/load.js +55 -3
- package/dist/config/schema.d.ts +125 -10
- package/dist/config/schema.js +138 -14
- package/dist/config/store.js +23 -3
- package/dist/diagnostics/doctor.d.ts +9 -0
- package/dist/diagnostics/doctor.js +34 -0
- package/dist/diagnostics/info.d.ts +71 -0
- package/dist/diagnostics/info.js +91 -5
- package/dist/exec/bridge/caller-tools.d.ts +96 -0
- package/dist/exec/bridge/caller-tools.js +213 -0
- package/dist/exec/bridge/decisions.d.ts +78 -0
- package/dist/exec/bridge/decisions.js +116 -0
- package/dist/exec/bridge/human-answers.d.ts +38 -0
- package/dist/exec/bridge/human-answers.js +164 -0
- package/dist/exec/bridge/limits.d.ts +68 -0
- package/dist/exec/bridge/limits.js +68 -0
- package/dist/exec/bridge/ndjson.d.ts +17 -0
- package/dist/exec/bridge/ndjson.js +83 -0
- package/dist/exec/bridge/pending.d.ts +70 -0
- package/dist/exec/bridge/pending.js +132 -0
- package/dist/exec/bridge/protocol.d.ts +346 -0
- package/dist/exec/bridge/protocol.js +256 -0
- package/dist/exec/bridge/server.d.ts +142 -0
- package/dist/exec/bridge/server.js +502 -0
- package/dist/exec/bridge/source.d.ts +58 -0
- package/dist/exec/bridge/source.js +145 -0
- package/dist/exec/bridge/writer.d.ts +26 -0
- package/dist/exec/bridge/writer.js +156 -0
- package/dist/exec/cli-commands.js +30 -2
- package/dist/exec/emitter.d.ts +16 -2
- package/dist/exec/emitter.js +26 -6
- package/dist/exec/events.d.ts +465 -10
- package/dist/exec/events.js +47 -1
- package/dist/exec/hooks/dispatch.d.ts +76 -0
- package/dist/exec/hooks/dispatch.js +169 -0
- package/dist/exec/hooks/index.d.ts +83 -0
- package/dist/exec/hooks/index.js +205 -0
- package/dist/exec/hooks/limits.d.ts +56 -0
- package/dist/exec/hooks/limits.js +49 -0
- package/dist/exec/hooks/registry.d.ts +49 -0
- package/dist/exec/hooks/registry.js +91 -0
- package/dist/exec/hooks/tool-wrapper.d.ts +94 -0
- package/dist/exec/hooks/tool-wrapper.js +154 -0
- package/dist/exec/hooks/turn.d.ts +61 -0
- package/dist/exec/hooks/turn.js +59 -0
- package/dist/exec/hooks/validate.d.ts +85 -0
- package/dist/exec/hooks/validate.js +310 -0
- package/dist/exec/index.d.ts +130 -4
- package/dist/exec/index.js +501 -10
- package/dist/exec/options.d.ts +124 -2
- package/dist/exec/options.js +413 -6
- package/dist/exec/permission.d.ts +9 -1
- package/dist/exec/permission.js +7 -1
- package/dist/exec/request/limits.d.ts +51 -0
- package/dist/exec/request/limits.js +49 -0
- package/dist/exec/request/scope.d.ts +106 -0
- package/dist/exec/request/scope.js +149 -0
- package/dist/exec/result/limits.d.ts +74 -0
- package/dist/exec/result/limits.js +72 -0
- package/dist/exec/result/prompt.d.ts +28 -0
- package/dist/exec/result/prompt.js +74 -0
- package/dist/exec/result/schema.d.ts +99 -0
- package/dist/exec/result/schema.js +464 -0
- package/dist/exec/result/sink.d.ts +56 -0
- package/dist/exec/result/sink.js +50 -0
- package/dist/exec/result/tool.d.ts +37 -0
- package/dist/exec/result/tool.js +118 -0
- package/dist/exec/runner.d.ts +395 -1
- package/dist/exec/runner.js +860 -8
- package/dist/exec/threads/aggregate.d.ts +34 -0
- package/dist/exec/threads/aggregate.js +30 -0
- package/dist/exec/threads/capacity.d.ts +23 -0
- package/dist/exec/threads/capacity.js +38 -0
- package/dist/exec/threads/dispatch-source.d.ts +60 -0
- package/dist/exec/threads/dispatch-source.js +106 -0
- package/dist/exec/threads/execute-threads.d.ts +53 -0
- package/dist/exec/threads/execute-threads.js +234 -0
- package/dist/exec/threads/gate.d.ts +42 -0
- package/dist/exec/threads/gate.js +81 -0
- package/dist/exec/threads/identity.d.ts +36 -0
- package/dist/exec/threads/identity.js +67 -0
- package/dist/exec/threads/interrupt.d.ts +29 -0
- package/dist/exec/threads/interrupt.js +79 -0
- package/dist/exec/threads/limits.d.ts +58 -0
- package/dist/exec/threads/limits.js +35 -0
- package/dist/exec/threads/outcome.d.ts +47 -0
- package/dist/exec/threads/outcome.js +26 -0
- package/dist/exec/threads/registry.d.ts +81 -0
- package/dist/exec/threads/registry.js +427 -0
- package/dist/exec/threads/runtime.d.ts +107 -0
- package/dist/exec/threads/runtime.js +523 -0
- package/dist/exec/threads/thread-source.d.ts +20 -0
- package/dist/exec/threads/thread-source.js +134 -0
- package/dist/fast/limits.d.ts +54 -0
- package/dist/fast/limits.js +54 -0
- package/dist/fast/summary-call.d.ts +72 -0
- package/dist/fast/summary-call.js +133 -0
- package/dist/fast/summary-prompt.d.ts +106 -0
- package/dist/fast/summary-prompt.js +320 -0
- package/dist/fast/task-summary-types.d.ts +66 -0
- package/dist/fast/task-summary-types.js +17 -0
- package/dist/logging/logger.d.ts +1 -1
- package/dist/proc/limits.d.ts +7 -0
- package/dist/proc/limits.js +7 -0
- package/dist/proc/log-mirror.d.ts +21 -4
- package/dist/proc/log-mirror.js +29 -7
- package/dist/proc/output-streams.d.ts +50 -0
- package/dist/proc/output-streams.js +54 -0
- package/dist/skills/service.d.ts +41 -0
- package/dist/skills/service.js +62 -0
- package/dist/skills/triage.d.ts +194 -0
- package/dist/skills/triage.js +393 -0
- package/dist/team/forced-dispatch.d.ts +95 -0
- package/dist/team/forced-dispatch.js +208 -0
- package/dist/team/limits.d.ts +21 -1
- package/dist/team/limits.js +21 -1
- package/dist/team/normalize.d.ts +15 -0
- package/dist/team/normalize.js +21 -4
- package/dist/team/prompt.d.ts +6 -3
- package/dist/team/prompt.js +9 -5
- package/dist/team/runtime.d.ts +9 -0
- package/dist/team/runtime.js +8 -0
- package/dist/team/subagent.d.ts +15 -0
- package/dist/team/subagent.js +45 -1
- package/dist/team/task-tool.js +11 -7
- package/dist/tools/bash-tool.d.ts +10 -0
- package/dist/tools/bash-tool.js +71 -6
- package/dist/tools/human-input.d.ts +35 -2
- package/dist/tools/human-input.js +38 -0
- package/dist/tools/index.d.ts +93 -1
- package/dist/tools/index.js +112 -3
- package/dist/tools/plan-tools.d.ts +20 -12
- package/dist/tools/plan-tools.js +24 -17
- package/dist/tools/tool-gate.d.ts +100 -0
- package/dist/tools/tool-gate.js +87 -0
- package/dist/ui/App.js +238 -12
- package/dist/ui/Header.d.ts +28 -16
- package/dist/ui/Header.js +21 -19
- package/dist/ui/StatusBar.d.ts +1 -0
- package/dist/ui/StatusBar.js +1 -0
- package/dist/ui/Transcript.js +1 -1
- package/dist/ui/entries/CompactionCard.d.ts +11 -1
- package/dist/ui/entries/CompactionCard.js +65 -4
- package/dist/ui/interaction-hints.js +6 -0
- package/dist/ui/layout/OverlayFrame.d.ts +18 -0
- package/dist/ui/layout/OverlayFrame.js +19 -4
- package/dist/ui/layout/header-hints.d.ts +55 -62
- package/dist/ui/layout/header-hints.js +59 -166
- package/dist/ui/layout/header-left.d.ts +115 -0
- package/dist/ui/layout/header-left.js +206 -0
- package/dist/ui/layout/shortcut-panel-layout.d.ts +191 -0
- package/dist/ui/layout/shortcut-panel-layout.js +321 -0
- package/dist/ui/layout/status-detail-layout.js +5 -1
- package/dist/ui/layout/status-layout.d.ts +10 -0
- package/dist/ui/layout/status-layout.js +18 -1
- package/dist/ui/layout/task-summary-cell.d.ts +61 -0
- package/dist/ui/layout/task-summary-cell.js +65 -0
- package/dist/ui/overlays/HelpOverlay.d.ts +12 -0
- package/dist/ui/overlays/HelpOverlay.js +29 -2
- package/dist/ui/overlays/SettingsScreen.js +29 -5
- package/dist/ui/overlays/ShortcutPanel.d.ts +39 -0
- package/dist/ui/overlays/ShortcutPanel.js +106 -0
- package/dist/ui/overlays/TeamFanoutPage.d.ts +35 -0
- package/dist/ui/overlays/TeamFanoutPage.js +78 -0
- package/dist/ui/overlays/model-profile-state.d.ts +19 -1
- package/dist/ui/overlays/model-profile-state.js +12 -0
- package/dist/ui/overlays/team-fanout-state.d.ts +73 -0
- package/dist/ui/overlays/team-fanout-state.js +97 -0
- package/dist/ui/shortcuts.d.ts +81 -0
- package/dist/ui/shortcuts.js +221 -0
- package/package.json +2 -2
package/dist/agent/reducer.d.ts
CHANGED
|
@@ -15,14 +15,22 @@ import type { AgentEvent, ModelCost, ToolResult, TokenUsage } from '@aragon-agen
|
|
|
15
15
|
import type { AgentMode } from './agent-mode.js';
|
|
16
16
|
import type { DispatchOutcome, SubagentRun, SubagentSpec, TeamSnapshot } from '../team/types.js';
|
|
17
17
|
import type { FastReview, FastSnapshot } from '../fast/types.js';
|
|
18
|
-
import type { CompactionMode, CompactionRecord, CompactionSnapshot, CompactionUiTrigger, ContextUsageSnapshot } from '../compaction/types.js';
|
|
18
|
+
import type { CompactionMode, CompactionPhase, CompactionRecord, CompactionSnapshot, CompactionUiTrigger, ContextUsageSnapshot } from '../compaction/types.js';
|
|
19
19
|
import type { AcceptanceSnapshot, TodoItem, TodoSnapshot } from '../todo/types.js';
|
|
20
20
|
import type { JobKind, ServiceSnapshot, ServiceStatus } from '../proc/types.js';
|
|
21
21
|
import type { RetryPhase } from './retry-view.js';
|
|
22
22
|
import type { FilePatch } from '../tools/patch.js';
|
|
23
|
+
import type { TaskSummaryView } from '../fast/task-summary-types.js';
|
|
23
24
|
export type NoticeLevel = 'info' | 'warn' | 'error';
|
|
24
25
|
export type ToastLevel = NoticeLevel | 'success';
|
|
25
|
-
export type Overlay = null | 'settings' | 'model' | 'help' | 'queue' | 'confirm' | 'question' | 'plan' | 'kit' | 'prompts' | 'prompt-pick' | 'agents'
|
|
26
|
+
export type Overlay = null | 'settings' | 'model' | 'help' | 'queue' | 'confirm' | 'question' | 'plan' | 'kit' | 'prompts' | 'prompt-pick' | 'agents'
|
|
27
|
+
/**
|
|
28
|
+
* tui-shortcut-drawer-and-task-summary §4.5: the keyboard drawer (`Ctrl+G` /
|
|
29
|
+
* `/keys`). A single field, so the drawer and `/help` cannot both hold the
|
|
30
|
+
* keyboard - which is also why `Ctrl+G` TAKES OVER from another overlay instead
|
|
31
|
+
* of being swallowed while one is open (P2-3).
|
|
32
|
+
*/
|
|
33
|
+
| 'shortcuts';
|
|
26
34
|
export type ToolStatus = 'pending' | 'running' | 'done' | 'error';
|
|
27
35
|
/** Ephemeral, auto-dismissed acknowledgement (spec §3.9). */
|
|
28
36
|
export interface Toast {
|
|
@@ -229,6 +237,22 @@ export type Entry = {
|
|
|
229
237
|
messages: number;
|
|
230
238
|
charsRemoved: number;
|
|
231
239
|
};
|
|
240
|
+
/**
|
|
241
|
+
* The stage the LIVE card is in (context-compaction-never-fires C).
|
|
242
|
+
*
|
|
243
|
+
* Absent on a settled card and on every card written before this field
|
|
244
|
+
* existed, which is why the renderer treats it as optional and falls back to
|
|
245
|
+
* the old `summarizing with <model>` line.
|
|
246
|
+
*/
|
|
247
|
+
phase?: CompactionPhase;
|
|
248
|
+
/** Set when the cut relaxed `keepRecentTurns` to exist at all (B). */
|
|
249
|
+
keepRelaxed?: boolean;
|
|
250
|
+
retainedTurns?: number;
|
|
251
|
+
/** Messages the relaxed cut left verbatim - the number the card states. */
|
|
252
|
+
retainedMessages?: number;
|
|
253
|
+
keepRecentTurnsUsed?: number;
|
|
254
|
+
/** Messages the digest left out, so they cannot be quoted (A1). */
|
|
255
|
+
elidedMessages?: number;
|
|
232
256
|
live: boolean;
|
|
233
257
|
} | {
|
|
234
258
|
id: string;
|
|
@@ -391,6 +415,23 @@ export interface ViewState {
|
|
|
391
415
|
* totals. `null` is what leaves an ordinary session's status bar unchanged.
|
|
392
416
|
*/
|
|
393
417
|
compaction: CompactionSnapshot | null;
|
|
418
|
+
/**
|
|
419
|
+
* The session's task label, or `null` while there is none
|
|
420
|
+
* (tui-shortcut-drawer-and-task-summary D-13).
|
|
421
|
+
*
|
|
422
|
+
* PURE VIEW STATE: never persisted, never in the conversation history, never in
|
|
423
|
+
* `config.json`. It lives here because the header and the drawer must read the
|
|
424
|
+
* SAME field - two copies would be two labels for one task.
|
|
425
|
+
*
|
|
426
|
+
* THE TWO WRITERS ARE `taskSummaryPending` / `taskSummaryReady`, and the two
|
|
427
|
+
* CLEARERS are `resetConversation` and `restoreEntries`: clearing is the
|
|
428
|
+
* reducer's job (it is the only place that knows a task ended), while
|
|
429
|
+
* REBUILDING after `/resume` is the App wrapper's job, because only it can see
|
|
430
|
+
* the restored entries before they are reduced.
|
|
431
|
+
*/
|
|
432
|
+
taskSummary: TaskSummaryView | null;
|
|
433
|
+
/** A summary call is in flight. Drives the drawer's `summarizing` line and `/task`. */
|
|
434
|
+
taskSummaryPending: boolean;
|
|
394
435
|
seq: number;
|
|
395
436
|
/** The `kind: 'team'` entry the live dispatch is writing into. */
|
|
396
437
|
teamEntryId?: string;
|
|
@@ -562,6 +603,21 @@ export type ViewAction = {
|
|
|
562
603
|
} | {
|
|
563
604
|
type: 'restoreEntries';
|
|
564
605
|
entries: Entry[];
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* The task label lifecycle (tui-shortcut-drawer-and-task-summary §7.1).
|
|
609
|
+
*
|
|
610
|
+
* TWO ACTIONS, because "a call started" and "a call finished" are different
|
|
611
|
+
* facts and the drawer reports them differently (`summarizing` vs the label).
|
|
612
|
+
* `taskSummaryReady` carries `null` in exactly one case: the call failed AND
|
|
613
|
+
* `taskSummary.fallback` is off, which is a deliberate "show nothing" rather
|
|
614
|
+
* than an empty string that would read as a broken feature.
|
|
615
|
+
*/
|
|
616
|
+
| {
|
|
617
|
+
type: 'taskSummaryPending';
|
|
618
|
+
} | {
|
|
619
|
+
type: 'taskSummaryReady';
|
|
620
|
+
view: TaskSummaryView | null;
|
|
565
621
|
} | {
|
|
566
622
|
type: 'setAgentMode';
|
|
567
623
|
mode: AgentMode;
|
|
@@ -643,6 +699,18 @@ export type ViewAction = {
|
|
|
643
699
|
type: 'compactionEnd';
|
|
644
700
|
record: CompactionRecord;
|
|
645
701
|
}
|
|
702
|
+
/**
|
|
703
|
+
* The live card's stage (context-compaction-never-fires C).
|
|
704
|
+
*
|
|
705
|
+
* Its own action rather than a field on `compactionStart` because the phases
|
|
706
|
+
* arrive AFTER it, one per step, and because a phase must be able to land on a
|
|
707
|
+
* card that a previous attempt already settled into the same entry id.
|
|
708
|
+
*/
|
|
709
|
+
| {
|
|
710
|
+
type: 'compactionPhase';
|
|
711
|
+
index: number;
|
|
712
|
+
phase: CompactionPhase;
|
|
713
|
+
}
|
|
646
714
|
/**
|
|
647
715
|
* Compaction spend.
|
|
648
716
|
*
|
package/dist/agent/reducer.js
CHANGED
|
@@ -67,6 +67,8 @@ export function initialViewState(seed = {}) {
|
|
|
67
67
|
retry: null,
|
|
68
68
|
fast: null,
|
|
69
69
|
compaction: null,
|
|
70
|
+
taskSummary: null,
|
|
71
|
+
taskSummaryPending: false,
|
|
70
72
|
seq: 0,
|
|
71
73
|
teamEntryId: undefined,
|
|
72
74
|
todoEntryId: undefined,
|
|
@@ -906,9 +908,25 @@ export function viewReducer(state, action) {
|
|
|
906
908
|
turnProduced: false,
|
|
907
909
|
errorNoticed: false,
|
|
908
910
|
aborted: false,
|
|
911
|
+
// THE TASK LABEL IS PART OF THE TASK (D-13). `/clear`, `/reset` and a
|
|
912
|
+
// session switch all land here, so the header loses its label without the
|
|
913
|
+
// App needing a second cleanup path. `/clear screen` does NOT come here -
|
|
914
|
+
// it keeps the conversation, so it keeps the label.
|
|
915
|
+
taskSummary: null,
|
|
916
|
+
taskSummaryPending: false,
|
|
909
917
|
};
|
|
910
918
|
case 'setOverlay':
|
|
911
919
|
return { ...state, overlay: action.overlay };
|
|
920
|
+
// --- Task summary (tui-shortcut-drawer-and-task-summary §7.1) ----------
|
|
921
|
+
//
|
|
922
|
+
// TWO FIELDS, ONE DIRECTION: `pending` is a latch the App raises before the
|
|
923
|
+
// call and releases on the result, and `taskSummary` is only ever replaced
|
|
924
|
+
// wholesale. Neither is persisted and neither is derived from `entries`, so a
|
|
925
|
+
// resumed conversation shows nothing until the App rebuilds the label.
|
|
926
|
+
case 'taskSummaryPending':
|
|
927
|
+
return { ...state, taskSummaryPending: true };
|
|
928
|
+
case 'taskSummaryReady':
|
|
929
|
+
return { ...state, taskSummary: action.view, taskSummaryPending: false };
|
|
912
930
|
// Pure mirror write. The App only ever dispatches what
|
|
913
931
|
// `controller.setAgentMode()` reported it ADOPTED, so this reducer has no
|
|
914
932
|
// deferral logic of its own to get out of step with (§3.1 / R-P7).
|
|
@@ -1116,12 +1134,11 @@ export function viewReducer(state, action) {
|
|
|
1116
1134
|
case 'fastTier':
|
|
1117
1135
|
return { ...state, fast: action.snapshot };
|
|
1118
1136
|
// --- Context compaction (context-auto-compaction §5.5) ----------------
|
|
1119
|
-
//
|
|
1120
|
-
//
|
|
1121
|
-
//
|
|
1122
|
-
//
|
|
1123
|
-
//
|
|
1124
|
-
// fired; `/compact status` and the diagnostic log are where the attempts are.
|
|
1137
|
+
// THE TRANSCRIPT NOW CARRIES ONE CARD PER ATTEMPT (context-compaction-never-
|
|
1138
|
+
// fires C). Before this change a declined `pressure` checkpoint dispatched
|
|
1139
|
+
// NOTHING, which is what made "95 % and nothing happens" unreportable: the
|
|
1140
|
+
// feature was trying, failing and saying nothing. The flood the old rule
|
|
1141
|
+
// feared is bounded by `maxPerRun` / `stuckLimit` in `compaction/limits.ts`.
|
|
1125
1142
|
case 'compactionStart': {
|
|
1126
1143
|
const { id, seq } = nextId(state);
|
|
1127
1144
|
let entries = state.entries;
|
|
@@ -1171,6 +1188,7 @@ export function viewReducer(state, action) {
|
|
|
1171
1188
|
tokensAfter: 0,
|
|
1172
1189
|
model: action.model,
|
|
1173
1190
|
startedAt: Date.now(),
|
|
1191
|
+
phase: 'planning',
|
|
1174
1192
|
live: true,
|
|
1175
1193
|
};
|
|
1176
1194
|
return {
|
|
@@ -1199,6 +1217,16 @@ export function viewReducer(state, action) {
|
|
|
1199
1217
|
...(record.tailRelief ? { tailRelief: record.tailRelief } : {}),
|
|
1200
1218
|
...(record.decision ? { decision: record.decision } : {}),
|
|
1201
1219
|
...(record.memoryVersion ? { memoryVersion: record.memoryVersion } : {}),
|
|
1220
|
+
...(record.keepRelaxed ? { keepRelaxed: record.keepRelaxed } : {}),
|
|
1221
|
+
...(record.retainedTurns !== undefined
|
|
1222
|
+
? { retainedTurns: record.retainedTurns } : {}),
|
|
1223
|
+
...(record.retainedMessages !== undefined
|
|
1224
|
+
? { retainedMessages: record.retainedMessages } : {}),
|
|
1225
|
+
...(record.retainedMessages !== undefined
|
|
1226
|
+
? { retainedMessages: record.retainedMessages } : {}),
|
|
1227
|
+
...(record.keepRecentTurnsUsed !== undefined
|
|
1228
|
+
? { keepRecentTurnsUsed: record.keepRecentTurnsUsed } : {}),
|
|
1229
|
+
...(record.elidedMessages ? { elidedMessages: record.elidedMessages } : {}),
|
|
1202
1230
|
model: record.model,
|
|
1203
1231
|
durationMs: record.durationMs,
|
|
1204
1232
|
// SETTLED. `Transcript`'s boundary is monotonic, so a card that
|
|
@@ -1235,12 +1263,30 @@ export function viewReducer(state, action) {
|
|
|
1235
1263
|
...(record.tailRelief ? { tailRelief: record.tailRelief } : {}),
|
|
1236
1264
|
...(record.decision ? { decision: record.decision } : {}),
|
|
1237
1265
|
...(record.memoryVersion ? { memoryVersion: record.memoryVersion } : {}),
|
|
1266
|
+
...(record.keepRelaxed ? { keepRelaxed: record.keepRelaxed } : {}),
|
|
1267
|
+
...(record.retainedTurns !== undefined ? { retainedTurns: record.retainedTurns } : {}),
|
|
1268
|
+
...(record.keepRecentTurnsUsed !== undefined
|
|
1269
|
+
? { keepRecentTurnsUsed: record.keepRecentTurnsUsed } : {}),
|
|
1270
|
+
...(record.elidedMessages ? { elidedMessages: record.elidedMessages } : {}),
|
|
1238
1271
|
model: record.model,
|
|
1239
1272
|
durationMs: record.durationMs,
|
|
1240
1273
|
live: false,
|
|
1241
1274
|
};
|
|
1242
1275
|
return { ...state, seq, ...appendEntry(state, state.entries, entry) };
|
|
1243
1276
|
}
|
|
1277
|
+
case 'compactionPhase': {
|
|
1278
|
+
// THE LIVE CARD'S STAGE, AND NOTHING ELSE. It must not open a card (a phase
|
|
1279
|
+
// can arrive for an entry that a fast settle already closed) and must not
|
|
1280
|
+
// resurrect a settled one: `live` is left untouched, so a late phase on a
|
|
1281
|
+
// settled card changes nothing the renderer shows.
|
|
1282
|
+
if (!state.compactionEntryId)
|
|
1283
|
+
return state;
|
|
1284
|
+
const phase = action.phase;
|
|
1285
|
+
return {
|
|
1286
|
+
...state,
|
|
1287
|
+
entries: mapEntry(state.entries, state.compactionEntryId, (e) => e.kind === 'compaction' && e.live ? { ...e, phase } : e),
|
|
1288
|
+
};
|
|
1289
|
+
}
|
|
1244
1290
|
case 'compactionUsage':
|
|
1245
1291
|
// `usageTotal` AND NOTHING ELSE, exactly as `teamUsage` and `fastUsage`. In
|
|
1246
1292
|
// particular NOT `context`: that gauge shows the LEAD's context
|
|
@@ -1423,6 +1469,13 @@ export function viewReducer(state, action) {
|
|
|
1423
1469
|
// NOT cleared — it is the session's own tier projection, which a
|
|
1424
1470
|
// `/resume` does not change.
|
|
1425
1471
|
fastEntryId: undefined,
|
|
1472
|
+
// `/resume` ADOPTS ANOTHER CONVERSATION, so the previous conversation's
|
|
1473
|
+
// label describes something that is no longer on screen. The reducer only
|
|
1474
|
+
// CLEARS it; the App's `makeCtx().dispatch` wrapper rebuilds one from
|
|
1475
|
+
// `action.entries` (D-13), because it is the only layer that sees the
|
|
1476
|
+
// restored entries BEFORE this branch runs.
|
|
1477
|
+
taskSummary: null,
|
|
1478
|
+
taskSummaryPending: false,
|
|
1426
1479
|
};
|
|
1427
1480
|
}
|
|
1428
1481
|
// --- Background services (§3.10 / D-11) -----------------------------
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `<skill_triage>` system-prompt block (skill-triage-and-unbounded-ask §4.2.3).
|
|
3
|
+
*
|
|
4
|
+
* WHY A PROTOCOL BLOCK AT ALL. The capability this feature fixes already existed:
|
|
5
|
+
* the Level 1 catalog is in every prompt, `skill(name)` loads a body, and
|
|
6
|
+
* `README.md` has claimed since the Skills feature landed that "the model decides
|
|
7
|
+
* on its own whether a task matches a skill". What was missing is any instruction
|
|
8
|
+
* that the decision has to HAPPEN, before the work rather than after it. The
|
|
9
|
+
* catalog's own opening paragraph is a STATEMENT ("if a task matches one, call the
|
|
10
|
+
* skill tool"), not a step in an order of operations, and a statement the model
|
|
11
|
+
* has read forty times is the one it skims.
|
|
12
|
+
*
|
|
13
|
+
* WHY IT IS THIS SHORT. The protocol is paid for on EVERY LLM request: the system
|
|
14
|
+
* prompt is re-sent each time and nothing in this repository uses provider-side
|
|
15
|
+
* prefix caching. An earlier draft carried a 1.9 KB version whose second half
|
|
16
|
+
* repeated the disclosure ladder that `<available_skills>` already states three
|
|
17
|
+
* lines above it. Repeating a rule is not emphasis, it is noise — and noise about
|
|
18
|
+
* a rule teaches the model that these blocks are skimmable. Measured size of the
|
|
19
|
+
* block below is 1273 bytes; `skill-triage-prompt.test.ts` asserts the ceiling of
|
|
20
|
+
* 1500 so an edit has 227 bytes of room, not unlimited scope.
|
|
21
|
+
*
|
|
22
|
+
* ASCII ONLY — `agent/` is inside the glyph scanner's scope.
|
|
23
|
+
*/
|
|
24
|
+
import type { SkillCandidate } from '../skills/triage.js';
|
|
25
|
+
/** Bump when the wording changes, so a transcript can be dated. */
|
|
26
|
+
export declare const SKILL_TRIAGE_BLOCK_VERSION = "v1-2026-10-26";
|
|
27
|
+
export interface SkillTriageBlockOptions {
|
|
28
|
+
/** This turn's candidates, best first. Empty is normal and renders no data block. */
|
|
29
|
+
candidates: SkillCandidate[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Protocol first, candidates second — in that order, always.
|
|
33
|
+
*
|
|
34
|
+
* The order is the meaning: the protocol says what to do, the data block says with
|
|
35
|
+
* what. Reversing them would put a list of suggestions above the rules for reading
|
|
36
|
+
* it, which is how a suggestion turns into an instruction.
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildSkillTriageBlock(options: SkillTriageBlockOptions): string;
|
|
39
|
+
/** Byte size of the protocol half, for the budget assertion in the tests. */
|
|
40
|
+
export declare function skillTriageProtocolBytes(): number;
|
|
41
|
+
/** The ceiling the protocol half must stay under, in bytes. */
|
|
42
|
+
export declare const SKILL_TRIAGE_PROTOCOL_MAX_BYTES: number;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `<skill_triage>` system-prompt block (skill-triage-and-unbounded-ask §4.2.3).
|
|
3
|
+
*
|
|
4
|
+
* WHY A PROTOCOL BLOCK AT ALL. The capability this feature fixes already existed:
|
|
5
|
+
* the Level 1 catalog is in every prompt, `skill(name)` loads a body, and
|
|
6
|
+
* `README.md` has claimed since the Skills feature landed that "the model decides
|
|
7
|
+
* on its own whether a task matches a skill". What was missing is any instruction
|
|
8
|
+
* that the decision has to HAPPEN, before the work rather than after it. The
|
|
9
|
+
* catalog's own opening paragraph is a STATEMENT ("if a task matches one, call the
|
|
10
|
+
* skill tool"), not a step in an order of operations, and a statement the model
|
|
11
|
+
* has read forty times is the one it skims.
|
|
12
|
+
*
|
|
13
|
+
* WHY IT IS THIS SHORT. The protocol is paid for on EVERY LLM request: the system
|
|
14
|
+
* prompt is re-sent each time and nothing in this repository uses provider-side
|
|
15
|
+
* prefix caching. An earlier draft carried a 1.9 KB version whose second half
|
|
16
|
+
* repeated the disclosure ladder that `<available_skills>` already states three
|
|
17
|
+
* lines above it. Repeating a rule is not emphasis, it is noise — and noise about
|
|
18
|
+
* a rule teaches the model that these blocks are skimmable. Measured size of the
|
|
19
|
+
* block below is 1273 bytes; `skill-triage-prompt.test.ts` asserts the ceiling of
|
|
20
|
+
* 1500 so an edit has 227 bytes of room, not unlimited scope.
|
|
21
|
+
*
|
|
22
|
+
* ASCII ONLY — `agent/` is inside the glyph scanner's scope.
|
|
23
|
+
*/
|
|
24
|
+
import { renderSkillCandidates, SKILL_TRIAGE_LIMITS } from '../skills/triage.js';
|
|
25
|
+
/** Bump when the wording changes, so a transcript can be dated. */
|
|
26
|
+
export const SKILL_TRIAGE_BLOCK_VERSION = 'v1-2026-10-26';
|
|
27
|
+
/**
|
|
28
|
+
* The protocol text. Kept as a literal array so a diff of the prompt is a diff of
|
|
29
|
+
* the source, and so the grader/test can see line boundaries.
|
|
30
|
+
*/
|
|
31
|
+
const PROTOCOL_LINES = [
|
|
32
|
+
'<skill_triage>',
|
|
33
|
+
`Version: ${SKILL_TRIAGE_BLOCK_VERSION}`,
|
|
34
|
+
'',
|
|
35
|
+
'Triage every task that touches the workspace: AFTER the project guidance and the',
|
|
36
|
+
'directory listing, BEFORE you plan or change anything. A user-typed /<skill-name>',
|
|
37
|
+
'is an override, not the only way in.',
|
|
38
|
+
'',
|
|
39
|
+
'1. Read <available_skills> above, and <skill_candidates> when present. A candidate',
|
|
40
|
+
' is a computed guess about your message, not a verdict - check its one-line',
|
|
41
|
+
' description before trusting it.',
|
|
42
|
+
'2. If the catalog says some skills were not shown, or nothing listed plainly',
|
|
43
|
+
' covers the task, call skill_find(query) once before concluding there is no',
|
|
44
|
+
' skill.',
|
|
45
|
+
'3. If a skill covers the task, call skill(name="...") BEFORE the first source read',
|
|
46
|
+
' that would change code, then follow it. Say why in one line, not a paragraph.',
|
|
47
|
+
'4. If nothing covers the task, say so in one clause and continue. Do not load a',
|
|
48
|
+
' skill to look diligent, and never load several "to be safe".',
|
|
49
|
+
'',
|
|
50
|
+
'A loaded skill is reference material, not permission to ignore the user, the',
|
|
51
|
+
'plan-mode rules, or the tools you actually have. If a skill narrows your tool set,',
|
|
52
|
+
'that is its allowed-tools declaration working: report it, do not work around it.',
|
|
53
|
+
'Never install or author a skill because a task looks like it needs one; that',
|
|
54
|
+
'decision belongs to the user.',
|
|
55
|
+
'</skill_triage>',
|
|
56
|
+
];
|
|
57
|
+
const PROTOCOL = PROTOCOL_LINES.join('\n');
|
|
58
|
+
/**
|
|
59
|
+
* Protocol first, candidates second — in that order, always.
|
|
60
|
+
*
|
|
61
|
+
* The order is the meaning: the protocol says what to do, the data block says with
|
|
62
|
+
* what. Reversing them would put a list of suggestions above the rules for reading
|
|
63
|
+
* it, which is how a suggestion turns into an instruction.
|
|
64
|
+
*/
|
|
65
|
+
export function buildSkillTriageBlock(options) {
|
|
66
|
+
const candidates = renderSkillCandidates(options.candidates);
|
|
67
|
+
return candidates.length > 0 ? `${PROTOCOL}\n${candidates}` : PROTOCOL;
|
|
68
|
+
}
|
|
69
|
+
/** Byte size of the protocol half, for the budget assertion in the tests. */
|
|
70
|
+
export function skillTriageProtocolBytes() {
|
|
71
|
+
return new TextEncoder().encode(PROTOCOL).length;
|
|
72
|
+
}
|
|
73
|
+
/** The ceiling the protocol half must stay under, in bytes. */
|
|
74
|
+
export const SKILL_TRIAGE_PROTOCOL_MAX_BYTES = SKILL_TRIAGE_LIMITS.maxProtocolBytes;
|
|
@@ -34,8 +34,20 @@ export interface SystemPromptParams {
|
|
|
34
34
|
* plan as its final message instead of calling tools it does not have.
|
|
35
35
|
*/
|
|
36
36
|
planInteractive?: boolean;
|
|
37
|
-
/**
|
|
38
|
-
|
|
37
|
+
/**
|
|
38
|
+
* The rendered `<skill_triage>` block plus (when there are candidates) the
|
|
39
|
+
* `<skill_candidates>` block, or `''`.
|
|
40
|
+
*
|
|
41
|
+
* Spliced conditionally exactly as `skillsBlock` and the plan block are, which
|
|
42
|
+
* is what keeps invariant I-T1 true: `skills.triage: false`, a zero-skill
|
|
43
|
+
* install and `--no-skills` all produce the pre-feature prompt BYTE FOR BYTE.
|
|
44
|
+
*
|
|
45
|
+
* POSITION IS THE SEMANTICS. It goes immediately AFTER `skillsBlock`, because
|
|
46
|
+
* its first instruction refers to `<available_skills> above`, and a block
|
|
47
|
+
* separated from what it points at reads as a dangling reference. It also goes
|
|
48
|
+
* BEFORE the plan block, whose first step defers to it.
|
|
49
|
+
*/
|
|
50
|
+
skillTriageBlock?: string;
|
|
39
51
|
/**
|
|
40
52
|
* The rendered `<team_mode>` block for a LEAD with team mode on, or `''`.
|
|
41
53
|
*
|
|
@@ -114,6 +126,20 @@ export interface SystemPromptParams {
|
|
|
114
126
|
* the child does not have.
|
|
115
127
|
*/
|
|
116
128
|
jobsBlock?: string;
|
|
129
|
+
/**
|
|
130
|
+
* The rendered `<structured_result>` block, or `''`
|
|
131
|
+
* (headless-request-scope-and-typed-result section 2.3.8).
|
|
132
|
+
*
|
|
133
|
+
* Spliced conditionally exactly as every block above is, which is what keeps I-S1
|
|
134
|
+
* true: a run without `--result-schema` produces the pre-feature prompt BYTE FOR
|
|
135
|
+
* BYTE for a fixed tool array.
|
|
136
|
+
*
|
|
137
|
+
* POSITION IS THE SEMANTICS. It goes after every subsystem block and before
|
|
138
|
+
* `## Additional instructions`: it describes the SHAPE OF THE ANSWER, which is
|
|
139
|
+
* closer to the end of the work than any "how to behave" block, while the caller's
|
|
140
|
+
* own appended instructions still come last and still win.
|
|
141
|
+
*/
|
|
142
|
+
structuredResultBlock?: string;
|
|
117
143
|
}
|
|
118
144
|
/** Describe the active shell so the model does not emit incompatible syntax. */
|
|
119
145
|
export declare function describeShell(): {
|
|
@@ -33,17 +33,18 @@ export function buildSystemPrompt(params) {
|
|
|
33
33
|
const skillsBlock = params.skillsBlock ?? '';
|
|
34
34
|
const hasSkills = skillsBlock.length > 0;
|
|
35
35
|
const planBlock = params.agentMode === 'plan'
|
|
36
|
-
? buildPlanModeBlock({
|
|
37
|
-
interactive: params.planInteractive !== false,
|
|
38
|
-
maxAskRounds: params.planMaxAskRounds ?? 4,
|
|
39
|
-
})
|
|
36
|
+
? buildPlanModeBlock({ interactive: params.planInteractive !== false })
|
|
40
37
|
: '';
|
|
38
|
+
// `''` when the caller has no candidates or the feature is off — which is what
|
|
39
|
+
// keeps this block's absence byte-identical to the pre-feature prompt (I-T1).
|
|
40
|
+
const skillTriageBlock = params.skillTriageBlock ?? '';
|
|
41
41
|
const teamBlock = params.teamBlock ?? '';
|
|
42
42
|
const subagentBlock = params.subagentBlock ?? '';
|
|
43
43
|
const todoBlock = params.todoBlock ?? '';
|
|
44
44
|
const fastBlock = params.fastBlock ?? '';
|
|
45
45
|
const backgroundBlock = params.backgroundBlock ?? '';
|
|
46
46
|
const jobsBlock = params.jobsBlock ?? '';
|
|
47
|
+
const structuredResultBlock = params.structuredResultBlock ?? '';
|
|
47
48
|
const appended = (params.appendSystemPrompt ?? '').trim();
|
|
48
49
|
return [
|
|
49
50
|
'You are AragonAgent, an autonomous coding assistant operating inside a terminal (TUI).',
|
|
@@ -60,6 +61,9 @@ export function buildSystemPrompt(params) {
|
|
|
60
61
|
'',
|
|
61
62
|
buildProjectGuidanceBlock(),
|
|
62
63
|
...(hasSkills ? ['', skillsBlock] : []),
|
|
64
|
+
// AFTER <available_skills> (it refers to it as "above") and BEFORE <plan_mode>
|
|
65
|
+
// (whose step 1 defers to it). Conditional like every other optional block.
|
|
66
|
+
...(skillTriageBlock ? ['', skillTriageBlock] : []),
|
|
63
67
|
...(planBlock ? ['', planBlock] : []),
|
|
64
68
|
...(teamBlock ? ['', teamBlock] : []),
|
|
65
69
|
...(subagentBlock ? ['', subagentBlock] : []),
|
|
@@ -67,6 +71,10 @@ export function buildSystemPrompt(params) {
|
|
|
67
71
|
...(fastBlock ? ['', fastBlock] : []),
|
|
68
72
|
...(backgroundBlock ? ['', backgroundBlock] : []),
|
|
69
73
|
...(jobsBlock ? ['', jobsBlock] : []),
|
|
74
|
+
// AFTER every subsystem block, BEFORE the caller's own instructions: it describes
|
|
75
|
+
// the shape of the answer, which is the last thing to know before answering, while
|
|
76
|
+
// `## Additional instructions` still has the final word (section 2.3.8).
|
|
77
|
+
...(structuredResultBlock ? ['', structuredResultBlock] : []),
|
|
70
78
|
'',
|
|
71
79
|
'Operating guidance:',
|
|
72
80
|
'- Prefer reading files and inspecting the workspace before making changes.',
|