@cortexkit/opencode-magic-context 0.41.2 → 0.41.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/README.md +9 -3
- package/dist/announcement-3c1vertn.js +14 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/project-security.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +756 -4
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/conflict-warning-hook-ejkc9sjn.js +16 -0
- package/dist/derive-budgets-bc366cz8.js +13 -0
- package/dist/features/magic-context/compartment-lease.d.ts +6 -0
- package/dist/features/magic-context/compartment-lease.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +13 -0
- package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts +3 -0
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts +18 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +13 -14
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta.d.ts +1 -1
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
- package/dist/features/magic-context/storage-subagent-invocations.d.ts +3 -2
- package/dist/features/magic-context/storage-subagent-invocations.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts +6 -0
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +2 -2
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/subagent-token-capture.d.ts +2 -1
- package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +5 -1
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts +6 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +4 -0
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts +2 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/derive-budgets.d.ts +1 -0
- package/dist/hooks/magic-context/derive-budgets.d.ts.map +1 -1
- package/dist/hooks/magic-context/emergency-drop.d.ts +3 -1
- package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
- package/dist/hooks/magic-context/execute-status.d.ts +7 -1
- package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts +4 -3
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts +2 -0
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +9 -5
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +6 -0
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/issue-423-fixture.d.ts +37 -0
- package/dist/hooks/magic-context/issue-423-fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/issue-424-fixture.d.ts +11 -0
- package/dist/hooks/magic-context/issue-424-fixture.d.ts.map +1 -0
- package/dist/hooks/magic-context/module-state-sync.d.ts +2 -1
- package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-transport.d.ts +11 -4
- package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-wire.d.ts +6 -1
- package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
- package/dist/hooks/magic-context/producer-window-guard.d.ts +8 -0
- package/dist/hooks/magic-context/producer-window-guard.d.ts.map +1 -0
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts +59 -0
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-chunk.d.ts +2 -0
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-db.d.ts +15 -0
- package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts +4 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
- package/dist/hooks/magic-context/recomp-orchestrator.d.ts +2 -0
- package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
- package/dist/hooks/magic-context/rust-mode-transform.d.ts +15 -2
- package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/send-session-notification.d.ts +6 -0
- package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
- package/dist/hooks/magic-context/sentinel.d.ts +8 -19
- package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts +2 -0
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +8 -3
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-drop-target.d.ts +1 -0
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +2 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +32 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +4 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
- package/dist/{index-j8r0ejb3.js → index-0y2mcg5y.js} +1971 -11203
- package/dist/{index-1yh8g550.js → index-22jkk6wg.js} +2 -15
- package/dist/{index-dmvy29z0.js → index-3wzdwt6p.js} +11 -15
- package/dist/{index-eq9wr75c.js → index-4avmwfp5.js} +57 -108
- package/dist/{index-d1mxrd3p.js → index-7k55qm8a.js} +17 -12
- package/dist/{index-2wchnyk6.js → index-avwt563y.js} +8 -1
- package/dist/{index-4x691bz5.js → index-dkv2dn46.js} +5 -2
- package/dist/{index-rgdqj8nj.js → index-e7vx3byk.js} +1 -1
- package/dist/{index-szf8w1p5.js → index-fmsr7v69.js} +2 -2
- package/dist/{index-y1yr57fw.js → index-fz104x1j.js} +18 -18
- package/dist/{index-d62ypazr.js → index-jdxxq8cz.js} +6 -11
- package/dist/{index-9j3tx8hy.js → index-may8skc8.js} +6 -25
- package/dist/{index-cvda5jb3.js → index-mjv9je4e.js} +23 -19
- package/dist/{index-zwjhba2r.js → index-q264erdp.js} +122 -41
- package/dist/{index-b9j85d29.js → index-raatkvw5.js} +49 -11
- package/dist/{index-9xexf8s7.js → index-rn7gafjr.js} +1 -9
- package/dist/index-sd3egckz.js +1583 -0
- package/dist/index-v6t0tg85.js +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2660 -3255
- package/dist/model-resolution-dxatzjde.js +12 -0
- package/dist/{index-dynqfgx1.js → module-asyncify-2EFITU5U-rkqjhjxd.js} +69 -8
- package/dist/plugin/boot-deadline.d.ts +47 -0
- package/dist/plugin/boot-deadline.d.ts.map +1 -0
- package/dist/plugin/conflict-warning-hook.d.ts +10 -0
- package/dist/plugin/conflict-warning-hook.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +5 -0
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/messages-transform.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/prompt-context-5y5ms8f9.js +6 -0
- package/dist/recomp-orchestrator-q98r6rga.js +19 -0
- package/dist/rpc-notifications-4amf6mf4.js +14 -0
- package/dist/{index-vnz6jvdc.js → safe-notification-target-q9z81zt3.js} +4 -3
- package/dist/send-session-notification-hdh02wy9.js +16 -0
- package/dist/shared/cache-ttl-display.d.ts +23 -0
- package/dist/shared/cache-ttl-display.d.ts.map +1 -0
- package/dist/shared/cache-ttl-seed.d.ts +10 -0
- package/dist/shared/cache-ttl-seed.d.ts.map +1 -0
- package/dist/shared/config-diagnostics.d.ts +30 -0
- package/dist/shared/config-diagnostics.d.ts.map +1 -0
- package/dist/shared/config-warning-surface.d.ts +3 -0
- package/dist/shared/config-warning-surface.d.ts.map +1 -0
- package/dist/shared/conflict-detector.d.ts +3 -1
- package/dist/shared/conflict-detector.d.ts.map +1 -1
- package/dist/shared/data-path.d.ts +10 -9
- package/dist/shared/data-path.d.ts.map +1 -1
- package/dist/shared/harness-provider-map.d.ts +7 -0
- package/dist/shared/harness-provider-map.d.ts.map +1 -1
- package/dist/shared/harness.d.ts +3 -3
- package/dist/shared/harness.d.ts.map +1 -1
- package/dist/shared/jsonc-parser.d.ts +12 -0
- package/dist/shared/jsonc-parser.d.ts.map +1 -1
- package/dist/shared/model-resolution.d.ts +3 -3
- package/dist/shared/model-resolution.d.ts.map +1 -1
- package/dist/shared/model-suggestion-retry.d.ts +14 -10
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/pi-executable.d.ts +6 -0
- package/dist/shared/pi-executable.d.ts.map +1 -0
- package/dist/shared/prompt-surface-runtime.d.ts +2 -2
- package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
- package/dist/shared/rpc-types.d.ts +6 -0
- package/dist/shared/rpc-types.d.ts.map +1 -1
- package/dist/shared/rpc-utils.d.ts.map +1 -1
- package/dist/shared/status-detail-text.d.ts.map +1 -1
- package/dist/shared/tag-transcript.d.ts.map +1 -1
- package/dist/shared/transcript.d.ts +2 -1
- package/dist/shared/transcript.d.ts.map +1 -1
- package/dist/storage-meta-session-dvwfw778.js +20 -0
- package/dist/task-config-hnv93r7p.js +9 -0
- package/dist/transformers-node-wasm.js +328 -328
- package/dist/transformers-web.js +72 -72
- package/dist/{transformers.node-b1wa0hgx.js → transformers.node-dpmf3wpx.js} +74 -74
- package/package.json +1 -1
- package/src/config/index.test.ts +72 -0
- package/src/config/index.ts +96 -15
- package/src/config/project-security.hostile-matrix.test.ts +78 -9
- package/src/config/project-security.ts +4 -3
- package/src/config/schema/magic-context.test.ts +64 -0
- package/src/config/schema/magic-context.ts +100 -6
- package/src/shared/cache-ttl-display.test.ts +84 -0
- package/src/shared/cache-ttl-display.ts +64 -0
- package/src/shared/cache-ttl-seed.ts +23 -0
- package/src/shared/config-diagnostics.test.ts +29 -0
- package/src/shared/config-diagnostics.ts +64 -0
- package/src/shared/config-warning-surface.ts +28 -0
- package/src/shared/conflict-detector.test.ts +24 -0
- package/src/shared/conflict-detector.ts +25 -7
- package/src/shared/data-path.ts +10 -9
- package/src/shared/harness-provider-map.test.ts +16 -0
- package/src/shared/harness-provider-map.ts +15 -0
- package/src/shared/harness.ts +3 -3
- package/src/shared/jsonc-parser.test.ts +14 -1
- package/src/shared/jsonc-parser.ts +93 -0
- package/src/shared/model-resolution.test.ts +61 -0
- package/src/shared/model-resolution.ts +14 -5
- package/src/shared/model-suggestion-retry.ts +143 -28
- package/src/shared/pi-executable.ts +20 -0
- package/src/shared/prompt-surface-runtime.ts +3 -3
- package/src/shared/rpc-types.ts +6 -0
- package/src/shared/rpc-utils.ts +2 -3
- package/src/shared/status-detail-text.test.ts +2 -1
- package/src/shared/status-detail-text.ts +5 -1
- package/src/shared/tag-transcript.ts +32 -2
- package/src/shared/transcript.ts +3 -1
- package/src/tui/index.tsx +15 -1
- package/src/tui-compiled/index.tsx +234 -222
- package/dist/announcement-3g9xg433.js +0 -18
- package/dist/conflict-warning-hook-rf17b6et.js +0 -17
- package/dist/derive-budgets-9q2d3r93.js +0 -14
- package/dist/emscripten-module-49k43zfy.js +0 -507
- package/dist/emscripten-module-ex4v0x4z.js +0 -606
- package/dist/emscripten-module-jfs3d1dq.js +0 -1536
- package/dist/emscripten-module-ss4g4spn.js +0 -4563
- package/dist/ffi-bbm9vkfa.js +0 -92
- package/dist/ffi-kb5r0x1j.js +0 -92
- package/dist/ffi-qnrt0y78.js +0 -80
- package/dist/ffi-yx2hpf4p.js +0 -80
- package/dist/index-8mtsfhyg.js +0 -146
- package/dist/index-8sseka65.js +0 -251
- package/dist/index-ss632za9.js +0 -77
- package/dist/model-resolution-6w6wzw18.js +0 -17
- package/dist/module-ES6BEMUI-1yjdz59c.js +0 -14
- package/dist/module-asyncify-2EFITU5U-fdkx4fhy.js +0 -9
- package/dist/prompt-context-29qkb28f.js +0 -7
- package/dist/recomp-orchestrator-m37p3fq6.js +0 -34
- package/dist/rpc-notifications-1ffm755w.js +0 -17
- package/dist/safe-notification-target-2a8py95v.js +0 -11
- package/dist/send-session-notification-bw7eex6w.js +0 -20
- package/dist/storage-meta-session-dse3qv6s.js +0 -23
- package/dist/task-config-gv6s04fp.js +0 -18
- /package/dist/{index-37yzyeca.js → index-3fe78beq.js} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ModelHarness = "opencode" | "pi";
|
|
1
|
+
export type ModelHarness = "opencode" | "pi" | "omp";
|
|
2
2
|
|
|
3
3
|
export interface ResolvedModelEntry {
|
|
4
4
|
/** Canonical provider/model reference used for identity and model selection. */
|
|
@@ -27,6 +27,14 @@ function hasOwn(record: ConfigRecord, key: string): boolean {
|
|
|
27
27
|
return Object.hasOwn(record, key);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
function resolveHarnessBlock(
|
|
31
|
+
container: ConfigRecord | undefined,
|
|
32
|
+
harness: ModelHarness,
|
|
33
|
+
): ConfigRecord | undefined {
|
|
34
|
+
const selected = harness === "omp" ? (container?.omp ?? container?.pi) : container?.[harness];
|
|
35
|
+
return asRecord(selected);
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
/**
|
|
31
39
|
* Collapses the string and object spellings of a harness model entry into the
|
|
32
40
|
* same model identity. Qualifiers stay separate because they alter an attempt,
|
|
@@ -98,15 +106,15 @@ export interface ResolvedHistorianModel {
|
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
/**
|
|
101
|
-
* Resolve historian model attempts from
|
|
102
|
-
* and
|
|
109
|
+
* Resolve historian model attempts from the selected harness block. OMP uses
|
|
110
|
+
* its own block when present and falls back to Pi when it is absent.
|
|
103
111
|
*/
|
|
104
112
|
export function resolveHistorianModel(
|
|
105
113
|
config: unknown,
|
|
106
114
|
harness: ModelHarness,
|
|
107
115
|
): ResolvedHistorianModel {
|
|
108
116
|
const historian = asRecord(asRecord(config)?.historian);
|
|
109
|
-
const block =
|
|
117
|
+
const block = resolveHarnessBlock(historian, harness);
|
|
110
118
|
if (!block) return { fallbacks: [] };
|
|
111
119
|
|
|
112
120
|
return {
|
|
@@ -139,7 +147,7 @@ export function resolveDreamerTaskModel(args: {
|
|
|
139
147
|
muralModel?: unknown;
|
|
140
148
|
}): ResolvedDreamerTaskModel {
|
|
141
149
|
const dreamer = asRecord(asRecord(args.config)?.dreamer);
|
|
142
|
-
const harnessBlock =
|
|
150
|
+
const harnessBlock = resolveHarnessBlock(dreamer, args.harness);
|
|
143
151
|
const taskBlock = asRecord(asRecord(harnessBlock?.tasks)?.[args.task]);
|
|
144
152
|
const schedulingTask = asRecord(asRecord(dreamer?.tasks)?.[args.task]);
|
|
145
153
|
if (!harnessBlock) {
|
|
@@ -211,6 +219,7 @@ export function resolveOpenCodeAgentOverrides(agent: unknown): Record<string, un
|
|
|
211
219
|
thinking_level: _thinking,
|
|
212
220
|
opencode,
|
|
213
221
|
pi,
|
|
222
|
+
omp,
|
|
214
223
|
tasks,
|
|
215
224
|
...rest
|
|
216
225
|
} = source;
|
|
@@ -3,6 +3,7 @@ import type { createOpencodeClient } from "@opencode-ai/sdk";
|
|
|
3
3
|
import { detectOverflow } from "../features/magic-context/overflow-detection";
|
|
4
4
|
import { log } from "./logger";
|
|
5
5
|
import type { ModelInput } from "./model-resolution";
|
|
6
|
+
import { sanitizeDiagnosticText } from "./redaction";
|
|
6
7
|
import { parseProviderModel, toModelEntry } from "./resolve-fallbacks";
|
|
7
8
|
|
|
8
9
|
type Client = ReturnType<typeof createOpencodeClient>;
|
|
@@ -100,6 +101,33 @@ export interface ValidatedPromptRetryResult<TOutput, TValidated> {
|
|
|
100
101
|
attempt: PromptAttemptInfo;
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
export type PromptFailureClass =
|
|
105
|
+
| "provider_timeout"
|
|
106
|
+
| "provider_error"
|
|
107
|
+
| "empty_completion"
|
|
108
|
+
| "no_models"
|
|
109
|
+
| "child_aborted"
|
|
110
|
+
| "parse_failed"
|
|
111
|
+
| "unknown";
|
|
112
|
+
|
|
113
|
+
/** Diagnostic facts retained when a validated child prompt ultimately fails. */
|
|
114
|
+
export interface PromptFailureDetail {
|
|
115
|
+
failureClass: PromptFailureClass;
|
|
116
|
+
modelAttempted: string | null;
|
|
117
|
+
modelsTried: string[];
|
|
118
|
+
providerError: string | null;
|
|
119
|
+
timeoutMs: number | null;
|
|
120
|
+
childSessionId: string | null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const promptFailureDetails = new WeakMap<object, PromptFailureDetail>();
|
|
124
|
+
|
|
125
|
+
export function getPromptFailureDetail(error: unknown): PromptFailureDetail | null {
|
|
126
|
+
return error !== null && typeof error === "object"
|
|
127
|
+
? (promptFailureDetails.get(error) ?? null)
|
|
128
|
+
: null;
|
|
129
|
+
}
|
|
130
|
+
|
|
103
131
|
export interface ModelSuggestionInfo {
|
|
104
132
|
providerID: string;
|
|
105
133
|
modelID: string;
|
|
@@ -279,6 +307,61 @@ function shortErr(error: unknown): string {
|
|
|
279
307
|
return extractMessage(error);
|
|
280
308
|
}
|
|
281
309
|
|
|
310
|
+
type PromptFailurePhase = "prompt" | "output" | "validation";
|
|
311
|
+
|
|
312
|
+
interface FailedAttempt {
|
|
313
|
+
error: unknown;
|
|
314
|
+
failureClass: PromptFailureClass;
|
|
315
|
+
attempt: PromptAttemptInfo;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function classifyPromptFailure(
|
|
319
|
+
error: unknown,
|
|
320
|
+
phase: PromptFailurePhase,
|
|
321
|
+
externalSignal?: AbortSignal,
|
|
322
|
+
): PromptFailureClass {
|
|
323
|
+
const message = extractMessage(error);
|
|
324
|
+
if (externalSignal?.aborted || message === "prompt aborted by external signal") {
|
|
325
|
+
return "child_aborted";
|
|
326
|
+
}
|
|
327
|
+
if (/^prompt timed out after \d+ms$/.test(message)) return "provider_timeout";
|
|
328
|
+
if (phase === "validation") {
|
|
329
|
+
if (/returned no (?:assistant )?output|no assistant output/i.test(message)) {
|
|
330
|
+
return "empty_completion";
|
|
331
|
+
}
|
|
332
|
+
if (error instanceof Error && error.name === "DreamerProviderOutputFailureError") {
|
|
333
|
+
return "provider_error";
|
|
334
|
+
}
|
|
335
|
+
return "parse_failed";
|
|
336
|
+
}
|
|
337
|
+
return phase === "prompt" || phase === "output" ? "provider_error" : "unknown";
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function throwWithPromptFailure(
|
|
341
|
+
legacyError: unknown,
|
|
342
|
+
failedAttempts: FailedAttempt[],
|
|
343
|
+
args: PromptArgs,
|
|
344
|
+
timeoutMs: number,
|
|
345
|
+
): never {
|
|
346
|
+
const error =
|
|
347
|
+
legacyError instanceof Error ? legacyError : new Error(extractMessage(legacyError));
|
|
348
|
+
const last = failedAttempts.at(-1);
|
|
349
|
+
const failureClass = last?.failureClass ?? "unknown";
|
|
350
|
+
const providerError =
|
|
351
|
+
failureClass === "provider_error"
|
|
352
|
+
? sanitizeDiagnosticText(shortErr(last?.error ?? legacyError)).slice(0, 500)
|
|
353
|
+
: null;
|
|
354
|
+
promptFailureDetails.set(error, {
|
|
355
|
+
failureClass,
|
|
356
|
+
modelAttempted: last?.attempt.label ?? null,
|
|
357
|
+
modelsTried: failedAttempts.map((failure) => failure.attempt.label),
|
|
358
|
+
providerError,
|
|
359
|
+
timeoutMs: failureClass === "provider_timeout" ? timeoutMs : null,
|
|
360
|
+
childSessionId: args.path.id || null,
|
|
361
|
+
});
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
364
|
+
|
|
282
365
|
/**
|
|
283
366
|
* Try a single prompt attempt against the supplied body, with the existing
|
|
284
367
|
* single-suggestion retry layered inside (so "did you mean X?" still self-heals
|
|
@@ -449,23 +532,43 @@ async function attemptAndValidate<TOutput, TValidated>(
|
|
|
449
532
|
attempt: PromptAttemptInfo,
|
|
450
533
|
options: ValidatedPromptRetryOptions<TOutput, TValidated>,
|
|
451
534
|
): Promise<ValidatedPromptRetryResult<TOutput, TValidated>> {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
535
|
+
try {
|
|
536
|
+
await attemptOnce(client, args, timeoutMs, signal, callContext, attempt.label);
|
|
537
|
+
} catch (error) {
|
|
538
|
+
throw {
|
|
539
|
+
error,
|
|
540
|
+
failureClass: classifyPromptFailure(error, "prompt", signal),
|
|
541
|
+
attempt,
|
|
542
|
+
} satisfies FailedAttempt;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
let output: TOutput;
|
|
546
|
+
try {
|
|
547
|
+
output = await options.fetchOutput(args, attempt);
|
|
548
|
+
} catch (error) {
|
|
549
|
+
throw {
|
|
550
|
+
error,
|
|
551
|
+
failureClass: classifyPromptFailure(error, "output", signal),
|
|
552
|
+
attempt,
|
|
553
|
+
} satisfies FailedAttempt;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
try {
|
|
557
|
+
const validated = await options.validateOutput(output, attempt);
|
|
558
|
+
return { output, validated, attempt };
|
|
559
|
+
} catch (error) {
|
|
560
|
+
throw {
|
|
561
|
+
error,
|
|
562
|
+
failureClass: classifyPromptFailure(error, "validation", signal),
|
|
563
|
+
attempt,
|
|
564
|
+
} satisfies FailedAttempt;
|
|
565
|
+
}
|
|
456
566
|
}
|
|
457
567
|
|
|
458
568
|
/**
|
|
459
|
-
* Run a prompt
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
* produced no usable assistant text / JSON.
|
|
463
|
-
*
|
|
464
|
-
* The happy path is still one prompt + one caller-owned output fetch: callers
|
|
465
|
-
* should use the returned output instead of fetching messages a second time.
|
|
466
|
-
* Validation failures are retryable across configured fallback models. If every
|
|
467
|
-
* attempt produces invalid output (or otherwise fails retryably), the first
|
|
468
|
-
* failure is re-thrown so callers surface the original failure semantics.
|
|
569
|
+
* Run a prompt across the configured model chain and retain which attempt failed.
|
|
570
|
+
* Output validation remains caller-owned so empty completions and malformed
|
|
571
|
+
* responses can be distinguished from provider transport failures.
|
|
469
572
|
*/
|
|
470
573
|
export async function promptSyncWithValidatedOutputRetry<TOutput, TValidated = TOutput>(
|
|
471
574
|
client: Client,
|
|
@@ -486,7 +589,7 @@ export async function promptSyncWithValidatedOutputRetry<TOutput, TValidated = T
|
|
|
486
589
|
? `${baseBody.model.providerID}/${baseBody.model.modelID}`
|
|
487
590
|
: "primary";
|
|
488
591
|
const totalAttempts = fallbacks.length + 1;
|
|
489
|
-
|
|
592
|
+
const failedAttempts: FailedAttempt[] = [];
|
|
490
593
|
let firstError: unknown = null;
|
|
491
594
|
let lastError: unknown = null;
|
|
492
595
|
|
|
@@ -506,17 +609,21 @@ export async function promptSyncWithValidatedOutputRetry<TOutput, TValidated = T
|
|
|
506
609
|
},
|
|
507
610
|
options,
|
|
508
611
|
);
|
|
509
|
-
} catch (
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
612
|
+
} catch (caught) {
|
|
613
|
+
const failure = caught as FailedAttempt;
|
|
614
|
+
failedAttempts.push(failure);
|
|
615
|
+
firstError = failure.error;
|
|
616
|
+
lastError = failure.error;
|
|
617
|
+
if (isNonRetryable(failure.error, options.signal)) {
|
|
618
|
+
throwWithPromptFailure(failure.error, failedAttempts, args, timeoutMs);
|
|
619
|
+
}
|
|
513
620
|
|
|
514
621
|
if (fallbacks.length === 0) {
|
|
515
|
-
|
|
622
|
+
throwWithPromptFailure(failure.error, failedAttempts, args, timeoutMs);
|
|
516
623
|
}
|
|
517
624
|
|
|
518
625
|
log(
|
|
519
|
-
`[${callContext}] primary (${explicitPrimaryLabel}) failed validation/prompt: ${shortErr(error)}; trying ${fallbacks.length} fallback(s)`,
|
|
626
|
+
`[${callContext}] primary (${explicitPrimaryLabel}) failed validation/prompt: ${shortErr(failure.error)}; trying ${fallbacks.length} fallback(s)`,
|
|
520
627
|
);
|
|
521
628
|
}
|
|
522
629
|
|
|
@@ -557,22 +664,30 @@ export async function promptSyncWithValidatedOutputRetry<TOutput, TValidated = T
|
|
|
557
664
|
`[${callContext}] fallback succeeded with ${label} (attempt ${i + 2}/${fallbacks.length + 1})`,
|
|
558
665
|
);
|
|
559
666
|
return result;
|
|
560
|
-
} catch (
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
667
|
+
} catch (caught) {
|
|
668
|
+
const failure = caught as FailedAttempt;
|
|
669
|
+
failedAttempts.push(failure);
|
|
670
|
+
lastError = failure.error;
|
|
671
|
+
if (isNonRetryable(failure.error, options.signal)) {
|
|
672
|
+
throwWithPromptFailure(failure.error, failedAttempts, args, timeoutMs);
|
|
673
|
+
}
|
|
564
674
|
|
|
565
675
|
const remaining = fallbacks.length - i - 1;
|
|
566
676
|
if (remaining > 0) {
|
|
567
677
|
log(
|
|
568
|
-
`[${callContext}] ${label} failed validation/prompt: ${shortErr(error)}; ${remaining} fallback(s) left`,
|
|
678
|
+
`[${callContext}] ${label} failed validation/prompt: ${shortErr(failure.error)}; ${remaining} fallback(s) left`,
|
|
569
679
|
);
|
|
570
680
|
}
|
|
571
681
|
}
|
|
572
682
|
}
|
|
573
683
|
|
|
574
684
|
log(
|
|
575
|
-
`[${callContext}] all models exhausted; tried: ${
|
|
685
|
+
`[${callContext}] all models exhausted; tried: ${failedAttempts.map((failure) => failure.attempt.label).join(", ")}; original error: ${shortErr(firstError)}; last error: ${shortErr(lastError)}`,
|
|
686
|
+
);
|
|
687
|
+
throwWithPromptFailure(
|
|
688
|
+
firstError ?? lastError ?? new Error("All fallback models failed validation"),
|
|
689
|
+
failedAttempts,
|
|
690
|
+
args,
|
|
691
|
+
timeoutMs,
|
|
576
692
|
);
|
|
577
|
-
throw firstError ?? lastError ?? new Error("All fallback models failed validation");
|
|
578
693
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type PiExecutableHarnessKind = "pi" | "omp";
|
|
2
|
+
|
|
3
|
+
/** Executable images recognized as Pi-compatible hosts. */
|
|
4
|
+
export const PI_IMAGE_NAMES = new Set(["pi", "pi.cmd", "omp", "oh-my-pi"]);
|
|
5
|
+
|
|
6
|
+
/** Classify a process title or executable path using the shared Pi image vocabulary. */
|
|
7
|
+
export function piHarnessKindFromExecutable(
|
|
8
|
+
value: string | undefined,
|
|
9
|
+
): PiExecutableHarnessKind | undefined {
|
|
10
|
+
const executable = (value ?? "")
|
|
11
|
+
.trim()
|
|
12
|
+
.replace(/^['"]|['"]$/g, "")
|
|
13
|
+
.replaceAll("\\", "/")
|
|
14
|
+
.split("/")
|
|
15
|
+
.at(-1)
|
|
16
|
+
?.toLowerCase()
|
|
17
|
+
.replace(/\.(?:exe|cmd)$/, "");
|
|
18
|
+
if (!executable || !PI_IMAGE_NAMES.has(executable)) return undefined;
|
|
19
|
+
return executable === "pi" ? "pi" : "omp";
|
|
20
|
+
}
|
|
@@ -2,7 +2,6 @@ import { existsSync, readFileSync, statSync } from "node:fs";
|
|
|
2
2
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
-
type ConfigHarness,
|
|
6
5
|
cortexKitUserConfigBasePath,
|
|
7
6
|
resolveLegacyConfigSourcesForHarness,
|
|
8
7
|
} from "../config/migrate-config-location";
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
CTX_REDUCE_LIGHT_DESCRIPTION,
|
|
14
13
|
CTX_SEARCH_LIGHT_DESCRIPTION,
|
|
15
14
|
} from "../tools/light-descriptions";
|
|
15
|
+
import type { HarnessId } from "./harness";
|
|
16
16
|
import { piModelRefToCanonical } from "./harness-provider-map";
|
|
17
17
|
import { detectConfigFile } from "./jsonc-parser";
|
|
18
18
|
import {
|
|
@@ -88,7 +88,7 @@ export interface PromptSurfaceRuntime {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
export interface CreatePromptSurfaceRuntimeOptions {
|
|
91
|
-
harness?:
|
|
91
|
+
harness?: HarnessId;
|
|
92
92
|
directory?: string;
|
|
93
93
|
/** Explicit test/integration seam; production derives the USER config directory. */
|
|
94
94
|
userConfigDirectory?: string;
|
|
@@ -105,7 +105,7 @@ function resolveUserConfigDirectory(options: CreatePromptSurfaceRuntimeOptions):
|
|
|
105
105
|
if (options.harness) {
|
|
106
106
|
const legacy = resolveLegacyConfigSourcesForHarness(
|
|
107
107
|
options.directory ?? process.cwd(),
|
|
108
|
-
options.harness,
|
|
108
|
+
options.harness === "omp" ? "pi" : options.harness,
|
|
109
109
|
).user.find((source) => existsSync(source.path));
|
|
110
110
|
if (legacy) return dirname(legacy.path);
|
|
111
111
|
}
|
package/src/shared/rpc-types.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
DreamTaskBacklogMap,
|
|
8
8
|
DreamTaskProgress,
|
|
9
9
|
} from "../features/magic-context/dreamer/task-registry";
|
|
10
|
+
import type { ConfigParseFailure } from "./config-diagnostics";
|
|
10
11
|
import type { LoggerDiagnostics } from "./logger";
|
|
11
12
|
|
|
12
13
|
export interface TailHygieneStatus {
|
|
@@ -181,6 +182,11 @@ export interface StatusDetail extends SidebarSnapshot {
|
|
|
181
182
|
* (only meaningful when lastResponseTime > 0); N = live countdown. */
|
|
182
183
|
cacheRemainingMs: number;
|
|
183
184
|
cacheExpired: boolean;
|
|
185
|
+
/** Reports whether the displayed TTL came from config, persisted session metadata,
|
|
186
|
+
* or the default; cache scheduling still uses the TTL stored in session metadata. */
|
|
187
|
+
cacheTtlSource?: "config" | "session" | "default";
|
|
188
|
+
cacheTtlModelKey?: string;
|
|
189
|
+
configParseFailures?: ConfigParseFailure[];
|
|
184
190
|
/** True when cacheTtl is "never" — the idle-TTL heuristic is disabled on
|
|
185
191
|
* this lane. Redundant with cacheTtlMs === -1; kept as the readable form. */
|
|
186
192
|
cacheNeverExpires?: boolean;
|
package/src/shared/rpc-utils.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { readFileSync } from "node:fs";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
|
|
6
6
|
import { log } from "./logger";
|
|
7
|
+
import { PI_IMAGE_NAMES, piHarnessKindFromExecutable } from "./pi-executable";
|
|
7
8
|
|
|
8
9
|
export type ProcessKind = "OpenCode server" | "OpenCode instance (TUI/CLI)" | "Pi" | "process";
|
|
9
10
|
|
|
@@ -102,8 +103,6 @@ const PI_HARNESS_ARC_MARKERS = [
|
|
|
102
103
|
"cljs/dist",
|
|
103
104
|
"dist/bundle/cli",
|
|
104
105
|
];
|
|
105
|
-
const PI_IMAGE_NAMES = new Set(["pi", "pi.cmd", "omp", "oh-my-pi"]);
|
|
106
|
-
|
|
107
106
|
let rpcIdentityReadFileSync: typeof readFileSync = readFileSync;
|
|
108
107
|
let rpcIdentityExecFileSync: typeof execFileSync = execFileSync;
|
|
109
108
|
let rpcIdentityProcessKill: typeof process.kill = process.kill;
|
|
@@ -346,7 +345,7 @@ function commandHasOpenCodeExecutable(tokens: readonly string[]): number {
|
|
|
346
345
|
function commandHasPiExecutable(tokens: readonly string[]): boolean {
|
|
347
346
|
for (let index = 0; index < tokens.length; index += 1) {
|
|
348
347
|
const executable = executableName(tokens[index]).replace(/\.(?:exe|cmd)$/, "");
|
|
349
|
-
if (
|
|
348
|
+
if (piHarnessKindFromExecutable(executable) !== undefined) return true;
|
|
350
349
|
if (["node", "bun", "deno"].includes(executable)) {
|
|
351
350
|
const script = executableName(tokens[index + 1]).replace(/\.(?:exe|cmd)$/, "");
|
|
352
351
|
if (
|
|
@@ -18,6 +18,7 @@ const STATUS_FIXTURE: StatusDetail = {
|
|
|
18
18
|
sessionNoteCount: 1,
|
|
19
19
|
readySmartNoteCount: 2,
|
|
20
20
|
cacheTtl: "5m",
|
|
21
|
+
cacheTtlSource: "session",
|
|
21
22
|
lastTransformError: null,
|
|
22
23
|
lastDreamerRunAt: null,
|
|
23
24
|
projectIdentity: "/repo",
|
|
@@ -73,7 +74,7 @@ describe("formatStatusDetailMarkdown", () => {
|
|
|
73
74
|
- **Mode:** Magic Context compaction
|
|
74
75
|
- **Active profile:** work
|
|
75
76
|
- **Usage:** 75.0% (96,000 / 128,000 usable tokens)
|
|
76
|
-
- **Cache
|
|
77
|
+
- **Cache TTL: 5m (session)**; live (42s remaining); TTL 5m
|
|
77
78
|
- **Historian:** running; boundary present; coverage 12
|
|
78
79
|
- **Memory:** 8 active; 3 injected
|
|
79
80
|
- **Tags:** 4 active, 1 dropped; 2 pending drops
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { formatCacheTtlDisplay } from "./cache-ttl-display";
|
|
2
|
+
import { formatConfigParseStatusLine } from "./config-diagnostics";
|
|
1
3
|
import type { StatusDetail } from "./rpc-types";
|
|
2
4
|
import { RUST_MODE_HOST_PATHS_LINE } from "./rust-mode-status";
|
|
3
5
|
|
|
@@ -33,12 +35,14 @@ export function formatStatusDetailMarkdown(detail: StatusDetail): string {
|
|
|
33
35
|
: "Magic Context compaction";
|
|
34
36
|
|
|
35
37
|
const lines = [
|
|
38
|
+
...(detail.configParseFailures ?? []).map(formatConfigParseStatusLine),
|
|
39
|
+
...((detail.configParseFailures?.length ?? 0) > 0 ? [""] : []),
|
|
36
40
|
"## Magic Context Status",
|
|
37
41
|
"",
|
|
38
42
|
`- **Mode:** ${mode}`,
|
|
39
43
|
`- **Active profile:** ${detail.activeProfile ?? "none"}`,
|
|
40
44
|
`- **Usage:** ${detail.usagePercentage.toFixed(1)}% (${formatCount(detail.inputTokens)} / ${usableLimit})`,
|
|
41
|
-
`-
|
|
45
|
+
`- **${formatCacheTtlDisplay({ value: detail.cacheTtl, source: detail.cacheTtlSource ?? "session", modelKey: detail.cacheTtlModelKey })}**; ${formatCacheLane(detail)}`,
|
|
42
46
|
`- **Historian:** ${[historianState, ...historianDetails].join("; ")}`,
|
|
43
47
|
...(detail.hostBackendsModuleSide ? [`- ${RUST_MODE_HOST_PATHS_LINE}`] : []),
|
|
44
48
|
`- **Memory:** ${formatCount(detail.memoryCount)} active; ${formatCount(detail.memoryBlockCount)} injected`,
|
|
@@ -62,6 +62,7 @@ import {
|
|
|
62
62
|
byteSize,
|
|
63
63
|
prependTag,
|
|
64
64
|
stripTagPrefix,
|
|
65
|
+
stripWellFormedLeadingTagPrefix,
|
|
65
66
|
} from "../hooks/magic-context/tag-content-primitives";
|
|
66
67
|
import type { TagTarget } from "../hooks/magic-context/tag-messages";
|
|
67
68
|
import type { Transcript, TranscriptPart } from "./transcript";
|
|
@@ -183,6 +184,8 @@ interface ToolAggregate {
|
|
|
183
184
|
inputByteSize: number;
|
|
184
185
|
/** Persisted input-token count, or null for a legacy/unobserved invocation. */
|
|
185
186
|
inputTokenCount: number | null;
|
|
187
|
+
/** At least one assistant-side occurrence shares its message with native reasoning. */
|
|
188
|
+
requiresToolArcSkeleton: boolean;
|
|
186
189
|
}
|
|
187
190
|
|
|
188
191
|
function textIdentityDigest(value: string): string {
|
|
@@ -243,6 +246,8 @@ export function tagTranscript(
|
|
|
243
246
|
let textOrdinal = 0;
|
|
244
247
|
let toolResultOrdinal = 0;
|
|
245
248
|
const parts = message.parts;
|
|
249
|
+
const messageHasNativeReasoning =
|
|
250
|
+
message.info.role === "assistant" && parts.some((part) => part.kind === "thinking");
|
|
246
251
|
const contentDerivedTextIds =
|
|
247
252
|
messageId !== undefined && options.textIdentityDriftMessageIds?.has(messageId) === true
|
|
248
253
|
? buildContentDerivedTextIds(messageId, parts)
|
|
@@ -344,6 +349,7 @@ export function tagTranscript(
|
|
|
344
349
|
const existing = toolAggregates.get(aggregateKey);
|
|
345
350
|
if (existing) {
|
|
346
351
|
existing.occurrences.push({ message, part, kind: part.kind });
|
|
352
|
+
existing.requiresToolArcSkeleton ||= messageHasNativeReasoning;
|
|
347
353
|
const canReuseIdentity = reuseIdentity && existing.identityReusable;
|
|
348
354
|
let text = "";
|
|
349
355
|
if (canReuseIdentity) {
|
|
@@ -462,6 +468,7 @@ export function tagTranscript(
|
|
|
462
468
|
toolName: null,
|
|
463
469
|
inputByteSize: reusableAccounting.inputByteSize,
|
|
464
470
|
inputTokenCount: reusableAccounting.inputTokenCount,
|
|
471
|
+
requiresToolArcSkeleton: messageHasNativeReasoning,
|
|
465
472
|
};
|
|
466
473
|
if (part.kind === "tool_result") {
|
|
467
474
|
text = part.getText() ?? "";
|
|
@@ -526,6 +533,7 @@ export function tagTranscript(
|
|
|
526
533
|
inputTokenCount:
|
|
527
534
|
persistedAccounting?.inputTokenCount ??
|
|
528
535
|
(part.kind === "tool_use" ? firstInputTokenCount : null),
|
|
536
|
+
requiresToolArcSkeleton: messageHasNativeReasoning,
|
|
529
537
|
};
|
|
530
538
|
if (part.kind === "tool_result") {
|
|
531
539
|
applyGrownToolResultAccounting({
|
|
@@ -677,7 +685,14 @@ function applyToolPrefixAndTarget(args: ApplyToolPrefixAndTargetArgs): void {
|
|
|
677
685
|
if (args.timing) args.timing.prefix += performance.now() - prefixStart;
|
|
678
686
|
}
|
|
679
687
|
const targetStart = args.timing ? performance.now() : 0;
|
|
680
|
-
args.targets.set(
|
|
688
|
+
args.targets.set(
|
|
689
|
+
args.tagId,
|
|
690
|
+
buildAggregateTarget(
|
|
691
|
+
args.tagId,
|
|
692
|
+
args.aggregate.occurrences,
|
|
693
|
+
args.aggregate.requiresToolArcSkeleton,
|
|
694
|
+
),
|
|
695
|
+
);
|
|
681
696
|
if (args.timing) args.timing.targets += performance.now() - targetStart;
|
|
682
697
|
}
|
|
683
698
|
|
|
@@ -814,6 +829,16 @@ interface TagTextPartArgs {
|
|
|
814
829
|
function tagTextPart(args: TagTextPartArgs): void {
|
|
815
830
|
const identityStart = args.timing ? performance.now() : 0;
|
|
816
831
|
const text = args.part.getText() ?? "";
|
|
832
|
+
// Pi and OMP can expose provider framing as assistant text blocks. Treat a
|
|
833
|
+
// previously prefixed blank as blank too, so MC never turns inert framing
|
|
834
|
+
// into a tag-bearing part that later strip logic could mistake for content.
|
|
835
|
+
if (
|
|
836
|
+
args.message.info.role === "assistant" &&
|
|
837
|
+
stripWellFormedLeadingTagPrefix(text).trim().length === 0
|
|
838
|
+
) {
|
|
839
|
+
if (args.timing) args.timing.identity += performance.now() - identityStart;
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
817
842
|
const contentId = args.contentId;
|
|
818
843
|
const reusableTagId = args.reuseIdentity
|
|
819
844
|
? args.tagger.getTag(args.sessionId, contentId, "message")
|
|
@@ -999,7 +1024,11 @@ function setToolContentOrText(part: TranscriptPart, content: string): boolean {
|
|
|
999
1024
|
*
|
|
1000
1025
|
* Mirrors OpenCode's createToolDropTarget semantics in tool-drop-target.ts.
|
|
1001
1026
|
*/
|
|
1002
|
-
function buildAggregateTarget(
|
|
1027
|
+
function buildAggregateTarget(
|
|
1028
|
+
tagId: number,
|
|
1029
|
+
occurrences: ToolOccurrence[],
|
|
1030
|
+
requiresToolArcSkeleton: boolean,
|
|
1031
|
+
): TagTarget {
|
|
1003
1032
|
const role = occurrences[0]?.message.info.role ?? "user";
|
|
1004
1033
|
const messageId = occurrences[0]?.message.info.id;
|
|
1005
1034
|
|
|
@@ -1079,6 +1108,7 @@ function buildAggregateTarget(tagId: number, occurrences: ToolOccurrence[]): Tag
|
|
|
1079
1108
|
canDrop(): boolean {
|
|
1080
1109
|
return occurrences.length > 0;
|
|
1081
1110
|
},
|
|
1111
|
+
requiresToolArcSkeleton,
|
|
1082
1112
|
// Non-mutating read of the invocation input (the tool_use occurrence
|
|
1083
1113
|
// carries the arguments). Used by smart-drops supersession selection.
|
|
1084
1114
|
readInput(): Record<string, unknown> | null {
|
package/src/shared/transcript.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { HarnessId } from "./harness";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Harness-agnostic transcript interface.
|
|
3
5
|
*
|
|
@@ -229,7 +231,7 @@ export interface Transcript {
|
|
|
229
231
|
* compaction marker injection).
|
|
230
232
|
* - Test assertions confirming the right adapter ran.
|
|
231
233
|
*/
|
|
232
|
-
readonly harness:
|
|
234
|
+
readonly harness: HarnessId;
|
|
233
235
|
|
|
234
236
|
/**
|
|
235
237
|
* Commit accumulated mutations to the underlying source array.
|
package/src/tui/index.tsx
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
import packageJson from "../../package.json"
|
|
11
11
|
import { closeRpc, dismissUpgradeReminder, getAnnouncement, getCompartmentCount, getRpcGeneration, initRpcClient, loadEmbedDetail, loadStatusDetail, loadToastDurationMs, markAnnounced, requestRecomp, requestUpgrade, type EmbedDetail, type StatusDetail } from "./data/context-db"
|
|
12
12
|
import { startNotificationSocket, stopNotificationSocket, type SocketNotification } from "./data/notification-socket"
|
|
13
|
+
import { formatCacheTtlDisplay } from "../shared/cache-ttl-display"
|
|
14
|
+
import { formatConfigParseStatusLine } from "../shared/config-diagnostics"
|
|
13
15
|
import { formatThresholdPercent } from "../shared/format-threshold"
|
|
14
16
|
import { formatTailHygiene } from "../shared/tail-hygiene-status"
|
|
15
17
|
import { RUST_MODE_HOST_PATHS_LINE } from "../shared/rust-mode-status"
|
|
@@ -228,6 +230,10 @@ const StatusDialog = (props: { api: TuiPluginApi; s: StatusDetail }) => {
|
|
|
228
230
|
<text fg={t().textMuted}>v{packageJson.version}</text>
|
|
229
231
|
</box>
|
|
230
232
|
|
|
233
|
+
{s().configParseFailures.map((failure) => (
|
|
234
|
+
<text fg={t().error}>{formatConfigParseStatusLine(failure)}</text>
|
|
235
|
+
))}
|
|
236
|
+
|
|
231
237
|
<box flexDirection="row" justifyContent="space-between" width="100%">
|
|
232
238
|
{compactionOff() ? (
|
|
233
239
|
<text fg={t().accent}>
|
|
@@ -378,7 +384,15 @@ const StatusDialog = (props: { api: TuiPluginApi; s: StatusDetail }) => {
|
|
|
378
384
|
<box marginTop={1}>
|
|
379
385
|
<text fg={t().text}><b>Cache TTL</b></text>
|
|
380
386
|
</box>
|
|
381
|
-
<R
|
|
387
|
+
<R
|
|
388
|
+
t={t()}
|
|
389
|
+
l="Configured"
|
|
390
|
+
v={formatCacheTtlDisplay({
|
|
391
|
+
value: s().cacheTtl,
|
|
392
|
+
source: s().cacheTtlSource,
|
|
393
|
+
modelKey: s().cacheTtlModelKey,
|
|
394
|
+
}).replace(/^Cache TTL: /, "")}
|
|
395
|
+
/>
|
|
382
396
|
<R t={t()} l="Last response" v={s().lastResponseTime > 0 ? `${Math.round(elapsed() / 1000)}s ago` : "never"} />
|
|
383
397
|
<R t={t()} l="Remaining" v={s().cacheExpired ? "expired" : s().cacheNeverExpires ? "never (MC never assumes expiry — external cache-keep)" : `${Math.round(s().cacheRemainingMs / 1000)}s`} fg={s().cacheExpired ? t().warning : t().textMuted} />
|
|
384
398
|
<R t={t()} l="Auto-execute" v={s().cacheExpired ? "yes (expired)" : s().cacheNeverExpires ? `at ≥${formatThresholdPercent(s().executeThreshold)}%` : `at TTL or ≥${formatThresholdPercent(s().executeThreshold)}%`} fg={t().textMuted} />
|