@retaw106/mmc-oc 1.2.3 → 2.1.0
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/dist/cli.js +7095 -0
- package/dist/config/index.d.ts +0 -12
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/legacy-harness-blocks.d.ts +27 -0
- package/dist/config/legacy-harness-blocks.d.ts.map +1 -0
- package/dist/config/live-run-config.d.ts.map +1 -1
- package/dist/config/live-snapshot.d.ts +2 -1
- package/dist/config/live-snapshot.d.ts.map +1 -1
- package/dist/config/project-security.d.ts +4 -5
- package/dist/config/project-security.d.ts.map +1 -1
- package/dist/config/raw-loader.d.ts +7 -26
- package/dist/config/raw-loader.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +164 -259
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/config/variable.d.ts +8 -0
- package/dist/config/variable.d.ts.map +1 -1
- package/dist/config-init.js +5595 -0
- package/dist/{context-a6px04s0.js → context-vhcstgs3.js} +5758 -4727
- package/dist/{derive-budgets-fhk00zv8.js → derive-budgets-rjjz5f7y.js} +2 -2
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/memory/types.d.ts +1 -0
- package/dist/features/magic-context/memory/types.d.ts.map +1 -1
- package/dist/features/magic-context/message-index.d.ts +2 -0
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/migration-v3-perf-schema.d.ts +8 -0
- package/dist/features/magic-context/migration-v3-perf-schema.d.ts.map +1 -0
- package/dist/features/magic-context/migration-v4-temporal-decisions.d.ts +12 -0
- package/dist/features/magic-context/migration-v4-temporal-decisions.d.ts.map +1 -0
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/overflow-detection.d.ts +6 -0
- package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
- package/dist/features/magic-context/reclaim-protection.d.ts +15 -10
- package/dist/features/magic-context/reclaim-protection.d.ts.map +1 -1
- package/dist/features/magic-context/session-cache-ttl.d.ts +4 -2
- package/dist/features/magic-context/session-cache-ttl.d.ts.map +1 -1
- package/dist/features/magic-context/session-project-storage.d.ts +8 -2
- package/dist/features/magic-context/session-project-storage.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-historian-runs.d.ts +2 -0
- package/dist/features/magic-context/storage-historian-runs.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +12 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-session.d.ts +6 -0
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-ops.d.ts +2 -0
- package/dist/features/magic-context/storage-ops.d.ts.map +1 -1
- package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts +17 -4
- 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/temporal-decisions.d.ts +10 -0
- package/dist/features/magic-context/temporal-decisions.d.ts.map +1 -0
- package/dist/features/magic-context/tool-definition-tokens.d.ts +3 -0
- package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
- package/dist/features/magic-context/transform-decision-log.d.ts +3 -1
- package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
- package/dist/hooks/magic-context/active-anthropic-turn.d.ts +8 -0
- package/dist/hooks/magic-context/active-anthropic-turn.d.ts.map +1 -0
- package/dist/hooks/magic-context/apply-operations.d.ts +15 -0
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-deadline.d.ts +10 -3
- package/dist/hooks/magic-context/auto-search-deadline.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-runner.d.ts +1 -1
- package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/caveman-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/channel2-cycle.d.ts +2 -0
- package/dist/hooks/magic-context/channel2-cycle.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-render-epoch.d.ts +8 -0
- package/dist/hooks/magic-context/compartment-render-epoch.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +3 -5
- 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/compartment-trigger.d.ts +3 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +12 -0
- package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
- package/dist/hooks/magic-context/decision-calibration.d.ts +3 -0
- package/dist/hooks/magic-context/decision-calibration.d.ts.map +1 -1
- package/dist/hooks/magic-context/emergency-drop.d.ts +2 -0
- package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
- package/dist/hooks/magic-context/emergency-fail-closed.d.ts +21 -1
- package/dist/hooks/magic-context/emergency-fail-closed.d.ts.map +1 -1
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +32 -1
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts +2 -0
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/historian-drain-gate.d.ts +11 -0
- package/dist/hooks/magic-context/historian-drain-gate.d.ts.map +1 -0
- package/dist/hooks/magic-context/inject-compartments.d.ts +10 -8
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/latest-assistant-turn.d.ts +25 -0
- package/dist/hooks/magic-context/latest-assistant-turn.d.ts.map +1 -0
- package/dist/hooks/magic-context/lkg-measured-request.d.ts +69 -0
- package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -0
- package/dist/hooks/magic-context/lkg-replay-fit.d.ts +118 -0
- package/dist/hooks/magic-context/lkg-replay-fit.d.ts.map +1 -0
- package/dist/hooks/magic-context/lkg-replay.d.ts +2 -0
- package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-formatting.d.ts +3 -0
- package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
- package/dist/hooks/magic-context/reasoning-budget-status.d.ts +15 -0
- package/dist/hooks/magic-context/reasoning-budget-status.d.ts.map +1 -0
- package/dist/hooks/magic-context/reasoning-budget.d.ts +40 -0
- package/dist/hooks/magic-context/reasoning-budget.d.ts.map +1 -0
- package/dist/hooks/magic-context/reasoning-removal.d.ts +6 -6
- package/dist/hooks/magic-context/reasoning-removal.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/sentinel.d.ts +2 -0
- package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts +7 -3
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/supersession-reclaim.d.ts +4 -0
- package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts +13 -0
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +5 -0
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
- package/dist/hooks/magic-context/temporal-awareness.d.ts +6 -3
- package/dist/hooks/magic-context/temporal-awareness.d.ts.map +1 -1
- package/dist/hooks/magic-context/temporal-served-projection.d.ts +4 -0
- package/dist/hooks/magic-context/temporal-served-projection.d.ts.map +1 -0
- package/dist/hooks/magic-context/tool-reclaim.d.ts +2 -0
- package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +3 -28
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +34 -12
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +11 -5
- 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-fg34g6a5.js → index-1j34a56j.js} +49 -8
- package/dist/index-33gprt9g.js +30 -0
- package/dist/{index-zx63j2e2.js → index-5cep2r9n.js} +3 -2
- package/dist/{index-5pg0acf7.js → index-amycb7b1.js} +1 -1
- package/dist/{index-wgt4gamw.js → index-dr0gepzw.js} +507 -53
- package/dist/{index-1vs6anwz.js → index-n0vnzz6h.js} +2 -1
- package/dist/{index-977gxfz0.js → index-ramz5kkm.js} +1 -1
- package/dist/{index-by6h2pav.js → index-wtb9hzk6.js} +499 -284
- package/dist/{index-3wagyrnj.js → index-x37vg474.js} +5 -1
- package/dist/{index-me3zcj5t.js → index-z2g20msd.js} +4 -8
- package/dist/index.js +1 -1
- package/dist/{message-time-backfill-5ewk0axe.js → message-time-backfill-phrwp2fz.js} +2 -2
- package/dist/{model-resolution-5haaxnpt.js → model-resolution-wazv26n0.js} +1 -1
- package/dist/plugin/rpc-handlers.d.ts +4 -0
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/{read-session-chunk-apjwrttc.js → read-session-chunk-82rkqa8j.js} +4 -4
- package/dist/{recomp-orchestrator-gyeevxaw.js → recomp-orchestrator-vc5dkzy2.js} +9 -9
- package/dist/{send-session-notification-y29y9fsr.js → send-session-notification-rnc4nrsr.js} +3 -3
- package/dist/shared/auto-search-lifecycle.d.ts +7 -0
- package/dist/shared/auto-search-lifecycle.d.ts.map +1 -0
- package/dist/shared/cache-ttl-display.d.ts +6 -4
- package/dist/shared/cache-ttl-display.d.ts.map +1 -1
- package/dist/shared/harness.d.ts +1 -1
- package/dist/shared/harness.d.ts.map +1 -1
- package/dist/shared/historian-tool-expansions.d.ts +1 -1
- package/dist/shared/historian-tool-expansions.d.ts.map +1 -1
- package/dist/shared/historian-tool-template.d.ts +2 -2
- package/dist/shared/historian-tool-template.d.ts.map +1 -1
- package/dist/shared/model-cache-ttl.d.ts +1 -1
- package/dist/shared/model-cache-ttl.d.ts.map +1 -1
- package/dist/shared/model-resolution.d.ts +6 -3
- package/dist/shared/model-resolution.d.ts.map +1 -1
- package/dist/shared/model-suggestion-retry.d.ts +2 -0
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/protected-tools-policy.d.ts +6 -0
- package/dist/shared/protected-tools-policy.d.ts.map +1 -0
- package/dist/shared/provider-output-failure.d.ts +19 -0
- package/dist/shared/provider-output-failure.d.ts.map +1 -0
- package/dist/shared/sqlite.d.ts +14 -1
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/shared/temporal-upgrade-fixture.d.ts +19 -0
- package/dist/shared/temporal-upgrade-fixture.d.ts.map +1 -0
- package/dist/shared/window-geometry.d.ts +4 -0
- package/dist/shared/window-geometry.d.ts.map +1 -1
- package/dist/shared/write-transaction-timing.d.ts +8 -1
- package/dist/shared/write-transaction-timing.d.ts.map +1 -1
- package/dist/tools/ctx-expand/render.d.ts.map +1 -1
- package/dist/tools/ctx-reduce/tools.d.ts +2 -0
- package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
- package/dist/v2/fold/host-media.d.ts +4 -0
- package/dist/v2/fold/host-media.d.ts.map +1 -1
- package/dist/v2/fold/memory-cache.d.ts +70 -0
- package/dist/v2/fold/memory-cache.d.ts.map +1 -0
- package/dist/v2/fold/native-codec.d.ts +10 -0
- package/dist/v2/fold/native-codec.d.ts.map +1 -0
- package/dist/v2/fold/native-replay.d.ts +58 -0
- package/dist/v2/fold/native-replay.d.ts.map +1 -0
- package/dist/v2/fold/policy.d.ts +24 -0
- package/dist/v2/fold/policy.d.ts.map +1 -0
- package/dist/v2/hidden-child-native.d.ts +7 -0
- package/dist/v2/hidden-child-native.d.ts.map +1 -1
- package/dist/v2/hidden-child-record.d.ts +19 -0
- package/dist/v2/hidden-child-record.d.ts.map +1 -1
- package/dist/v2/hidden-completion.d.ts.map +1 -1
- package/dist/v2/hooks/context.d.ts.map +1 -1
- package/dist/v2/hooks/hidden-child.d.ts +46 -2
- package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
- package/dist/v2/hooks/payload.d.ts.map +1 -1
- package/dist/v2/hooks/store.d.ts.map +1 -1
- package/dist/v2/hooks/tools.d.ts.map +1 -1
- package/dist/v2/hooks/types.d.ts +14 -0
- package/dist/v2/hooks/types.d.ts.map +1 -1
- package/dist/v2/server.js +13226 -11340
- package/dist/v2/store-reader.d.ts +16 -0
- package/dist/v2/store-reader.d.ts.map +1 -1
- package/dist/v2/tool-result.d.ts +8 -0
- package/dist/v2/tool-result.d.ts.map +1 -0
- package/dist/web/api.d.ts +6 -0
- package/dist/web/api.d.ts.map +1 -1
- package/dist/web/context-store.d.ts +13 -0
- package/dist/web/context-store.d.ts.map +1 -1
- package/dist/web/display-path.d.ts +28 -0
- package/dist/web/display-path.d.ts.map +1 -0
- package/dist/web/entry-args.d.ts +33 -0
- package/dist/web/entry-args.d.ts.map +1 -0
- package/dist/web/fixtures.d.ts +41 -0
- package/dist/web/fixtures.d.ts.map +1 -1
- package/dist/web/host-opencode.d.ts +9 -0
- package/dist/web/host-opencode.d.ts.map +1 -1
- package/dist/web/host-pi.d.ts +2 -0
- package/dist/web/host-pi.d.ts.map +1 -1
- package/dist/web/main.d.ts +4 -6
- package/dist/web/main.d.ts.map +1 -1
- package/dist/web/main.js +1477 -130
- package/dist/web/memories.d.ts +18 -2
- package/dist/web/memories.d.ts.map +1 -1
- package/dist/web/message-stats.d.ts +45 -0
- package/dist/web/message-stats.d.ts.map +1 -0
- package/dist/web/ui/index.html +1 -0
- package/dist/web/ui/panel.css +7 -0
- package/dist/web/ui/panel.js +332 -124
- package/dist/web/views.d.ts +73 -9
- package/dist/web/views.d.ts.map +1 -1
- package/dist/{wrapup-orchestrator-z9sqpqjf.js → wrapup-orchestrator-x9xamts2.js} +10 -9
- package/package.json +7 -2
- package/src/config/index.test.ts +257 -126
- package/src/config/index.ts +45 -39
- package/src/config/legacy-harness-blocks.test.ts +78 -0
- package/src/config/legacy-harness-blocks.ts +71 -0
- package/src/config/live-run-config.test.ts +49 -5
- package/src/config/live-run-config.ts +29 -0
- package/src/config/live-snapshot.ts +5 -1
- package/src/config/profiles.ts +1 -1
- package/src/config/project-config-trust-boundary.test.ts +2 -2
- package/src/config/project-security.hostile-matrix.test.ts +51 -65
- package/src/config/project-security.test.ts +6 -1
- package/src/config/project-security.ts +13 -12
- package/src/config/protected-tokens.test.ts +1 -1
- package/src/config/raw-loader.test.ts +29 -352
- package/src/config/raw-loader.ts +17 -406
- package/src/config/removed-config-keys.test.ts +1 -1
- package/src/config/schema/magic-context.test.ts +60 -64
- package/src/config/schema/magic-context.ts +105 -137
- package/src/config/variable.ts +21 -12
- package/src/shared/auto-search-lifecycle.ts +27 -0
- package/src/shared/cache-ttl-display.test.ts +1 -1
- package/src/shared/cache-ttl-display.ts +17 -16
- package/src/shared/harness.ts +1 -1
- package/src/shared/historian-tool-defaults.json +6 -6
- package/src/shared/historian-tool-expansions.ts +65 -8
- package/src/shared/historian-tool-preview-defaults.json +13 -0
- package/src/shared/historian-tool-template.ts +48 -14
- package/src/shared/model-cache-ttl.test.ts +2 -2
- package/src/shared/model-cache-ttl.ts +8 -4
- package/src/shared/model-resolution.test.ts +22 -32
- package/src/shared/model-resolution.ts +14 -19
- package/src/shared/model-suggestion-retry.ts +63 -7
- package/src/shared/protected-tools-policy.ts +25 -0
- package/src/shared/provider-output-failure.ts +176 -0
- package/src/shared/sqlite-acquisition-routing.test.ts +18 -0
- package/src/shared/sqlite.ts +100 -15
- package/src/shared/status-detail-text.test.ts +1 -1
- package/src/shared/status-view.test.ts +1 -1
- package/src/shared/temporal-upgrade-fixture.ts +50 -0
- package/src/shared/window-geometry.ts +10 -0
- package/src/shared/write-transaction-attribution.test.ts +2 -2
- package/src/shared/write-transaction-timing.ts +25 -1
- package/dist/features/magic-context/window-report-ledger.d.ts +0 -70
- package/dist/features/magic-context/window-report-ledger.d.ts.map +0 -1
- package/dist/index-e1q8002h.js +0 -16
- package/src/config/misplaced-agent-model.test.ts +0 -55
|
@@ -1,18 +1,75 @@
|
|
|
1
1
|
import defaults from "./historian-tool-defaults.json";
|
|
2
|
+
import previewDefaults from "./historian-tool-preview-defaults.json";
|
|
2
3
|
import { renderToolTemplate, type ToolExpansionMap } from "./historian-tool-template";
|
|
3
4
|
|
|
4
5
|
export { defaults as DEFAULT_TOOL_EXPANSIONS };
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
// Room actions, private-message addresses and board lanes have multiple input
|
|
8
|
+
// shapes. Derive readable labels only for built-ins; configured template overrides
|
|
9
|
+
// keep the unmodified tool input.
|
|
10
|
+
function builtinInput(tool: string, input: unknown): unknown {
|
|
11
|
+
if (!input || typeof input !== "object") return input;
|
|
12
|
+
const i = input as Record<string, unknown>;
|
|
13
|
+
if (tool === "peer_send") {
|
|
14
|
+
const external = i.external as Record<string, unknown> | undefined;
|
|
15
|
+
const recipient = i.reply_to_pmid
|
|
16
|
+
? `reply to ${i.reply_to_pmid}`
|
|
17
|
+
: i.agent || i.agent_id
|
|
18
|
+
? `to ${i.agent || i.agent_id}`
|
|
19
|
+
: external?.session_id || i.session_id
|
|
20
|
+
? `to session ${external?.session_id || i.session_id}`
|
|
21
|
+
: "to unknown recipient";
|
|
22
|
+
return { ...i, recipient };
|
|
23
|
+
}
|
|
24
|
+
if (tool === "room") {
|
|
25
|
+
return {
|
|
26
|
+
...i,
|
|
27
|
+
room_label: i.room_id || i.title,
|
|
28
|
+
room_detail:
|
|
29
|
+
i.action === "create" || i.action === "invite"
|
|
30
|
+
? `invitees: ${renderToolTemplate("${input.invitees}", i)}`
|
|
31
|
+
: i.text,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (tool === "board") {
|
|
35
|
+
return {
|
|
36
|
+
...i,
|
|
37
|
+
board_lane: i.lane ? ` ${i.lane}` : "",
|
|
38
|
+
ops: Array.isArray(i.ops)
|
|
39
|
+
? i.ops.map((op) =>
|
|
40
|
+
op && typeof op === "object"
|
|
41
|
+
? {
|
|
42
|
+
...op,
|
|
43
|
+
lane_label:
|
|
44
|
+
typeof op.lane === "string"
|
|
45
|
+
? op.lane
|
|
46
|
+
: op.lane?.title || op.lane?.id,
|
|
47
|
+
}
|
|
48
|
+
: op,
|
|
49
|
+
)
|
|
50
|
+
: i.ops,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return input;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function expandToolPart(
|
|
57
|
+
part: unknown,
|
|
58
|
+
overrides?: ToolExpansionMap,
|
|
59
|
+
legacyPreview = false,
|
|
60
|
+
): string | null {
|
|
6
61
|
if (!part || typeof part !== "object") return null;
|
|
7
62
|
const p = part as Record<string, unknown>;
|
|
8
63
|
if (p.type !== "tool" || typeof p.tool !== "string") return null;
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
64
|
+
const builtinDefaults = legacyPreview ? previewDefaults : defaults;
|
|
65
|
+
const overridden = overrides && Object.hasOwn(overrides, p.tool);
|
|
66
|
+
const template = overridden
|
|
67
|
+
? overrides[p.tool]
|
|
68
|
+
: Object.hasOwn(builtinDefaults, p.tool)
|
|
69
|
+
? builtinDefaults[p.tool as keyof typeof defaults]
|
|
70
|
+
: undefined;
|
|
15
71
|
if (typeof template !== "string") return null;
|
|
16
72
|
const state = p.state as Record<string, unknown> | undefined;
|
|
17
|
-
|
|
73
|
+
const input = overridden || legacyPreview ? state?.input : builtinInput(p.tool, state?.input);
|
|
74
|
+
return renderToolTemplate(template, input, state?.output ?? state?.error, legacyPreview);
|
|
18
75
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"todowrite": "Todos (${input.todos.count}): ${input.todos.each(\"${status}: ${content}\")}",
|
|
3
|
+
"question": "Asked user: ${input.questions[*].question.join(\" / \")} → ${output}",
|
|
4
|
+
"task": "Task ${input.subagent_type}: ${input.prompt} → ${output.truncate(200)}",
|
|
5
|
+
"ask": "Asked: ${input.question.truncate(250)} [options: ${input.options.join(\" / \")}] ${input.resolution} → ${output.truncate(300)}",
|
|
6
|
+
"peer_send": "PM to ${input.agent}${input.agent_id}: ${input.message.truncate(400)}",
|
|
7
|
+
"board": "Board ${input.verb}: ${input.ops.each(\"${op} ${item}${lane.title} ${state}${lane.status}${props.text} ${lane.items[*].text}\")}",
|
|
8
|
+
"room": "Room ${input.action} ${input.room_id}: ${input.text.truncate(400)}",
|
|
9
|
+
"work": "Work ${input.action} ${input.id}: ${input.prompt_file}${input.prompt.truncate(200)}${input.notes.truncate(200)} → ${output.truncate(160)}",
|
|
10
|
+
"knowhow": "Looked up how-to: ${input.query}${input.id}",
|
|
11
|
+
"mmc_note": "Note ${input.action} ${input.note_ids}: ${input.content} → ${output.truncate(160)}",
|
|
12
|
+
"mmc_memory": "Memory ${input.action} ${input.category} ${input.ids}: ${input.content} → ${output.truncate(160)}"
|
|
13
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** A deliberately non-executable language for readable
|
|
1
|
+
/** A deliberately non-executable language for readable historian tool lines. */
|
|
2
2
|
export type ToolExpansionMap = Record<string, string | false>;
|
|
3
3
|
type Step = { field: string } | { index: number } | { project: string };
|
|
4
4
|
type Expression = {
|
|
@@ -6,7 +6,7 @@ type Expression = {
|
|
|
6
6
|
each?: Template;
|
|
7
7
|
join?: string;
|
|
8
8
|
count?: boolean;
|
|
9
|
-
cap
|
|
9
|
+
cap?: number;
|
|
10
10
|
};
|
|
11
11
|
type Template = Array<string | Expression>;
|
|
12
12
|
|
|
@@ -78,7 +78,7 @@ class Parser {
|
|
|
78
78
|
if (this.source[this.pos] === "(") return this.error();
|
|
79
79
|
} else break;
|
|
80
80
|
}
|
|
81
|
-
const expression: Expression = { steps
|
|
81
|
+
const expression: Expression = { steps };
|
|
82
82
|
if (this.take(".each(")) {
|
|
83
83
|
if (relative) return this.error();
|
|
84
84
|
expression.each = parseTemplate(this.quoted(), true);
|
|
@@ -145,9 +145,24 @@ function compiled(source: string): Template | null {
|
|
|
145
145
|
function oneLine(value: string): string {
|
|
146
146
|
return value.replace(/[\r\n\u2028\u2029]+/g, " ");
|
|
147
147
|
}
|
|
148
|
-
function truncate(value: string, cap
|
|
148
|
+
function truncate(value: string, cap?: number, legacyPreview = false): string {
|
|
149
149
|
const chars = Array.from(oneLine(value));
|
|
150
|
-
|
|
150
|
+
if (cap === undefined || chars.length <= cap) return chars.join("");
|
|
151
|
+
if (legacyPreview) return `${chars.slice(0, cap).join("")}…`;
|
|
152
|
+
// Explicit caps stop after sentence-ending punctuation so a cut is not
|
|
153
|
+
// mistaken for an intact tool message. If no sentence fits, show only the marker.
|
|
154
|
+
let end = 0;
|
|
155
|
+
for (let i = 0; i < Math.min(cap, chars.length); i++) {
|
|
156
|
+
if (!".!?。!?".includes(chars[i])) continue;
|
|
157
|
+
let next = i + 1;
|
|
158
|
+
while (next < chars.length && "\"'”’)]".includes(chars[next])) next++;
|
|
159
|
+
if (
|
|
160
|
+
next <= cap &&
|
|
161
|
+
("。!?".includes(chars[i]) || next === chars.length || /[ \t]/.test(chars[next]))
|
|
162
|
+
)
|
|
163
|
+
end = next;
|
|
164
|
+
}
|
|
165
|
+
return `${end ? `${chars.slice(0, end).join("")} ` : ""}[… ${chars.length - end} more characters]`;
|
|
151
166
|
}
|
|
152
167
|
function scalar(value: unknown): string {
|
|
153
168
|
if (value === undefined) return "";
|
|
@@ -174,10 +189,11 @@ function field(value: unknown, key: string): unknown {
|
|
|
174
189
|
? (value as Record<string, unknown>)[key]
|
|
175
190
|
: undefined;
|
|
176
191
|
}
|
|
177
|
-
function render(nodes: Template, root: unknown): string {
|
|
192
|
+
function render(nodes: Template, root: unknown, legacyPreview: boolean): string {
|
|
178
193
|
return nodes
|
|
179
194
|
.map((node) => {
|
|
180
195
|
if (typeof node === "string") return node;
|
|
196
|
+
const cap = node.cap ?? (legacyPreview ? 300 : undefined);
|
|
181
197
|
let value = root;
|
|
182
198
|
let list = false;
|
|
183
199
|
for (const step of node.steps) {
|
|
@@ -196,18 +212,31 @@ function render(nodes: Template, root: unknown): string {
|
|
|
196
212
|
}
|
|
197
213
|
}
|
|
198
214
|
if (node.count)
|
|
199
|
-
return truncate(
|
|
215
|
+
return truncate(
|
|
216
|
+
Array.isArray(value) ? String(value.length) : "",
|
|
217
|
+
cap,
|
|
218
|
+
legacyPreview,
|
|
219
|
+
);
|
|
200
220
|
if (node.each || list || node.join !== undefined) {
|
|
201
221
|
if (!Array.isArray(value)) return "";
|
|
202
222
|
const elements = value
|
|
203
|
-
.slice(0, 10)
|
|
223
|
+
.slice(0, legacyPreview ? 10 : undefined)
|
|
204
224
|
.map((item) =>
|
|
205
|
-
truncate(
|
|
225
|
+
truncate(
|
|
226
|
+
node.each ? render(node.each, item, legacyPreview) : scalar(item),
|
|
227
|
+
legacyPreview ? 300 : undefined,
|
|
228
|
+
legacyPreview,
|
|
229
|
+
),
|
|
206
230
|
);
|
|
207
|
-
if (
|
|
208
|
-
|
|
231
|
+
if (legacyPreview && value.length > 10)
|
|
232
|
+
elements.push(`… +${value.length - 10} more`);
|
|
233
|
+
return truncate(
|
|
234
|
+
elements.join(node.join ?? (node.each ? "; " : ", ")),
|
|
235
|
+
cap,
|
|
236
|
+
legacyPreview,
|
|
237
|
+
);
|
|
209
238
|
}
|
|
210
|
-
return truncate(scalar(value),
|
|
239
|
+
return truncate(scalar(value), cap, legacyPreview);
|
|
211
240
|
})
|
|
212
241
|
.join("");
|
|
213
242
|
}
|
|
@@ -216,6 +245,7 @@ export function renderToolTemplate(
|
|
|
216
245
|
source: string,
|
|
217
246
|
input: unknown,
|
|
218
247
|
output?: unknown,
|
|
248
|
+
legacyPreview = false,
|
|
219
249
|
): string | null {
|
|
220
250
|
const nodes = compiled(source);
|
|
221
251
|
if (!nodes) return null;
|
|
@@ -241,8 +271,12 @@ export function renderToolTemplate(
|
|
|
241
271
|
!node.each &&
|
|
242
272
|
!node.count &&
|
|
243
273
|
node.join === undefined
|
|
244
|
-
? truncate(text ?? "", node.cap)
|
|
274
|
+
? truncate(text ?? "", node.cap ?? (legacyPreview ? 300 : undefined), legacyPreview)
|
|
245
275
|
: node,
|
|
246
276
|
);
|
|
247
|
-
return truncate(
|
|
277
|
+
return truncate(
|
|
278
|
+
render(bareOutputNodes, root, legacyPreview),
|
|
279
|
+
legacyPreview ? 1000 : undefined,
|
|
280
|
+
legacyPreview,
|
|
281
|
+
);
|
|
248
282
|
}
|
|
@@ -29,8 +29,8 @@ describe("known model cache TTL", () => {
|
|
|
29
29
|
expect(resolveCacheTtl("5m", "openai/gpt-6")).toBe("30m");
|
|
30
30
|
expect(resolveCacheTtl("10m", "openai/gpt-6")).toBe("10m");
|
|
31
31
|
});
|
|
32
|
-
it("honors per-model entries
|
|
33
|
-
expect(resolveCacheTtl({ default: "10m" }, "openai/gpt-6")).toBe("
|
|
32
|
+
it("honors per-model entries and configured defaults before built-ins", () => {
|
|
33
|
+
expect(resolveCacheTtl({ default: "10m" }, "openai/gpt-6")).toBe("10m");
|
|
34
34
|
expect(resolveCacheTtl({ default: "10m", "gpt-6": "5m" }, "openai/gpt-6")).toBe("5m");
|
|
35
35
|
expect(resolveCacheTtl({ default: "10m", "openai/*": "never" }, "openai/gpt-6")).toBe(
|
|
36
36
|
"never",
|
|
@@ -28,6 +28,8 @@ const MODEL_CACHE_LIFETIMES = [
|
|
|
28
28
|
export function resolveModelCacheTtl(
|
|
29
29
|
config: CacheTtlConfig | undefined,
|
|
30
30
|
modelKey: string | undefined,
|
|
31
|
+
configuredExplicitly = typeof config === "object" ||
|
|
32
|
+
(typeof config === "string" && config !== "5m"),
|
|
31
33
|
): ResolvedCacheTtl {
|
|
32
34
|
if (config && typeof config !== "string") {
|
|
33
35
|
const match =
|
|
@@ -37,11 +39,13 @@ export function resolveModelCacheTtl(
|
|
|
37
39
|
modelKey !== "default"
|
|
38
40
|
? config[modelKey]
|
|
39
41
|
: resolveModelConfigValue(config, modelKey)?.value;
|
|
40
|
-
|
|
42
|
+
const value = match ?? config.default;
|
|
43
|
+
if (value !== undefined && configuredExplicitly)
|
|
44
|
+
return { value, source: "config", modelKey };
|
|
41
45
|
}
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
if (typeof config === "string" &&
|
|
46
|
+
// The loader supplies provenance: an explicit 5m is policy too. Older callers
|
|
47
|
+
// without that bit still distinguish non-default strings from the schema's 5m.
|
|
48
|
+
if (typeof config === "string" && configuredExplicitly)
|
|
45
49
|
return { value: config, source: "config", modelKey };
|
|
46
50
|
const model =
|
|
47
51
|
canonicalModelIdentity(modelKey ?? "")
|
|
@@ -18,8 +18,9 @@ describe("model-resolution", () => {
|
|
|
18
18
|
const resolved = resolveHistorianAgentOverrides({
|
|
19
19
|
...(fixture.temperature !== undefined ? { temperature: fixture.temperature } : {}),
|
|
20
20
|
maxTokens: 16_000,
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
model: "google/flash",
|
|
22
|
+
variant: "low",
|
|
23
|
+
thinking_level: "high",
|
|
23
24
|
});
|
|
24
25
|
expect(resolved).toEqual({
|
|
25
26
|
maxTokens: 16_000,
|
|
@@ -61,8 +62,7 @@ describe("model-resolution", () => {
|
|
|
61
62
|
test("keeps the flash calibration available only as an explicit override", () => {
|
|
62
63
|
expect(
|
|
63
64
|
resolveHistorianAgentOverrides({
|
|
64
|
-
|
|
65
|
-
pi: { model: "pi/ignored" },
|
|
65
|
+
model: { model: "google/flash", variant: "fast" },
|
|
66
66
|
two_pass: true,
|
|
67
67
|
}),
|
|
68
68
|
).toEqual({
|
|
@@ -76,56 +76,46 @@ describe("model-resolution", () => {
|
|
|
76
76
|
).toMatchObject({ temperature: 0.1, maxTokens: 12_000 });
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
test("does not inherit
|
|
79
|
+
test("does not inherit the primary qualifier into unqualified fallbacks", () => {
|
|
80
80
|
const config = {
|
|
81
81
|
historian: {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
},
|
|
87
|
-
pi: {
|
|
88
|
-
model: "pi/primary",
|
|
89
|
-
fallback_models: ["pi/fallback"],
|
|
90
|
-
thinking_level: "high",
|
|
91
|
-
},
|
|
82
|
+
model: "open/primary",
|
|
83
|
+
fallback_models: ["open/fallback"],
|
|
84
|
+
variant: "primary-only",
|
|
85
|
+
thinking_level: "high",
|
|
92
86
|
},
|
|
93
87
|
};
|
|
94
88
|
|
|
95
89
|
// Inheritance is deliberately absent because a fallback model may not support the
|
|
96
|
-
// qualifier selected for the primary model.
|
|
90
|
+
// qualifier selected for the primary model. Each harness reads only its own
|
|
91
|
+
// qualifier (OpenCode variant, Pi thinking_level) from the flat entry.
|
|
97
92
|
expect(resolveHistorianModel(config, "opencode")).toEqual({
|
|
98
93
|
primary: { model: "open/primary", qualifier: "primary-only" },
|
|
99
94
|
fallbacks: [{ model: "open/fallback" }],
|
|
100
95
|
});
|
|
101
96
|
expect(resolveHistorianModel(config, "pi")).toEqual({
|
|
102
|
-
primary: { model: "
|
|
103
|
-
fallbacks: [{ model: "
|
|
97
|
+
primary: { model: "open/primary", qualifier: "high" },
|
|
98
|
+
fallbacks: [{ model: "open/fallback" }],
|
|
104
99
|
});
|
|
105
100
|
});
|
|
106
101
|
|
|
107
|
-
test("
|
|
102
|
+
test("selects the requested harness's qualifier from a shared flat entry", () => {
|
|
108
103
|
const config = {
|
|
109
104
|
historian: {
|
|
110
|
-
model: "
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
},
|
|
115
|
-
pi: {
|
|
116
|
-
model: { model: "pi/model", thinking_level: "high" },
|
|
117
|
-
fallback_models: [{ model: "pi/fallback", thinking_level: "max" }],
|
|
118
|
-
},
|
|
105
|
+
model: { model: "shared/model", variant: "oc-primary", thinking_level: "high" },
|
|
106
|
+
fallback_models: [
|
|
107
|
+
{ model: "shared/fallback", variant: "oc-fallback", thinking_level: "max" },
|
|
108
|
+
],
|
|
119
109
|
},
|
|
120
110
|
};
|
|
121
111
|
|
|
122
112
|
expect(resolveHistorianModel(config, "opencode")).toEqual({
|
|
123
|
-
primary: { model: "
|
|
124
|
-
fallbacks: [{ model: "
|
|
113
|
+
primary: { model: "shared/model", qualifier: "oc-primary" },
|
|
114
|
+
fallbacks: [{ model: "shared/fallback", qualifier: "oc-fallback" }],
|
|
125
115
|
});
|
|
126
116
|
expect(resolveHistorianModel(config, "pi")).toEqual({
|
|
127
|
-
primary: { model: "
|
|
128
|
-
fallbacks: [{ model: "
|
|
117
|
+
primary: { model: "shared/model", qualifier: "high" },
|
|
118
|
+
fallbacks: [{ model: "shared/fallback", qualifier: "max" }],
|
|
129
119
|
});
|
|
130
120
|
expect(resolveHistorianModel({}, "pi")).toEqual({ fallbacks: [] });
|
|
131
121
|
});
|
|
@@ -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. */
|
|
@@ -23,13 +23,6 @@ function readString(value: unknown): string | undefined {
|
|
|
23
23
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
function resolveHarnessBlock(
|
|
27
|
-
container: ConfigRecord | undefined,
|
|
28
|
-
harness: ModelHarness,
|
|
29
|
-
): ConfigRecord | undefined {
|
|
30
|
-
return asRecord(container?.[harness]);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
26
|
/**
|
|
34
27
|
* Collapses the string and object spellings of a harness model entry into the
|
|
35
28
|
* same model identity. Qualifiers stay separate because they alter an attempt,
|
|
@@ -101,29 +94,31 @@ export interface ResolvedHistorianModel {
|
|
|
101
94
|
}
|
|
102
95
|
|
|
103
96
|
/**
|
|
104
|
-
* Resolve historian model attempts from the
|
|
97
|
+
* Resolve historian model attempts from the flat historian config. The harness
|
|
98
|
+
* parameter selects which qualifier is read: OpenCode uses `variant`, Pi uses
|
|
99
|
+
* `thinking_level`. The other harness's qualifier is ignored (no cross-harness
|
|
100
|
+
* mapping).
|
|
105
101
|
*/
|
|
106
102
|
export function resolveHistorianModel(
|
|
107
103
|
config: unknown,
|
|
108
104
|
harness: ModelHarness,
|
|
109
105
|
): ResolvedHistorianModel {
|
|
110
106
|
const historian = asRecord(asRecord(config)?.historian);
|
|
111
|
-
|
|
112
|
-
if (!block) return { fallbacks: [] };
|
|
107
|
+
if (!historian) return { fallbacks: [] };
|
|
113
108
|
|
|
114
109
|
return {
|
|
115
110
|
primary: resolvePrimaryEntry({
|
|
116
|
-
entry:
|
|
117
|
-
defaultQualifier:
|
|
111
|
+
entry: historian.model,
|
|
112
|
+
defaultQualifier: historian[harness === "opencode" ? "variant" : "thinking_level"],
|
|
118
113
|
harness,
|
|
119
114
|
}),
|
|
120
|
-
fallbacks: resolveFallbackEntries(
|
|
115
|
+
fallbacks: resolveFallbackEntries(historian.fallback_models, harness),
|
|
121
116
|
};
|
|
122
117
|
}
|
|
123
118
|
|
|
124
119
|
/**
|
|
125
120
|
* Keep non-model agent settings at their original level while replacing only
|
|
126
|
-
* OpenCode's model-resolution fields with the
|
|
121
|
+
* OpenCode's model-resolution fields with the flat primary entry.
|
|
127
122
|
*/
|
|
128
123
|
export function resolveOpenCodeAgentOverrides(agent: unknown): Record<string, unknown> {
|
|
129
124
|
const source = asRecord(agent);
|
|
@@ -133,14 +128,14 @@ export function resolveOpenCodeAgentOverrides(agent: unknown): Record<string, un
|
|
|
133
128
|
fallback_models: _fallbackModels,
|
|
134
129
|
variant: _variant,
|
|
135
130
|
thinking_level: _thinking,
|
|
136
|
-
opencode,
|
|
137
|
-
pi,
|
|
131
|
+
opencode: _opencode,
|
|
132
|
+
pi: _pi,
|
|
138
133
|
tasks,
|
|
139
134
|
...rest
|
|
140
135
|
} = source;
|
|
141
136
|
const primary = resolvePrimaryEntry({
|
|
142
|
-
entry:
|
|
143
|
-
defaultQualifier:
|
|
137
|
+
entry: source.model,
|
|
138
|
+
defaultQualifier: source.variant,
|
|
144
139
|
harness: "opencode",
|
|
145
140
|
});
|
|
146
141
|
return {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { createOpencodeClient } from "@opencode-ai/sdk";
|
|
2
|
-
|
|
3
2
|
import { detectOverflow } from "../features/magic-context/overflow-detection";
|
|
4
3
|
import { HiddenCompletionRefusal } from "../hooks/magic-context/compartment-runner-types";
|
|
5
4
|
import { HiddenAgentStepLimit } from "../v2/hooks/hidden-child";
|
|
@@ -11,6 +10,12 @@ import {
|
|
|
11
10
|
} from "./assistant-message-extractor";
|
|
12
11
|
import { log } from "./logger";
|
|
13
12
|
import type { ModelInput } from "./model-resolution";
|
|
13
|
+
import {
|
|
14
|
+
ProviderOutputFailureError,
|
|
15
|
+
primaryQuotaFailure,
|
|
16
|
+
providerOutputFailureFromInvalidManifest,
|
|
17
|
+
rememberPrimaryQuota,
|
|
18
|
+
} from "./provider-output-failure";
|
|
14
19
|
import { sanitizeDiagnosticText } from "./redaction";
|
|
15
20
|
import { parseProviderModel, toModelEntry } from "./resolve-fallbacks";
|
|
16
21
|
|
|
@@ -59,6 +64,8 @@ export interface PromptAttemptInfo {
|
|
|
59
64
|
totalAttempts: number;
|
|
60
65
|
/** Explicit model override for this attempt, when one was supplied. */
|
|
61
66
|
model?: { providerID: string; modelID: string };
|
|
67
|
+
/** A run-local quota deadline prevented dispatch; not an actual model call. */
|
|
68
|
+
skipped?: boolean;
|
|
62
69
|
}
|
|
63
70
|
|
|
64
71
|
export interface PromptRetryOptions {
|
|
@@ -433,14 +440,25 @@ function throwWithPromptFailure(
|
|
|
433
440
|
legacyError instanceof Error ? legacyError : new Error(extractMessage(legacyError));
|
|
434
441
|
const last = failedAttempts.at(-1);
|
|
435
442
|
const failureClass = last?.failureClass ?? "unknown";
|
|
443
|
+
const quota = failedAttempts.find(
|
|
444
|
+
(failure) =>
|
|
445
|
+
failure.error instanceof ProviderOutputFailureError &&
|
|
446
|
+
failure.error.quotaResetAt !== undefined,
|
|
447
|
+
)?.error as ProviderOutputFailureError | undefined;
|
|
448
|
+
if (quota && error !== quota && !error.message.includes(quota.message))
|
|
449
|
+
error.message = `${quota.message}; ${error.message}`;
|
|
436
450
|
const providerError =
|
|
437
|
-
failureClass === "provider_error"
|
|
438
|
-
? sanitizeDiagnosticText(
|
|
451
|
+
failureClass === "provider_error" || quota
|
|
452
|
+
? sanitizeDiagnosticText(
|
|
453
|
+
`${quota ? `${quota.message}; ` : ""}${shortErr(last?.error ?? legacyError)}`,
|
|
454
|
+
).slice(0, 500)
|
|
439
455
|
: null;
|
|
440
456
|
promptFailureDetails.set(error, {
|
|
441
457
|
failureClass,
|
|
442
458
|
modelAttempted: last?.attempt.label ?? null,
|
|
443
|
-
modelsTried: failedAttempts
|
|
459
|
+
modelsTried: failedAttempts
|
|
460
|
+
.filter((failure) => !failure.attempt.skipped)
|
|
461
|
+
.map((failure) => failure.attempt.label),
|
|
444
462
|
providerError,
|
|
445
463
|
timeoutMs: failureClass === "provider_timeout" ? timeoutMs : null,
|
|
446
464
|
childSessionId: transport ? (transport.childSessionId ?? null) : args.path.id || null,
|
|
@@ -664,6 +682,16 @@ async function attemptAndValidate<TOutput, TValidated>(
|
|
|
664
682
|
}
|
|
665
683
|
|
|
666
684
|
try {
|
|
685
|
+
// Only the structured account-pool notice bypasses caller validation.
|
|
686
|
+
// The near-zero-token heuristic remains owned by manifest callers.
|
|
687
|
+
const messages = Array.isArray(output)
|
|
688
|
+
? output
|
|
689
|
+
: (output as { messages?: unknown } | null)?.messages;
|
|
690
|
+
const text = extractLatestAssistantText(messages);
|
|
691
|
+
if (text) {
|
|
692
|
+
const failure = providerOutputFailureFromInvalidManifest(messages, text);
|
|
693
|
+
if (failure?.quotaResetAt !== undefined) throw failure;
|
|
694
|
+
}
|
|
667
695
|
if (!extractLatestAssistantText(output)) {
|
|
668
696
|
const assistantFailure = extractLatestAssistantFailure(output);
|
|
669
697
|
if (assistantFailure) {
|
|
@@ -718,8 +746,22 @@ export async function promptSyncWithValidatedOutputRetry<TOutput, TValidated = T
|
|
|
718
746
|
const failedAttempts: FailedAttempt[] = [];
|
|
719
747
|
let firstError: unknown = null;
|
|
720
748
|
let lastError: unknown = null;
|
|
749
|
+
const cooledPrimary = primaryQuotaFailure(explicitPrimaryLabel);
|
|
721
750
|
|
|
722
751
|
try {
|
|
752
|
+
if (cooledPrimary)
|
|
753
|
+
throw {
|
|
754
|
+
error: cooledPrimary,
|
|
755
|
+
failureClass: "provider_error",
|
|
756
|
+
attempt: {
|
|
757
|
+
label: explicitPrimaryLabel,
|
|
758
|
+
attemptIndex: 0,
|
|
759
|
+
isFallback: false,
|
|
760
|
+
totalAttempts,
|
|
761
|
+
model: baseBody.model,
|
|
762
|
+
skipped: true,
|
|
763
|
+
},
|
|
764
|
+
} satisfies FailedAttempt;
|
|
723
765
|
return await attemptAndValidate(
|
|
724
766
|
client,
|
|
725
767
|
baseArgs,
|
|
@@ -739,6 +781,19 @@ export async function promptSyncWithValidatedOutputRetry<TOutput, TValidated = T
|
|
|
739
781
|
const failure = caught as FailedAttempt;
|
|
740
782
|
failedAttempts.push(failure);
|
|
741
783
|
firstError = failure.error;
|
|
784
|
+
if (
|
|
785
|
+
failure.error instanceof ProviderOutputFailureError &&
|
|
786
|
+
failure.error.quotaResetAt !== undefined
|
|
787
|
+
)
|
|
788
|
+
failure.error.message = failure.error.message.replace(
|
|
789
|
+
/^provider quota exhausted/,
|
|
790
|
+
"primary quota exhausted",
|
|
791
|
+
);
|
|
792
|
+
const quota = !cooledPrimary && rememberPrimaryQuota(explicitPrimaryLabel, failure.error);
|
|
793
|
+
if (quota)
|
|
794
|
+
log(
|
|
795
|
+
`[${callContext}] ${quota.message}; skipping ${explicitPrimaryLabel} for this run until reset`,
|
|
796
|
+
);
|
|
742
797
|
lastError = failure.error;
|
|
743
798
|
if (isNonRetryable(failure.error, options.signal)) {
|
|
744
799
|
throwWithPromptFailure(
|
|
@@ -760,9 +815,10 @@ export async function promptSyncWithValidatedOutputRetry<TOutput, TValidated = T
|
|
|
760
815
|
);
|
|
761
816
|
}
|
|
762
817
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
818
|
+
if (!cooledPrimary && !quota)
|
|
819
|
+
log(
|
|
820
|
+
`[${callContext}] primary (${explicitPrimaryLabel}) failed validation/prompt: ${shortErr(failure.error)}; trying ${fallbacks.length} fallback(s)`,
|
|
821
|
+
);
|
|
766
822
|
}
|
|
767
823
|
|
|
768
824
|
for (let i = 0; i < fallbacks.length; i += 1) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Default result keep counts shared by runtime and configuration. */
|
|
2
|
+
export const DEFAULT_PROTECTED_TOOLS: Readonly<Record<string, number>> = {
|
|
3
|
+
todowrite: 1,
|
|
4
|
+
// The fork's tool name; upstream's ctx_reduce alias merges onto the same key.
|
|
5
|
+
mmc_reduce: 3,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function normalizeProtectedToolName(name: string | null): string {
|
|
9
|
+
const lowered = (name ?? "").toLowerCase().replace(/^mcp_/, "");
|
|
10
|
+
return lowered === "ctx_reduce" ? "mmc_reduce" : lowered;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Normalize before merging tiers so aliases cannot defeat a project override. */
|
|
14
|
+
export function mergeProtectedTools(
|
|
15
|
+
...maps: (Readonly<Record<string, number>> | undefined)[]
|
|
16
|
+
): Record<string, number> {
|
|
17
|
+
return Object.fromEntries(
|
|
18
|
+
[DEFAULT_PROTECTED_TOOLS, ...maps].flatMap((map) =>
|
|
19
|
+
Object.entries(map ?? {}).map(([name, count]) => [
|
|
20
|
+
normalizeProtectedToolName(name),
|
|
21
|
+
count,
|
|
22
|
+
]),
|
|
23
|
+
),
|
|
24
|
+
);
|
|
25
|
+
}
|