@iowarp/clio-coder 0.3.3 → 0.3.4
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 +39 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +3 -3
- package/dist/{acp-P2AQILE2.js → acp-S5R4RR5B.js} +7 -6
- package/dist/{agents-72W3BI7I.js → agents-P6DMMVZY.js} +24 -21
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-5TWEIYDN.js → auth-2XCZLPKS.js} +12 -8
- package/dist/{chunk-GGXXDWE4.js → chunk-22NAGB7X.js} +2 -2
- package/dist/{chunk-2DJ2KNFG.js → chunk-2LZI5CAG.js} +133 -13
- package/dist/{chunk-OAO4GE4M.js → chunk-2TZWSW76.js} +2 -2
- package/dist/{chunk-OOJYHWRB.js → chunk-34475P3I.js} +2 -2
- package/dist/{chunk-4XUGQOHA.js → chunk-35MKKU5R.js} +4 -4
- package/dist/{chunk-LM5TQCJZ.js → chunk-3HZ5RWN2.js} +5 -5
- package/dist/{chunk-AGYYIBLL.js → chunk-3JLKSKD7.js} +2 -2
- package/dist/{chunk-KZWTDYJF.js → chunk-4JUF2NNX.js} +7 -7
- package/dist/{chunk-ZDOOVTXZ.js → chunk-4OC57DA6.js} +27 -4
- package/dist/chunk-5M54SPOL.js +926 -0
- package/dist/{chunk-STBPMHSX.js → chunk-7RXG6QRZ.js} +51 -11
- package/dist/{chunk-X6IAEBZR.js → chunk-A2GZF7DC.js} +5 -5
- package/dist/{chunk-A3CYT5EX.js → chunk-AD2SYQYC.js} +55 -2
- package/dist/chunk-AOCYTWAV.js +449 -0
- package/dist/chunk-BEY543CS.js +258 -0
- package/dist/{chunk-6N5PTWMY.js → chunk-BP4OYD6A.js} +32 -13
- package/dist/chunk-BPGS2WCQ.js +612 -0
- package/dist/{chunk-V6RTAOC2.js → chunk-BRXQQJFP.js} +8 -8
- package/dist/chunk-CFGTUFWB.js +67 -0
- package/dist/{chunk-CBCAPZAA.js → chunk-E25LMLRW.js} +2 -2
- package/dist/{chunk-DUYJ5IO6.js → chunk-EDRHSCIE.js} +4 -4
- package/dist/{chunk-XBXAASKX.js → chunk-EFADSJET.js} +2 -2
- package/dist/{chunk-M6SHUN7Q.js → chunk-FO5ZOVUY.js} +2 -2
- package/dist/chunk-FYYLNIL5.js +313 -0
- package/dist/{chunk-FNTMWMX5.js → chunk-HV5X7OR2.js} +14 -12
- package/dist/{chunk-TZTZS7QK.js → chunk-HXG4IURW.js} +5 -3
- package/dist/{chunk-5UFT4SUX.js → chunk-K6WL7QZT.js} +3 -3
- package/dist/chunk-K7VKOLQQ.js +15 -0
- package/dist/{chunk-BMEMKKIT.js → chunk-KOHPCX4K.js} +2 -2
- package/dist/{chunk-OC7FIQPC.js → chunk-KRPY7NTG.js} +10 -7
- package/dist/chunk-LL4KHSZI.js +22 -0
- package/dist/{chunk-DSELYM6W.js → chunk-MEQ45TQ4.js} +15 -9
- package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
- package/dist/{chunk-6SGHMWE3.js → chunk-N4CZJQRK.js} +5 -5
- package/dist/{chunk-TZK7PACC.js → chunk-NILBFAPG.js} +14 -8
- package/dist/chunk-OZNBF4L3.js +23 -0
- package/dist/{verify-375KUB3Y.js → chunk-PCZJO5TI.js} +127 -42
- package/dist/chunk-QQK64KLB.js +1360 -0
- package/dist/{chunk-SRDMMSEP.js → chunk-QQL5RT5M.js} +979 -1619
- package/dist/{chunk-LZSJBIVT.js → chunk-QWU7ZBO7.js} +70 -720
- package/dist/{chunk-2TLUCQVG.js → chunk-RD5U66HV.js} +3 -3
- package/dist/{chunk-OKGUZO2U.js → chunk-SPULKLCF.js} +4 -3
- package/dist/{chunk-OQ33BKR3.js → chunk-TTNYS3EA.js} +3 -60
- package/dist/chunk-TW3WDMVS.js +677 -0
- package/dist/chunk-TZSKNMZG.js +434 -0
- package/dist/{chunk-7MNJORFF.js → chunk-UL3WSD3F.js} +6 -1
- package/dist/{chunk-PIWWS5BL.js → chunk-UZHIZC5S.js} +7 -7
- package/dist/{chunk-UFIIWP2H.js → chunk-VAWWTKDP.js} +8 -8
- package/dist/{chunk-COU2UHX6.js → chunk-VEZEGCGW.js} +170 -2
- package/dist/{chunk-LW6DSM3M.js → chunk-VMNQ6OZA.js} +98 -202
- package/dist/chunk-VSNATDE6.js +122 -0
- package/dist/chunk-W6GROXXM.js +69 -0
- package/dist/chunk-WPQLXFOZ.js +375 -0
- package/dist/{chunk-ORBHGJC5.js → chunk-WR67VIZY.js} +3 -3
- package/dist/{chunk-PAJK6MAQ.js → chunk-X6COSD2O.js} +5 -5
- package/dist/chunk-ZGVHUX3M.js +66 -0
- package/dist/{chunk-LWLEKMDQ.js → chunk-ZYKPLLNQ.js} +510 -547
- package/dist/cli/index.js +27 -23
- package/dist/{clio-JOU4FXVA.js → clio-J5JIOIDS.js} +7 -6
- package/dist/{code-nav-7AX6FYE6.js → code-nav-AXCXSBHX.js} +5 -3
- package/dist/{config-XCDVKR23.js → config-OEBMIN2U.js} +37 -27
- package/dist/{configure-4GAP54ZW.js → configure-PUQOSIXQ.js} +16 -13
- package/dist/{context-5VKGUVJJ.js → context-EKDCKUUZ.js} +82 -7
- package/dist/{context-4UOGGLQ5.js → context-MGSE4Z2T.js} +33 -23
- package/dist/{context-77FM5DV5.js → context-URSXPBCK.js} +17 -9
- package/dist/{context-clear-XXJRLCJJ.js → context-clear-KDAJRNUK.js} +33 -23
- package/dist/context-working-set-SBKMPPI2.js +1552 -0
- package/dist/{dispatch-runner-QPRDDBDX.js → dispatch-runner-MSWN72NK.js} +43 -29
- package/dist/{doctor-HR46URBJ.js → doctor-7BSE27PJ.js} +10 -10
- package/dist/{eval-XSSNATB4.js → eval-IZGDOO4H.js} +9 -8
- package/dist/{evidence-6HG2PY2B.js → evidence-SR7WXB5B.js} +51 -23
- package/dist/{evolve-K7YU3NCY.js → evolve-K7VE2CBX.js} +30 -20
- package/dist/{fleet-VY3HHKN6.js → fleet-7XMJNQNF.js} +48 -38
- package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-AQNAH644.js} +3 -3
- package/dist/{init-JYGXI3FK.js → init-JGNPAYXT.js} +41 -31
- package/dist/{memory-WFZMGYHX.js → memory-4ALKDJ4Q.js} +32 -22
- package/dist/{models-I5QWSEOM.js → models-ZMMLFJNN.js} +22 -19
- package/dist/{monitor-GE4ID3IA.js → monitor-2F3T5KHP.js} +55 -43
- package/dist/{orchestrator-EM5MC3HM.js → orchestrator-ORHT43JB.js} +572 -388
- package/dist/{reset-L2FQEE3E.js → reset-NXGTYNUO.js} +4 -3
- package/dist/{run-ZU3QMZPZ.js → run-RF4WJGMT.js} +51 -41
- package/dist/{share-S5BZQC5I.js → share-UT3W6E4M.js} +5 -4
- package/dist/{skills-X5VXCRNQ.js → skills-PSACKC5Q.js} +2 -2
- package/dist/{skills-eval-WKIHWTHR.js → skills-eval-WJSI55RZ.js} +34 -24
- package/dist/{targets-SNCPI2NR.js → targets-PIIRAOYS.js} +23 -20
- package/dist/{terminal-lease-BNAHVHBS.js → terminal-lease-ULWXWNVY.js} +4 -3
- package/dist/{upgrade-JQHHPQ4K.js → upgrade-346TZ6AV.js} +18 -17
- package/dist/{usage-OR4O5SMZ.js → usage-6KKXR32N.js} +34 -24
- package/dist/verifiers-4UUM6TEE.js +1214 -0
- package/dist/verify-X5HDROLA.js +25 -0
- package/dist/{wiki-generate-UEXP2ARI.js → wiki-generate-7STOCIFZ.js} +42 -31
- package/dist/worker/entry.js +33 -24
- package/docs/README.md +7 -6
- package/docs/acp.md +1 -1
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-versions.md +1 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +53 -21
- package/docs/config-knobs-audit.md +1 -2
- package/docs/configuration-and-targets.md +15 -1
- package/docs/context-engine.md +64 -12
- package/docs/context-working-set.md +194 -0
- package/docs/development-pipeline.md +1 -1
- package/docs/documentation-coverage.md +5 -5
- package/docs/documentation-guide.md +6 -5
- package/docs/environment-variables.md +2 -1
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +14 -1
- package/docs/evidence-and-memory.md +74 -2
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +2 -2
- package/docs/fleet-dispatch.md +22 -7
- package/docs/glossary.md +21 -1
- package/docs/installation-and-lifecycle.md +2 -2
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +7 -9
- package/docs/observability.md +4 -4
- package/docs/proactive-memory.md +1 -1
- package/docs/prompt-envelope-and-tools.md +4 -4
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +31 -31
- package/docs/safety-model.md +23 -4
- package/docs/scientific-validation.md +21 -3
- package/docs/session-lifecycle.md +3 -3
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +79 -12
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +11 -1
- package/package.json +8 -11
- package/skills/meta/clio-test/SKILL.md +20 -17
- package/skills/meta/clio-test/evals.md +3 -3
- package/skills/meta/clio-test/references/harness.md +35 -6
- package/skills/meta/clio-test/references/test-map.md +20 -10
- package/skills/registry.yaml +2 -2
- package/skills/skill-marketplace.json +1 -1
- package/src/cli/context-working-set.ts +513 -0
- package/src/cli/context.ts +8 -0
- package/src/cli/evidence.ts +20 -2
- package/src/cli/index.ts +4 -0
- package/src/cli/verifiers.ts +325 -0
- package/src/core/bash-exec.ts +39 -14
- package/src/core/bus-events.ts +19 -4
- package/src/core/config.ts +54 -0
- package/src/core/defaults.ts +50 -3
- package/src/core/verification-scripts.ts +6 -0
- package/src/domains/agents/builtins/verifier.md +3 -0
- package/src/domains/config/classify.ts +1 -0
- package/src/domains/context/working-set/contract.ts +161 -0
- package/src/domains/context/working-set/defaults.ts +28 -0
- package/src/domains/context/working-set/engine.ts +203 -0
- package/src/domains/context/working-set/fold.ts +62 -0
- package/src/domains/context/working-set/horizon.ts +38 -0
- package/src/domains/context/working-set/marker.ts +103 -0
- package/src/domains/context/working-set/path-index.ts +436 -0
- package/src/domains/context/working-set/payload.ts +152 -0
- package/src/domains/context/working-set/policies/age-horizon.ts +55 -0
- package/src/domains/context/working-set/policies/index.ts +21 -0
- package/src/domains/context/working-set/policies/structural.ts +160 -0
- package/src/domains/context/working-set/project.ts +132 -0
- package/src/domains/context/working-set/protect.ts +109 -0
- package/src/domains/context/working-set/recall.ts +177 -0
- package/src/domains/context/working-set/replay/controls.ts +112 -0
- package/src/domains/context/working-set/replay/load-clio.ts +199 -0
- package/src/domains/context/working-set/replay/metrics.ts +185 -0
- package/src/domains/context/working-set/replay/reference-graph.ts +79 -0
- package/src/domains/context/working-set/replay/report.ts +139 -0
- package/src/domains/context/working-set/replay/runner.ts +325 -0
- package/src/domains/context/working-set/replay/synthetic.ts +422 -0
- package/src/domains/context/working-set/replay/trace.ts +21 -0
- package/src/domains/context/working-set/visible.ts +54 -0
- package/src/domains/evidence/build.ts +112 -45
- package/src/domains/evidence/eval.ts +24 -7
- package/src/domains/evidence/index.ts +53 -0
- package/src/domains/evidence/ordering.ts +12 -0
- package/src/domains/evidence/run-trust.ts +221 -0
- package/src/domains/evidence/store.ts +46 -6
- package/src/domains/evidence/trust-status.ts +854 -0
- package/src/domains/evidence/types.ts +26 -0
- package/src/domains/middleware/memory-intervention.ts +3 -0
- package/src/domains/middleware/stalled-turn.ts +165 -4
- package/src/domains/safety/autonomy.ts +1 -1
- package/src/domains/safety/default-path-policy.ts +8 -0
- package/src/domains/safety/finish-contract.ts +4 -3
- package/src/domains/safety/policy-engine.ts +48 -6
- package/src/domains/session/compaction/compact.ts +23 -1
- package/src/domains/session/compaction/cut-point.ts +2 -0
- package/src/domains/session/compaction/tokens.ts +16 -1
- package/src/domains/session/context-ledger.ts +2 -0
- package/src/domains/session/entries.ts +107 -1
- package/src/domains/session/manager.ts +9 -2
- package/src/domains/session/migrations/index.ts +22 -3
- package/src/engine/acp/server.ts +3 -0
- package/src/engine/agent.ts +18 -1
- package/src/engine/session.ts +9 -3
- package/src/entry/orchestrator.ts +16 -4
- package/src/interactive/chat-loop-messages.ts +18 -6
- package/src/interactive/chat-panel.ts +17 -1
- package/src/interactive/chat-renderer.ts +30 -21
- package/src/interactive/context-meter.ts +10 -0
- package/src/interactive/context-overlay.ts +81 -6
- package/src/interactive/context-recall-command.ts +110 -0
- package/src/interactive/interactive-slash-runtime.ts +37 -1
- package/src/interactive/model-session-replay.ts +21 -0
- package/src/interactive/overlay-general-openers.ts +6 -0
- package/src/interactive/overlay-session-lifecycle.ts +8 -4
- package/src/interactive/renderers/tool-execution.ts +18 -2
- package/src/interactive/session-transcript.ts +2 -2
- package/src/interactive/slash-commands.ts +29 -2
- package/src/interactive/turn-context.ts +238 -88
- package/src/interactive/turn-middleware.ts +6 -6
- package/src/tools/agent-tools.ts +11 -4
- package/src/tools/bash.ts +144 -82
- package/src/tools/builtin-tool-catalog.ts +11 -5
- package/src/tools/context/index.ts +105 -3
- package/src/tools/context/surface.ts +3 -2
- package/src/tools/core-bootstrap.ts +21 -0
- package/src/tools/dispatch-runner.ts +9 -7
- package/src/tools/monitor.ts +28 -20
- package/src/tools/registry.ts +59 -7
- package/src/tools/result-disposition.ts +550 -0
- package/src/tools/result-shaping.ts +262 -19
- package/src/tools/safe-exec.ts +2 -0
- package/src/tools/verify/authoring.ts +1119 -0
- package/src/tools/verify/catalog.ts +346 -0
- package/src/tools/verify/index.ts +13 -3
- package/src/tools/verify/scripts.ts +135 -37
- package/src/tools/verify/surface.ts +9 -5
- package/src/tools/worker-evidence.ts +35 -12
- package/dist/chunk-J7CWMCQD.js +0 -255
- package/dist/chunk-T6YILFSB.js +0 -80
- package/dist/chunk-VAKQQHWR.js +0 -434
- package/dist/chunk-VPAYEGVX.js +0 -184
|
@@ -10,11 +10,16 @@ import {
|
|
|
10
10
|
BusChannels,
|
|
11
11
|
type ContextActivityStatus,
|
|
12
12
|
type ContextPrunedPayload,
|
|
13
|
+
type ContextRecalledPayload,
|
|
13
14
|
type ContextWarningPayload,
|
|
14
15
|
} from "../core/bus-events.js";
|
|
15
16
|
import type { ClioSettings } from "../core/config.js";
|
|
16
17
|
import type { SafeEventBus } from "../core/event-bus.js";
|
|
17
18
|
import type { ToolName } from "../core/tool-names.js";
|
|
19
|
+
import { buildEvictionFields, planEviction } from "../domains/context/working-set/engine.js";
|
|
20
|
+
import { foldWorkingSet } from "../domains/context/working-set/fold.js";
|
|
21
|
+
import { resolveWorkingSetPolicy } from "../domains/context/working-set/policies/index.js";
|
|
22
|
+
import { selectVisibleEntries } from "../domains/context/working-set/visible.js";
|
|
18
23
|
import type { ObservabilityContract } from "../domains/observability/contract.js";
|
|
19
24
|
import type { CompiledSessionPrompt, SessionPromptInputs } from "../domains/prompts/compiler.js";
|
|
20
25
|
import type { PromptsContract } from "../domains/prompts/contract.js";
|
|
@@ -27,6 +32,7 @@ import {
|
|
|
27
32
|
} from "../domains/session/compaction/auto.js";
|
|
28
33
|
import type { CompactResult } from "../domains/session/compaction/compact.js";
|
|
29
34
|
import { maskStaleObservations } from "../domains/session/compaction/mask-observations.js";
|
|
35
|
+
import { estimateTokens } from "../domains/session/compaction/tokens.js";
|
|
30
36
|
import {
|
|
31
37
|
appendContextSnapshot,
|
|
32
38
|
type CaptureContextSnapshotInput,
|
|
@@ -57,7 +63,7 @@ import {
|
|
|
57
63
|
sumRunUsage,
|
|
58
64
|
toolNamesFromAgentState,
|
|
59
65
|
} from "./chat-loop-messages.js";
|
|
60
|
-
import {
|
|
66
|
+
import { buildModelReplayAgentMessagesFromTurns } from "./model-session-replay.js";
|
|
61
67
|
import { renderCompactionSummaryLine } from "./renderers/compaction-summary.js";
|
|
62
68
|
import type { TurnMiddleware } from "./turn-middleware.js";
|
|
63
69
|
import type { AgentRuntime, ChatTurnState } from "./turn-state.js";
|
|
@@ -73,6 +79,8 @@ export interface TurnContextDeps {
|
|
|
73
79
|
bus?: SafeEventBus | undefined;
|
|
74
80
|
readSessionEntries?: (() => ReadonlyArray<SessionEntry>) | undefined;
|
|
75
81
|
autoCompact?: ((instructions?: string, trigger?: CompactionTrigger) => Promise<CompactResult | null>) | undefined;
|
|
82
|
+
/** Test seam for the eviction planner; production uses `planEviction` from the working-set engine. */
|
|
83
|
+
planEviction?: typeof planEviction;
|
|
76
84
|
getMemorySection?: (() => string) | undefined;
|
|
77
85
|
middleware: TurnMiddleware;
|
|
78
86
|
emitNotice: (text: string) => void;
|
|
@@ -159,6 +167,11 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
159
167
|
let sessionPromptKey: string | null = null;
|
|
160
168
|
const sessionWorkingContextPaths = new Set<string>();
|
|
161
169
|
let pendingPromptLogEntry: SessionPromptCompileRecord | null = null;
|
|
170
|
+
// A post-tool guard can run after every tool result in one model turn. Once
|
|
171
|
+
// both automatic stages report that they have nothing to do, remember that
|
|
172
|
+
// stable user-turn id so the remaining results do not repeat the same plan
|
|
173
|
+
// and summary probes. A new submitted user turn gets a new id naturally.
|
|
174
|
+
let emptyAutoCompactTurnId: string | null = null;
|
|
162
175
|
|
|
163
176
|
// Cache-disturbance honesty (T3.3). Dispatch traffic and history
|
|
164
177
|
// compaction invalidate a single-slot local backend's prefix cache.
|
|
@@ -167,20 +180,41 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
167
180
|
// its first assistant entry, and shows one dim notice.
|
|
168
181
|
const pendingColdReasons = new Set<string>();
|
|
169
182
|
let runExpectedColdReasons: string[] = [];
|
|
170
|
-
let
|
|
183
|
+
let nextAssistantColdReasons: string[] = [];
|
|
184
|
+
// A working-set eviction changes the prefix itself, so it cools every
|
|
185
|
+
// tier's cache, not only a single-slot local one. Dispatch and compaction
|
|
186
|
+
// disturbances keep the local-native gate below.
|
|
187
|
+
const TIER_INDEPENDENT_COLD_REASONS: ReadonlySet<string> = new Set(["working_set_evict"]);
|
|
188
|
+
const stampsOnTier = (reason: string, runtimeId: string | undefined): boolean =>
|
|
189
|
+
TIER_INDEPENDENT_COLD_REASONS.has(reason) ||
|
|
190
|
+
(runtimeId !== undefined && deps.providers.getRuntime(runtimeId)?.tier === "local-native");
|
|
191
|
+
const noteColdReason = (reason: string): void => {
|
|
192
|
+
if (!state.streaming) {
|
|
193
|
+
pendingColdReasons.add(reason);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (!stampsOnTier(reason, state.runtime?.runtimeId)) return;
|
|
197
|
+
if (!runExpectedColdReasons.includes(reason)) runExpectedColdReasons.push(reason);
|
|
198
|
+
if (nextAssistantColdReasons.includes(reason)) return;
|
|
199
|
+
nextAssistantColdReasons.push(reason);
|
|
200
|
+
deps.emitNotice(`[context engine] backend prefix cache likely cold this turn: ${reason}`);
|
|
201
|
+
};
|
|
171
202
|
const unsubscribeColdReasonSources = [
|
|
172
203
|
...[BusChannels.DispatchStarted, BusChannels.DispatchCompleted, BusChannels.DispatchFailed].map(
|
|
173
204
|
(channel) =>
|
|
174
205
|
deps.bus?.on(channel, () => {
|
|
175
|
-
|
|
206
|
+
noteColdReason("dispatch");
|
|
176
207
|
}) ?? null,
|
|
177
208
|
),
|
|
178
209
|
...[BusChannels.CompactionBegin, BusChannels.CompactionEnd].map(
|
|
179
210
|
(channel) =>
|
|
180
211
|
deps.bus?.on(channel, () => {
|
|
181
|
-
|
|
212
|
+
noteColdReason("compaction");
|
|
182
213
|
}) ?? null,
|
|
183
214
|
),
|
|
215
|
+
deps.bus?.on(BusChannels.ContextRecalled, (payload: ContextRecalledPayload) => {
|
|
216
|
+
middleware.fireCompactionHook("working_set_recall", payload.trigger);
|
|
217
|
+
}) ?? null,
|
|
184
218
|
];
|
|
185
219
|
|
|
186
220
|
/**
|
|
@@ -292,7 +326,7 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
292
326
|
|
|
293
327
|
const refreshAgentMessagesFromSession = (agentRuntime: AgentRuntime): ReadonlyArray<SessionEntry> => {
|
|
294
328
|
const refreshedEntries = deps.readSessionEntries?.() ?? [];
|
|
295
|
-
agentRuntime.agent.state.messages =
|
|
329
|
+
agentRuntime.agent.state.messages = buildModelReplayAgentMessagesFromTurns(refreshedEntries, {
|
|
296
330
|
...(state.lastTurnId ? { activeLeafTurnId: state.lastTurnId } : {}),
|
|
297
331
|
});
|
|
298
332
|
state.replayedContextMessages = [];
|
|
@@ -339,12 +373,12 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
339
373
|
|
|
340
374
|
/**
|
|
341
375
|
* Two-mechanism context protection. When pressure crosses the single
|
|
342
|
-
* threshold, first
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
376
|
+
* threshold, first apply a non-destructive working-set eviction. If pressure
|
|
377
|
+
* stays above the threshold, delegate to the pi-style LLM compaction path:
|
|
378
|
+
* append a compaction summary entry, then replay from the session view. The
|
|
379
|
+
* destructive observation mask remains only as a one-release escape hatch.
|
|
346
380
|
*
|
|
347
|
-
* `force = true` skips the pressure check and
|
|
381
|
+
* `force = true` skips the pressure check and every pre-stage and runs
|
|
348
382
|
* the LLM summary directly. Used for `/context compact`, CLIO_CODER_FORCE_COMPACT=1,
|
|
349
383
|
* and overflow recovery.
|
|
350
384
|
*/
|
|
@@ -355,11 +389,17 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
355
389
|
triggerOverride?: CompactionTrigger,
|
|
356
390
|
pendingUserText?: string,
|
|
357
391
|
): Promise<boolean> => {
|
|
358
|
-
if (!deps.
|
|
392
|
+
if (!deps.readSessionEntries) return false;
|
|
393
|
+
const activeAutoTurnId = force ? null : state.activeUserTurnId;
|
|
394
|
+
if (activeAutoTurnId && emptyAutoCompactTurnId === activeAutoTurnId) return false;
|
|
359
395
|
const settings = deps.getSettings();
|
|
360
396
|
const cfg = settings.compaction;
|
|
361
397
|
const autoEnabled = cfg?.auto !== false;
|
|
362
398
|
if (!force && !autoEnabled) return false;
|
|
399
|
+
let preSummaryStageActed = false;
|
|
400
|
+
const rememberEmptyAutomaticAttempt = (): void => {
|
|
401
|
+
if (!force && !preSummaryStageActed && activeAutoTurnId) emptyAutoCompactTurnId = activeAutoTurnId;
|
|
402
|
+
};
|
|
363
403
|
|
|
364
404
|
const compactionThreshold = cfg?.threshold ?? DEFAULT_COMPACTION_THRESHOLD;
|
|
365
405
|
const trigger: CompactionTrigger = triggerOverride ?? (force ? "force" : "auto");
|
|
@@ -369,91 +409,198 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
369
409
|
const verdict = shouldCompact(estimate.tokens, compactionThreshold, estimate.contextWindow);
|
|
370
410
|
if (!verdict.shouldCompact) return false;
|
|
371
411
|
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
// CompactionBegin/End subscription explains the next cold turn.
|
|
412
|
+
// One-release compatibility escape hatch. This is the destructive
|
|
413
|
+
// pre-stage that working-set eviction replaces; keep it byte-for-byte
|
|
414
|
+
// reachable only when explicitly requested.
|
|
376
415
|
if (deps.session?.current()) {
|
|
377
416
|
const beforeSnapshotId = currentContextSnapshot?.snapshotId ?? null;
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
masked.
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
417
|
+
if (process.env.CLIO_CODER_LEGACY_MASK === "1") {
|
|
418
|
+
let masked: ReturnType<typeof maskStaleObservations>;
|
|
419
|
+
try {
|
|
420
|
+
masked = maskStaleObservations(deps.readSessionEntries() ?? [], cfg?.excludeLastTurns ?? 6);
|
|
421
|
+
} catch (error) {
|
|
422
|
+
middleware.fireCompactionHook("mask_observations", trigger, estimate.tokens);
|
|
423
|
+
deps.bus?.emit(BusChannels.CompactionBegin, { trigger, at: Date.now() });
|
|
424
|
+
emitCompactionActivity("started", "compacting context (mask stage)");
|
|
425
|
+
emitCompactionActivity("failed", compactionFailureMessage(error));
|
|
426
|
+
deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
|
|
427
|
+
throw error;
|
|
428
|
+
}
|
|
429
|
+
if (masked.changed) {
|
|
430
|
+
preSummaryStageActed = true;
|
|
431
|
+
middleware.fireCompactionHook("mask_observations", trigger, estimate.tokens);
|
|
432
|
+
deps.bus?.emit(BusChannels.CompactionBegin, { trigger, at: Date.now() });
|
|
433
|
+
emitCompactionActivity("started", "compacting context (mask stage)");
|
|
434
|
+
deps.session.replaceEntries(masked.entries);
|
|
435
|
+
refreshAgentMessagesFromSession(agentRuntime);
|
|
436
|
+
deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
|
|
437
|
+
|
|
438
|
+
const postMaskSnapshot = captureRuntimeContextSnapshot(
|
|
439
|
+
agentRuntime,
|
|
440
|
+
state.activeUserTurnId || "compaction",
|
|
441
|
+
compactionThreshold,
|
|
442
|
+
);
|
|
443
|
+
currentContextSnapshot = postMaskSnapshot;
|
|
444
|
+
persistContextSnapshot(postMaskSnapshot);
|
|
445
|
+
|
|
446
|
+
const tokensAfterMask = snapshotInputTokens(postMaskSnapshot);
|
|
447
|
+
lastCompactionEvent = {
|
|
448
|
+
stage: "mask_observations",
|
|
449
|
+
tokensBefore: estimate.tokens,
|
|
450
|
+
tokensAfter: tokensAfterMask,
|
|
451
|
+
trigger,
|
|
452
|
+
};
|
|
453
|
+
deps.bus?.emit(BusChannels.ContextPruned, {
|
|
454
|
+
stage: "mask_observations",
|
|
455
|
+
pressure: verdict.pressure,
|
|
456
|
+
tokensBefore: estimate.tokens,
|
|
457
|
+
tokensAfter: tokensAfterMask,
|
|
458
|
+
maskedObservations: masked.maskedObservations,
|
|
459
|
+
maskedThinkingBlocks: masked.maskedThinkingBlocks,
|
|
460
|
+
maskedThinkingChars: masked.maskedThinkingChars,
|
|
461
|
+
trigger,
|
|
462
|
+
snapshotIdBefore: beforeSnapshotId,
|
|
463
|
+
snapshotIdAfter: postMaskSnapshot.snapshotId,
|
|
464
|
+
at: Date.now(),
|
|
465
|
+
} satisfies ContextPrunedPayload);
|
|
466
|
+
emitCompactionActivity("completed", `${masked.maskedObservations} observations masked`);
|
|
467
|
+
const thinkingNote =
|
|
468
|
+
masked.maskedThinkingBlocks > 0
|
|
469
|
+
? `, ${masked.maskedThinkingBlocks} thinking blocks dropped (~${masked.maskedThinkingChars} chars)`
|
|
470
|
+
: "";
|
|
471
|
+
deps.emitNotice(
|
|
472
|
+
`[context engine] mask_observations: ${masked.maskedObservations} observations masked${thinkingNote}; ~${estimate.tokens} tokens -> ~${tokensAfterMask} tokens`,
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
const after = liveContextEstimate(agentRuntime, pendingUserText);
|
|
476
|
+
if (!shouldCompact(after.tokens, compactionThreshold, after.contextWindow).shouldCompact) return true;
|
|
477
|
+
}
|
|
478
|
+
} else if (settings.context.workingSet.enabled) {
|
|
479
|
+
let planned: ReturnType<typeof planEviction>;
|
|
480
|
+
try {
|
|
481
|
+
const entries = deps.readSessionEntries() ?? [];
|
|
482
|
+
const view = foldWorkingSet(entries, state.lastTurnId ?? undefined);
|
|
483
|
+
const policy = resolveWorkingSetPolicy(settings.context.workingSet.policy);
|
|
484
|
+
planned = (deps.planEviction ?? planEviction)(policy, {
|
|
485
|
+
entries: selectVisibleEntries(entries, state.lastTurnId ?? undefined),
|
|
486
|
+
view,
|
|
487
|
+
cwd: deps.session.current()?.cwd ?? null,
|
|
488
|
+
settings: settings.context.workingSet,
|
|
489
|
+
pressure: {
|
|
490
|
+
tokens: estimate.tokens,
|
|
491
|
+
contextWindow: estimate.contextWindow,
|
|
492
|
+
threshold: compactionThreshold,
|
|
493
|
+
target: settings.context.workingSet.target,
|
|
494
|
+
},
|
|
495
|
+
estimateTokens,
|
|
496
|
+
});
|
|
497
|
+
} catch (error) {
|
|
498
|
+
middleware.fireCompactionHook("working_set_evict", "pressure", estimate.tokens);
|
|
499
|
+
emitCompactionActivity("started", "compacting context (working-set eviction)");
|
|
500
|
+
emitCompactionActivity("failed", compactionFailureMessage(error));
|
|
501
|
+
throw error;
|
|
502
|
+
}
|
|
503
|
+
if (planned) {
|
|
504
|
+
preSummaryStageActed = true;
|
|
505
|
+
middleware.fireCompactionHook("working_set_evict", "pressure", estimate.tokens);
|
|
506
|
+
emitCompactionActivity("started", "compacting context (working-set eviction)");
|
|
507
|
+
try {
|
|
508
|
+
deps.session.appendEntry({
|
|
509
|
+
...buildEvictionFields(planned, {
|
|
510
|
+
trigger: "pressure",
|
|
511
|
+
pressureBefore: verdict.pressure,
|
|
512
|
+
snapshotIdBefore: beforeSnapshotId,
|
|
513
|
+
}),
|
|
514
|
+
// appendEntry does not infer this anchor; the interactive
|
|
515
|
+
// cursor is the leaf the next message will extend.
|
|
516
|
+
parentTurnId: state.lastTurnId,
|
|
517
|
+
});
|
|
518
|
+
noteColdReason("working_set_evict");
|
|
519
|
+
refreshAgentMessagesFromSession(agentRuntime);
|
|
520
|
+
|
|
521
|
+
const postEvictionSnapshot = captureRuntimeContextSnapshot(
|
|
522
|
+
agentRuntime,
|
|
523
|
+
state.activeUserTurnId || "compaction",
|
|
524
|
+
compactionThreshold,
|
|
525
|
+
);
|
|
526
|
+
currentContextSnapshot = postEvictionSnapshot;
|
|
527
|
+
persistContextSnapshot(postEvictionSnapshot);
|
|
528
|
+
|
|
529
|
+
// Every surface that describes this event (the notice, the toast
|
|
530
|
+
// ContextPruned feeds, the overlay's last-compaction line, the
|
|
531
|
+
// ledger entry) quotes the plan: the same chars/4 pricing over the
|
|
532
|
+
// same visible slice. The live estimate prices the agent message
|
|
533
|
+
// list and differs by the tool schemas and replay text; it stays
|
|
534
|
+
// what the meter and the re-check below read, not what the event
|
|
535
|
+
// reports about itself.
|
|
536
|
+
lastCompactionEvent = {
|
|
537
|
+
stage: "working_set",
|
|
538
|
+
tokensBefore: planned.tokensBefore,
|
|
539
|
+
tokensAfter: planned.tokensAfter,
|
|
540
|
+
trigger,
|
|
541
|
+
};
|
|
542
|
+
deps.bus?.emit(BusChannels.ContextPruned, {
|
|
543
|
+
stage: "working_set",
|
|
544
|
+
pressure: verdict.pressure,
|
|
545
|
+
tokensBefore: planned.tokensBefore,
|
|
546
|
+
tokensAfter: planned.tokensAfter,
|
|
547
|
+
trigger,
|
|
548
|
+
snapshotIdBefore: beforeSnapshotId,
|
|
549
|
+
snapshotIdAfter: postEvictionSnapshot.snapshotId,
|
|
550
|
+
policyId: planned.policyId,
|
|
551
|
+
evictedItems: planned.items.length,
|
|
552
|
+
at: Date.now(),
|
|
553
|
+
} satisfies ContextPrunedPayload);
|
|
554
|
+
const itemsWord = planned.items.length === 1 ? "item" : "items";
|
|
555
|
+
emitCompactionActivity("completed", `${planned.items.length} working-set ${itemsWord} evicted`);
|
|
556
|
+
deps.emitNotice(
|
|
557
|
+
`[context engine] working set: ${planned.items.length} ${itemsWord} evicted by ${planned.policyId}; ~${planned.tokensBefore} -> ~${planned.tokensAfter} tokens, recall by ref with context(scope="recall")`,
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
const after = liveContextEstimate(agentRuntime, pendingUserText);
|
|
561
|
+
if (!shouldCompact(after.tokens, compactionThreshold, after.contextWindow).shouldCompact) return true;
|
|
562
|
+
} catch (error) {
|
|
563
|
+
emitCompactionActivity("failed", compactionFailureMessage(error));
|
|
564
|
+
throw error;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
436
567
|
}
|
|
437
568
|
}
|
|
438
569
|
}
|
|
439
570
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
571
|
+
if (!deps.autoCompact) {
|
|
572
|
+
rememberEmptyAutomaticAttempt();
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
let summaryLifecycleStarted = false;
|
|
576
|
+
const startSummaryLifecycle = (): void => {
|
|
577
|
+
middleware.fireCompactionHook("llm_summary", trigger);
|
|
578
|
+
deps.bus?.emit(BusChannels.CompactionBegin, { trigger, at: Date.now() });
|
|
579
|
+
emitCompactionActivity("started", "compacting context (summary)");
|
|
580
|
+
summaryLifecycleStarted = true;
|
|
581
|
+
};
|
|
582
|
+
if (force) startSummaryLifecycle();
|
|
443
583
|
let result: CompactResult | null = null;
|
|
444
584
|
const beforeSnapshotId = currentContextSnapshot?.snapshotId ?? null;
|
|
445
585
|
try {
|
|
446
586
|
result = await compactionTrigger.fire(() => (deps.autoCompact ?? (async () => null))(instructions, trigger));
|
|
447
587
|
} catch (error) {
|
|
588
|
+
if (!summaryLifecycleStarted) startSummaryLifecycle();
|
|
448
589
|
emitCompactionActivity("failed", compactionFailureMessage(error));
|
|
449
|
-
throw error;
|
|
450
|
-
} finally {
|
|
451
590
|
deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
|
|
591
|
+
throw error;
|
|
452
592
|
}
|
|
453
593
|
if (!result || result.summary.length === 0) {
|
|
454
|
-
|
|
594
|
+
if (summaryLifecycleStarted) {
|
|
595
|
+
deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
|
|
596
|
+
emitCompactionActivity("completed", "nothing to compact");
|
|
597
|
+
} else {
|
|
598
|
+
rememberEmptyAutomaticAttempt();
|
|
599
|
+
}
|
|
455
600
|
return false;
|
|
456
601
|
}
|
|
602
|
+
if (!summaryLifecycleStarted) startSummaryLifecycle();
|
|
603
|
+
deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
|
|
457
604
|
|
|
458
605
|
// The summarization call spends tokens on the same target the turn would
|
|
459
606
|
// have. The ledger entry carries its usage for a later reseed; this is the
|
|
@@ -790,16 +937,17 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
790
937
|
consumeExpectedColdReasons(runtimeId: string): void {
|
|
791
938
|
// Cache-disturbance honesty (T3.3): consume disturbances since
|
|
792
939
|
// the last settled run. Only single-slot local backends lose their
|
|
793
|
-
// prefix cache to interleaved work, so
|
|
794
|
-
// stamp
|
|
940
|
+
// prefix cache to interleaved work, so dispatch and compaction
|
|
941
|
+
// stamp only on local-native targets; a working-set eviction moved
|
|
942
|
+
// the prefix itself and stamps on every tier (see stampsOnTier).
|
|
795
943
|
runExpectedColdReasons = [];
|
|
796
|
-
|
|
944
|
+
nextAssistantColdReasons = [];
|
|
797
945
|
if (pendingColdReasons.size > 0) {
|
|
798
|
-
const reasons = [...pendingColdReasons];
|
|
946
|
+
const reasons = [...pendingColdReasons].filter((reason) => stampsOnTier(reason, runtimeId));
|
|
799
947
|
pendingColdReasons.clear();
|
|
800
|
-
if (
|
|
948
|
+
if (reasons.length > 0) {
|
|
801
949
|
runExpectedColdReasons = reasons;
|
|
802
|
-
|
|
950
|
+
nextAssistantColdReasons = reasons;
|
|
803
951
|
deps.emitNotice(`[context engine] backend prefix cache likely cold this turn: ${reasons.join(", ")}`);
|
|
804
952
|
}
|
|
805
953
|
}
|
|
@@ -818,9 +966,9 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
818
966
|
cacheWrite,
|
|
819
967
|
backendVerdict: backendCacheVerdict(input, cacheRead),
|
|
820
968
|
};
|
|
821
|
-
if (
|
|
822
|
-
promptCache.expectedColdReasons = [...
|
|
823
|
-
|
|
969
|
+
if (nextAssistantColdReasons.length > 0) {
|
|
970
|
+
promptCache.expectedColdReasons = [...nextAssistantColdReasons];
|
|
971
|
+
nextAssistantColdReasons = [];
|
|
824
972
|
}
|
|
825
973
|
return promptCache;
|
|
826
974
|
},
|
|
@@ -834,6 +982,7 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
834
982
|
cacheWriteTokens: cacheSummary.cacheRead > 0 || cacheSummary.cacheWrite > 0 ? cacheSummary.cacheWrite : null,
|
|
835
983
|
uncachedInputTokens: cacheSummary.input,
|
|
836
984
|
backendVerdict: runFirstCallVerdict,
|
|
985
|
+
...(runExpectedColdReasons.length > 0 ? { expectedColdReasons: [...runExpectedColdReasons] } : {}),
|
|
837
986
|
};
|
|
838
987
|
}
|
|
839
988
|
},
|
|
@@ -844,6 +993,7 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
844
993
|
sessionPromptKey = null;
|
|
845
994
|
sessionWorkingContextPaths.clear();
|
|
846
995
|
pendingPromptLogEntry = null;
|
|
996
|
+
emptyAutoCompactTurnId = null;
|
|
847
997
|
const session = deps.session?.current();
|
|
848
998
|
currentContextSnapshot = session ? getLatestContextSnapshot(session) : null;
|
|
849
999
|
},
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
type MiddlewareToolChoiceControl,
|
|
16
16
|
} from "../domains/middleware/index.js";
|
|
17
17
|
import type { SessionContract } from "../domains/session/contract.js";
|
|
18
|
-
import type { CompactionTrigger } from "../domains/session/entries.js";
|
|
18
|
+
import type { CompactionTrigger, EvictionTrigger, RecallTrigger } from "../domains/session/entries.js";
|
|
19
19
|
import type { AgentMessage } from "../engine/types.js";
|
|
20
20
|
import { extractText, hasStructuredToolCall, toolNamesFromAgentState } from "./chat-loop-messages.js";
|
|
21
21
|
import type { AgentRuntime, ChatTurnState } from "./turn-state.js";
|
|
@@ -42,8 +42,8 @@ export interface TurnMiddleware {
|
|
|
42
42
|
terminalToolResult?: { toolCallId: string; toolName: string },
|
|
43
43
|
): Promise<void>;
|
|
44
44
|
fireCompactionHook(
|
|
45
|
-
stage: "mask_observations" | "llm_summary",
|
|
46
|
-
trigger: CompactionTrigger,
|
|
45
|
+
stage: "mask_observations" | "working_set_evict" | "working_set_recall" | "llm_summary",
|
|
46
|
+
trigger: CompactionTrigger | EvictionTrigger | RecallTrigger,
|
|
47
47
|
tokensBefore?: number,
|
|
48
48
|
): void;
|
|
49
49
|
flushPendingReminders(): string;
|
|
@@ -240,9 +240,9 @@ export function createTurnMiddleware(deps: TurnMiddlewareDeps): TurnMiddleware {
|
|
|
240
240
|
},
|
|
241
241
|
|
|
242
242
|
/**
|
|
243
|
-
* Observe-only lifecycle point fired before each compaction
|
|
244
|
-
*
|
|
245
|
-
*
|
|
243
|
+
* Observe-only lifecycle point fired before each compaction or working-set
|
|
244
|
+
* stage. Consumers record telemetry or state around projected context
|
|
245
|
+
* changes; returned effects are discarded by design.
|
|
246
246
|
*/
|
|
247
247
|
fireCompactionHook(stage, trigger, tokensBefore): void {
|
|
248
248
|
if (!deps.middleware) return;
|
package/src/tools/agent-tools.ts
CHANGED
|
@@ -28,6 +28,7 @@ import { validateEngineToolArguments } from "../engine/ai.js";
|
|
|
28
28
|
import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from "../engine/types.js";
|
|
29
29
|
import { applyToolProfile, type ToolProfileName } from "./profiles.js";
|
|
30
30
|
import type { ToolInvokeOptions, ToolRegistry, ToolResult, ToolSpec } from "./registry.js";
|
|
31
|
+
import { isDispositionedToolResultError, toolResultContextText } from "./result-disposition.js";
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* Lightweight per-call observability hook. Default no-op so unused
|
|
@@ -99,10 +100,10 @@ type WorkerToolOkDetails = { kind: "ok" } & Record<string, unknown>;
|
|
|
99
100
|
function projectToolResult(result: ToolResult): WorkerAgentToolResult {
|
|
100
101
|
const details = { ...(result.details ?? {}), kind: result.kind } as { kind: "ok" } | { kind: "error" };
|
|
101
102
|
if (result.kind === "error") {
|
|
102
|
-
return { content: [{ type: "text", text: result
|
|
103
|
+
return { content: [{ type: "text", text: toolResultContextText(result) }], details };
|
|
103
104
|
}
|
|
104
105
|
return {
|
|
105
|
-
content: [{ type: "text", text: result
|
|
106
|
+
content: [{ type: "text", text: toolResultContextText(result) }],
|
|
106
107
|
details,
|
|
107
108
|
...(result.terminate === true ? { terminate: true } : {}),
|
|
108
109
|
};
|
|
@@ -119,6 +120,8 @@ interface RunValidatedToolCallInput {
|
|
|
119
120
|
signal?: AbortSignal;
|
|
120
121
|
telemetry?: ToolTelemetry;
|
|
121
122
|
invokeOptions?: Partial<ToolInvokeOptions>;
|
|
123
|
+
/** Agent loops can preserve canonical failure envelopes and classify them after execution. */
|
|
124
|
+
returnDispositionedErrors?: boolean;
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
async function runValidatedToolCall(input: RunValidatedToolCallInput): Promise<WorkerAgentToolResult> {
|
|
@@ -183,13 +186,16 @@ async function runValidatedToolCall(input: RunValidatedToolCallInput): Promise<W
|
|
|
183
186
|
reason: verdict.result.message,
|
|
184
187
|
decision: verdict.decision,
|
|
185
188
|
});
|
|
186
|
-
|
|
189
|
+
if (input.returnDispositionedErrors === true && isDispositionedToolResultError(verdict.result)) {
|
|
190
|
+
return projectToolResult(verdict.result);
|
|
191
|
+
}
|
|
192
|
+
throw new Error(toolResultContextText(verdict.result));
|
|
187
193
|
}
|
|
188
194
|
const toolDetails = isRecord(verdict.result.details) ? verdict.result.details : {};
|
|
189
195
|
const skillActivation =
|
|
190
196
|
spec.name === ToolNames.Context ? skillActivationFromToolDetails(toolDetails, input.invokeOptions?.turnId) : null;
|
|
191
197
|
const result: AgentToolResult<WorkerToolOkDetails> = {
|
|
192
|
-
content: [{ type: "text", text: verdict.result
|
|
198
|
+
content: [{ type: "text", text: toolResultContextText(verdict.result) }],
|
|
193
199
|
details: { ...toolDetails, kind: "ok" },
|
|
194
200
|
};
|
|
195
201
|
if (verdict.result.terminate === true) {
|
|
@@ -291,6 +297,7 @@ function toAgentTool(
|
|
|
291
297
|
spec,
|
|
292
298
|
args: params as Record<string, unknown>,
|
|
293
299
|
registry,
|
|
300
|
+
returnDispositionedErrors: true,
|
|
294
301
|
};
|
|
295
302
|
if (signal) callInput.signal = signal;
|
|
296
303
|
if (telemetry) callInput.telemetry = telemetry;
|