@retaw106/mmc-oc 1.2.3 → 2.0.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-95zkksn3.js} +2471 -2438
- 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/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/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-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 +15 -2
- 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/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-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 +30 -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/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/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/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-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-wgt4gamw.js → index-1mjhzqq7.js} +422 -31
- package/dist/index-33gprt9g.js +30 -0
- package/dist/{index-zx63j2e2.js → index-5cep2r9n.js} +3 -2
- package/dist/{index-by6h2pav.js → index-bdt9my9y.js} +374 -239
- package/dist/{index-3wagyrnj.js → index-x37vg474.js} +5 -1
- package/dist/{index-1vs6anwz.js → index-xt7y10x6.js} +2 -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-zfernxbw.js} +1 -1
- 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-hp464g13.js} +2 -2
- package/dist/{recomp-orchestrator-gyeevxaw.js → recomp-orchestrator-3qxeqwb9.js} +6 -6
- 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/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 +5 -2
- 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/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-reduce/tools.d.ts +2 -0
- package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
- 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 +13 -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 +8 -0
- package/dist/v2/hooks/types.d.ts.map +1 -1
- package/dist/v2/server.js +4540 -3889
- 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/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 +772 -77
- 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 +5 -0
- package/dist/web/ui/panel.js +220 -70
- package/dist/web/views.d.ts +23 -0
- package/dist/web/views.d.ts.map +1 -1
- package/dist/{wrapup-orchestrator-z9sqpqjf.js → wrapup-orchestrator-wgb2nd19.js} +7 -6
- 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 +1 -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/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 +13 -18
- 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/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-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
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { isValidLanguageCode } from "../../agents/language-directive";
|
|
3
3
|
import { toolTemplateError } from "../../shared/historian-tool-template";
|
|
4
4
|
import { isValidPromptSurfaceModelKey } from "../../shared/prompt-surface";
|
|
5
|
+
import { DEFAULT_PROTECTED_TOOLS, mergeProtectedTools } from "../../shared/protected-tools-policy";
|
|
5
6
|
import { AgentOverrideConfigSchema } from "./agent-overrides";
|
|
6
7
|
|
|
7
8
|
export const DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65;
|
|
@@ -96,131 +97,66 @@ export const PromptSurfaceConfigSchema = z
|
|
|
96
97
|
export type PromptSurfaceConfig = z.infer<typeof PromptSurfaceConfigSchema>;
|
|
97
98
|
|
|
98
99
|
/**
|
|
99
|
-
* The flat model-resolution fields
|
|
100
|
-
*
|
|
101
|
-
*
|
|
100
|
+
* The flat historian model-resolution fields. This is the exhaustive contract
|
|
101
|
+
* for what a project-tier (repo-supplied) config must never set: the model, its
|
|
102
|
+
* fallbacks, and the per-harness qualifiers (OpenCode `variant`, Pi
|
|
103
|
+
* `thinking_level`) all merge onto the user's historian model at resolve time,
|
|
104
|
+
* so a cloned repo could otherwise force extra variant/thinking spend.
|
|
102
105
|
*/
|
|
103
|
-
export const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
"tools",
|
|
110
|
-
"disable",
|
|
111
|
-
"description",
|
|
112
|
-
"mode",
|
|
113
|
-
"color",
|
|
114
|
-
"maxSteps",
|
|
115
|
-
"permission",
|
|
116
|
-
"maxTokens",
|
|
117
|
-
"two_pass",
|
|
118
|
-
"disallowed_tools",
|
|
119
|
-
],
|
|
120
|
-
migrated_execution: ["model", "fallback_models", "variant", "thinking_level"],
|
|
121
|
-
},
|
|
122
|
-
} as const;
|
|
106
|
+
export const HISTORIAN_MODEL_RESOLUTION_FIELDS = [
|
|
107
|
+
"model",
|
|
108
|
+
"fallback_models",
|
|
109
|
+
"variant",
|
|
110
|
+
"thinking_level",
|
|
111
|
+
] as const;
|
|
123
112
|
|
|
124
|
-
/**
|
|
125
|
-
|
|
113
|
+
/**
|
|
114
|
+
* The removed per-harness historian model blocks. They are no longer part of
|
|
115
|
+
* the schema; this list exists only so the loaders can detect them and REJECT
|
|
116
|
+
* the config file loudly (a parse failure → defaults / last-known-good) instead
|
|
117
|
+
* of letting Zod silently strip them (which would leave the historian with no
|
|
118
|
+
* model and look "configured but never running").
|
|
119
|
+
*/
|
|
120
|
+
export const LEGACY_HARNESS_BLOCK_KEYS = ["opencode", "pi"] as const;
|
|
126
121
|
|
|
127
|
-
/**
|
|
128
|
-
|
|
122
|
+
/**
|
|
123
|
+
* A historian model entry: either a bare model ID string, or an object that may
|
|
124
|
+
* carry the OpenCode `variant` and/or the Pi `thinking_level` qualifier. The
|
|
125
|
+
* active harness reads only its own qualifier and ignores the other; there is
|
|
126
|
+
* no cross-harness mapping.
|
|
127
|
+
*/
|
|
128
|
+
const HistorianModelEntryObjectSchema = z
|
|
129
129
|
.object({
|
|
130
|
-
model: z.string().describe("
|
|
130
|
+
model: z.string().describe("Model ID (for example, provider/model)."),
|
|
131
131
|
variant: z.string().optional().describe("OpenCode reasoning variant for this entry."),
|
|
132
|
-
})
|
|
133
|
-
.strict();
|
|
134
|
-
export const OcEntrySchema = z.union([z.string(), OcEntryObjectSchema]);
|
|
135
|
-
export type OcEntry = z.infer<typeof OcEntrySchema>;
|
|
136
|
-
|
|
137
|
-
/** Pi entry objects permit `thinking_level` and reject OpenCode-only `variant`. */
|
|
138
|
-
const PiEntryObjectSchema = z
|
|
139
|
-
.object({
|
|
140
|
-
model: z.string().describe("Pi model ID (for example, provider/model)."),
|
|
141
132
|
thinking_level: PiThinkingLevelSchema.describe("Pi thinking level for this entry."),
|
|
142
133
|
})
|
|
143
134
|
.strict();
|
|
144
|
-
export const
|
|
145
|
-
export type
|
|
146
|
-
|
|
147
|
-
/** Strict model-resolution block used by historian.opencode. */
|
|
148
|
-
export const OpenCodeHarnessBlockSchema = z
|
|
149
|
-
.object({
|
|
150
|
-
model: OcEntrySchema.optional().describe("Primary OpenCode model entry."),
|
|
151
|
-
fallback_models: z
|
|
152
|
-
.array(OcEntrySchema)
|
|
153
|
-
.optional()
|
|
154
|
-
.describe(
|
|
155
|
-
"Ordered fallback OpenCode entries. New-shape configuration requires an array; legacy singleton values migrate to a one-element array.",
|
|
156
|
-
),
|
|
157
|
-
variant: z
|
|
158
|
-
.string()
|
|
159
|
-
.optional()
|
|
160
|
-
.describe(
|
|
161
|
-
"OpenCode reasoning variant for the primary entry when it declares none. Fallback entries declare variants per-entry.",
|
|
162
|
-
),
|
|
163
|
-
})
|
|
164
|
-
.strict()
|
|
165
|
-
.describe("Strict OpenCode model-resolution block. It accepts no Pi vocabulary.");
|
|
166
|
-
export type OpenCodeHarnessBlock = z.infer<typeof OpenCodeHarnessBlockSchema>;
|
|
167
|
-
|
|
168
|
-
/** Strict model-resolution block used by historian.pi. */
|
|
169
|
-
export const PiHarnessBlockSchema = z
|
|
170
|
-
.object({
|
|
171
|
-
model: PiEntrySchema.optional().describe("Primary Pi model entry."),
|
|
172
|
-
fallback_models: z
|
|
173
|
-
.array(PiEntrySchema)
|
|
174
|
-
.optional()
|
|
175
|
-
.describe(
|
|
176
|
-
"Ordered fallback Pi entries. New-shape configuration requires an array; legacy singleton values migrate to a one-element array.",
|
|
177
|
-
),
|
|
178
|
-
thinking_level: PiThinkingLevelSchema.describe(
|
|
179
|
-
"Pi thinking level for the primary entry when it declares none. Fallback entries declare thinking levels per-entry.",
|
|
180
|
-
),
|
|
181
|
-
})
|
|
182
|
-
.strict()
|
|
183
|
-
.describe("Strict Pi model-resolution block. It accepts no OpenCode vocabulary.");
|
|
184
|
-
export type PiHarnessBlock = z.infer<typeof PiHarnessBlockSchema>;
|
|
135
|
+
export const HistorianModelEntrySchema = z.union([z.string(), HistorianModelEntryObjectSchema]);
|
|
136
|
+
export type HistorianModelEntry = z.infer<typeof HistorianModelEntrySchema>;
|
|
185
137
|
|
|
186
138
|
/**
|
|
187
|
-
* A profile may select models but must not alter execution policy.
|
|
188
|
-
*
|
|
189
|
-
*
|
|
139
|
+
* A profile may select models but must not alter execution policy. It uses the
|
|
140
|
+
* same flat historian model-resolution fields; execution metadata is not
|
|
141
|
+
* allowed here.
|
|
190
142
|
*/
|
|
191
|
-
const
|
|
143
|
+
const ProfileHistorianSchema = z
|
|
192
144
|
.object({
|
|
193
|
-
model:
|
|
145
|
+
model: HistorianModelEntrySchema.optional().describe("Primary historian model entry."),
|
|
194
146
|
fallback_models: z
|
|
195
|
-
.array(
|
|
147
|
+
.array(HistorianModelEntrySchema)
|
|
196
148
|
.optional()
|
|
197
|
-
.describe("Ordered fallback
|
|
149
|
+
.describe("Ordered fallback historian model entries."),
|
|
198
150
|
variant: z
|
|
199
151
|
.string()
|
|
200
152
|
.optional()
|
|
201
|
-
.describe("OpenCode reasoning variant for the primary
|
|
202
|
-
})
|
|
203
|
-
.strict()
|
|
204
|
-
.describe("Strict profile-only OpenCode model-selection block.");
|
|
205
|
-
const ProfilePiModelBlockSchema = z
|
|
206
|
-
.object({
|
|
207
|
-
model: PiEntrySchema.optional().describe("Primary Pi model entry."),
|
|
208
|
-
fallback_models: z
|
|
209
|
-
.array(PiEntrySchema)
|
|
210
|
-
.optional()
|
|
211
|
-
.describe("Ordered fallback Pi model entries."),
|
|
153
|
+
.describe("OpenCode reasoning variant for the primary entry. Ignored by Pi."),
|
|
212
154
|
thinking_level: PiThinkingLevelSchema.describe(
|
|
213
|
-
"Pi thinking level for the primary
|
|
155
|
+
"Pi thinking level for the primary entry. Ignored by OpenCode.",
|
|
214
156
|
),
|
|
215
157
|
})
|
|
216
158
|
.strict()
|
|
217
|
-
.describe("Strict profile-only
|
|
218
|
-
const ProfileHistorianSchema = z
|
|
219
|
-
.object({
|
|
220
|
-
opencode: ProfileOpenCodeModelBlockSchema.optional(),
|
|
221
|
-
pi: ProfilePiModelBlockSchema.optional(),
|
|
222
|
-
})
|
|
223
|
-
.strict();
|
|
159
|
+
.describe("Strict profile-only historian model-selection block.");
|
|
224
160
|
|
|
225
161
|
export const ConfigProfileSchema = z
|
|
226
162
|
.object({
|
|
@@ -228,7 +164,7 @@ export const ConfigProfileSchema = z
|
|
|
228
164
|
})
|
|
229
165
|
.strict()
|
|
230
166
|
.describe(
|
|
231
|
-
"User-owned model-selection overlay. Only historian
|
|
167
|
+
"User-owned model-selection overlay. Only the flat historian model-resolution fields are allowed.",
|
|
232
168
|
);
|
|
233
169
|
export type ConfigProfile = z.infer<typeof ConfigProfileSchema>;
|
|
234
170
|
|
|
@@ -253,8 +189,10 @@ const AgentMetadataSchema = AgentOverrideConfigSchema.pick({
|
|
|
253
189
|
});
|
|
254
190
|
|
|
255
191
|
/**
|
|
256
|
-
* Historian metadata
|
|
257
|
-
*
|
|
192
|
+
* Historian metadata stays harness-independent. Model resolution uses the flat
|
|
193
|
+
* `model` / `fallback_models` fields plus the harness's own qualifier
|
|
194
|
+
* (`variant` for OpenCode, `thinking_level` for Pi); two_pass and
|
|
195
|
+
* disallowed_tools stay here.
|
|
258
196
|
*/
|
|
259
197
|
export const HistorianConfigSchema = AgentMetadataSchema.extend({
|
|
260
198
|
expand_tools: z
|
|
@@ -272,8 +210,22 @@ export const HistorianConfigSchema = AgentMetadataSchema.extend({
|
|
|
272
210
|
.describe(
|
|
273
211
|
'Readable historian tool expansions, keyed by exact host tool name. Templates override built-in defaults; false disables an expansion. Supports ${input.path}, ${output.path}, bare ${output}, array [N], [*].field, .each("${field}"), .join("separator"), .count and final .truncate(N). Missing fields are empty; placeholders default to 300 characters, lists to 10 elements, expansions to 1000 characters. Valid in user and project config; affects historian/recomp and verbose ctx_expand only, never the wire or default ctx_expand transcript.',
|
|
274
212
|
),
|
|
275
|
-
|
|
276
|
-
|
|
213
|
+
model: HistorianModelEntrySchema.optional().describe(
|
|
214
|
+
"Primary historian model entry. The active harness reads its own qualifier (OpenCode variant, Pi thinking_level); the other harness's qualifier is ignored.",
|
|
215
|
+
),
|
|
216
|
+
fallback_models: z
|
|
217
|
+
.array(HistorianModelEntrySchema)
|
|
218
|
+
.optional()
|
|
219
|
+
.describe("Ordered fallback historian model entries, tried in order."),
|
|
220
|
+
variant: z
|
|
221
|
+
.string()
|
|
222
|
+
.optional()
|
|
223
|
+
.describe(
|
|
224
|
+
"OpenCode reasoning variant for the primary entry when it declares none. Ignored by Pi.",
|
|
225
|
+
),
|
|
226
|
+
thinking_level: PiThinkingLevelSchema.describe(
|
|
227
|
+
"Pi thinking level for the primary entry when it declares none. Ignored by OpenCode.",
|
|
228
|
+
),
|
|
277
229
|
two_pass: z
|
|
278
230
|
.boolean()
|
|
279
231
|
.default(false)
|
|
@@ -286,10 +238,14 @@ export const HistorianConfigSchema = AgentMetadataSchema.extend({
|
|
|
286
238
|
.describe(
|
|
287
239
|
'OpenCode only. Tools to REMOVE from the historian\'s default allow-list [read, aft_outline, aft_zoom, aft_search]. Applies to both historian and historian-editor agents. Use ["*"] to strip all tool definitions from the model request — this prevents weak instruction-following models (e.g. mistral-small-latest) from entering tool-calling loops. Individual tool names remove just that tool. Note: a user-supplied historian.permission override can re-allow a tool that disallowed_tools removed — disallowed_tools sets the baseline, permission overrides take precedence. (default: [])',
|
|
288
240
|
),
|
|
289
|
-
})
|
|
241
|
+
})
|
|
242
|
+
.strict()
|
|
243
|
+
.optional();
|
|
290
244
|
export type HistorianConfig = NonNullable<z.infer<typeof HistorianConfigSchema>>;
|
|
291
245
|
|
|
292
246
|
export interface MagicContextConfig {
|
|
247
|
+
/** The loader sets this to distinguish an explicit `5m` from the built-in default; users do not configure it. */
|
|
248
|
+
cacheTtlConfigured?: boolean;
|
|
293
249
|
enabled: boolean;
|
|
294
250
|
/** User-level setting that lets a session in the canonical home directory use project memory. */
|
|
295
251
|
allow_home_project: boolean;
|
|
@@ -319,7 +275,10 @@ export interface MagicContextConfig {
|
|
|
319
275
|
* matching provider input limits. Values above 90% × context_limit are clamped with a warning. */
|
|
320
276
|
execute_threshold_tokens?: { default?: number; [modelKey: string]: number | undefined };
|
|
321
277
|
protected_tokens?: number;
|
|
322
|
-
|
|
278
|
+
/** Deprecated and ignored. Use keep_reasoning_tokens instead. */
|
|
279
|
+
clear_reasoning_age?: unknown;
|
|
280
|
+
/** Reasoning tokens to keep on rebuilding passes; per-model map allowed. */
|
|
281
|
+
keep_reasoning_tokens?: number | Record<string, number>;
|
|
323
282
|
history_budget_percentage: number;
|
|
324
283
|
historian_timeout_ms: number;
|
|
325
284
|
commit_cluster_trigger: {
|
|
@@ -394,15 +353,10 @@ export interface MagicContextConfig {
|
|
|
394
353
|
};
|
|
395
354
|
/** Pi-only child-process extension controls. */
|
|
396
355
|
pi?: PiConfig;
|
|
397
|
-
/**
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
* already rewriting the messages, so it never triggers a prompt-cache miss
|
|
402
|
-
* on its own; when off, the messages sent to the model are byte-identical to
|
|
403
|
-
* the age-based-only behavior. Experimental, opt-in, default off until cache
|
|
404
|
-
* stability is proven. */
|
|
405
|
-
smart_drops: boolean;
|
|
356
|
+
/** Deprecated and ignored: supersession reclaim is always on. */
|
|
357
|
+
smart_drops?: unknown;
|
|
358
|
+
/** Keep each tool's newest N still-active results in every drop lane. */
|
|
359
|
+
protected_tools: Record<string, number>;
|
|
406
360
|
/**
|
|
407
361
|
* Age-tier caveman compression for long user/assistant text parts.
|
|
408
362
|
* Graduated from `experimental.caveman_text_compression`; opt-in, default off.
|
|
@@ -517,16 +471,16 @@ export const MagicContextConfigSchema = z.object({
|
|
|
517
471
|
"Select a named user-owned model profile. A valid project name overrides this user default; an empty string, null, or other non-string project value is ignored with a warning so the user selection still applies. Unknown names warn and use the base configuration.",
|
|
518
472
|
),
|
|
519
473
|
profiles: ConfigProfilesSchema.optional().describe(
|
|
520
|
-
"User-level named model profiles. A profile may contain only historian model, fallback_models, OpenCode variant,
|
|
474
|
+
"User-level named model profiles. A profile may contain only the flat historian model-resolution fields (model, fallback_models, OpenCode variant, Pi thinking_level). Project configs may select a name but cannot define profiles.",
|
|
521
475
|
),
|
|
522
476
|
historian: HistorianConfigSchema.describe(
|
|
523
|
-
"Historian metadata plus
|
|
477
|
+
"Historian metadata plus the flat model-resolution fields (model, fallback_models, variant, thinking_level). The active harness reads its own qualifier; the removed historian.opencode / historian.pi blocks are no longer accepted.",
|
|
524
478
|
),
|
|
525
479
|
cache_ttl: z
|
|
526
480
|
.union([z.string(), z.object({ default: z.string() }).catchall(z.string())])
|
|
527
481
|
.default("5m")
|
|
528
482
|
.describe(
|
|
529
|
-
'How long Magic Context assumes the provider\'s cached prefix stays valid. This is MC\'s own deferral gate — it does not change the provider\'s actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "provider/model": "1h", "provider/*": "never" }); keys resolve most-specific first (exact provider/model, bare model ID, shorter dash-prefixes, then the provider/* wildcard). Explicit per-model entries win; otherwise GPT-5.6 and later (including gpt-6*, through any provider prefix) use a built-in 30m lifetime before the object default or 5m fallback. An unset or global "5m" opts into built-in defaults; any other global string is an explicit policy and wins.
|
|
483
|
+
'How long Magic Context assumes the provider\'s cached prefix stays valid. This is MC\'s own deferral gate — it does not change the provider\'s actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "provider/model": "1h", "provider/*": "never" }); keys resolve most-specific first (exact provider/model, bare model ID, shorter dash-prefixes, then the provider/* wildcard). Explicit per-model entries win; otherwise GPT-5.6 and later (including gpt-6*, through any provider prefix) use a built-in 30m lifetime before the object default or 5m fallback. An unset or global "5m" opts into built-in defaults; any other global string is an explicit policy and wins. User and project settings, including an explicit "5m" or object default, apply on the next pass. Only built-in defaults are frozen per session (per model), including across restarts. /mmc-status shows the effective value and source. OpenAI documents at least 30 minutes since the latest write or reuse: https://developers.openai.com/api/docs/guides/prompt-caching (Cache lifetime and Summary of model differences). Set to "never" to mean MC never assumes expiry (for lanes kept warm externally by a cache-keep tool) — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time. Provider-side extended TTL is a separate request-level concern (cache_control: { ttl } in the request body).',
|
|
530
484
|
),
|
|
531
485
|
prompt_surface: PromptSurfaceConfigSchema.default({ default: "full" }).describe(
|
|
532
486
|
"Prompt-surface presets: default is full; models use bare model IDs, provider/model, or provider/* routing keys. Guidance and tool-description overrides are user-level only. OpenCode 1.x and Pi register tool descriptions once per process (they follow the default preset). OpenCode 2 rewrites the five mmc_* descriptions per request from the draft model.",
|
|
@@ -586,10 +540,23 @@ export const MagicContextConfigSchema = z.object({
|
|
|
586
540
|
"Positive integer token floor to protect from automatic reclaim (min: 4_000, max: 1_000_000). When omitted, the derived default is clamp(round(0.05 × usableSoft), min(16_000, round(0.08 × usableSoft)), 64_000).",
|
|
587
541
|
),
|
|
588
542
|
clear_reasoning_age: z
|
|
589
|
-
.
|
|
590
|
-
.
|
|
591
|
-
.
|
|
592
|
-
.
|
|
543
|
+
.unknown()
|
|
544
|
+
.optional()
|
|
545
|
+
.describe("Deprecated and ignored. Use keep_reasoning_tokens instead.")
|
|
546
|
+
.meta({ deprecated: true }),
|
|
547
|
+
keep_reasoning_tokens: z
|
|
548
|
+
.union([
|
|
549
|
+
z.number().int().min(0).max(1_000_000),
|
|
550
|
+
z
|
|
551
|
+
.object({
|
|
552
|
+
default: z.number().int().min(0).max(1_000_000).optional(),
|
|
553
|
+
})
|
|
554
|
+
.catchall(z.number().int().min(0).max(1_000_000)),
|
|
555
|
+
])
|
|
556
|
+
.optional()
|
|
557
|
+
.describe(
|
|
558
|
+
"Reasoning tokens to keep on rebuilding passes. Number or per-model object; exact, shorter model keys, provider/*, then default. Omitted: fixed 10,000. 0 removes all eligible historical reasoning; newest and exempt steps always stay.",
|
|
559
|
+
),
|
|
593
560
|
history_budget_percentage: z
|
|
594
561
|
.number()
|
|
595
562
|
.min(0.05)
|
|
@@ -744,11 +711,13 @@ export const MagicContextConfigSchema = z.object({
|
|
|
744
711
|
pi: PiConfigSchema.describe(
|
|
745
712
|
"Pi-only child-process extension controls. This setting is user-level only; project configuration cannot choose which extensions a user's subagent children load.",
|
|
746
713
|
),
|
|
747
|
-
smart_drops: z
|
|
748
|
-
|
|
749
|
-
.
|
|
714
|
+
smart_drops: z.union([z.boolean(), z.record(z.string(), z.unknown())]).optional(),
|
|
715
|
+
protected_tools: z
|
|
716
|
+
.record(z.string(), z.number().int().nonnegative())
|
|
717
|
+
.default({ ...DEFAULT_PROTECTED_TOOLS })
|
|
718
|
+
.transform((map) => mergeProtectedTools(map))
|
|
750
719
|
.describe(
|
|
751
|
-
"
|
|
720
|
+
"Keep each tool's newest N still-active results in every automatic drop lane (upstream issue 621). User and project maps merge over defaults {todowrite: 1, mmc_reduce: 3}; 0 turns protection off. Names are case-insensitive and ignore leading mcp_ (upstream's ctx_reduce maps to mmc_reduce). Holds even at 95% pressure, with no byte cap: large protected outputs can reach refusal sooner. Queued drops, from the agent or historian publication, are held until newer calls displace the result and a later cache-rebuilding pass applies them. The historian's summary is unaffected; the raw result leaves at the next fold. Frozen strips are unaffected. Changes and rotation never originate a bust; dropped results are never restored.",
|
|
752
721
|
),
|
|
753
722
|
caveman_text_compression: z
|
|
754
723
|
.object({
|
|
@@ -964,13 +933,12 @@ export const MagicContextConfigSchema = z.object({
|
|
|
964
933
|
|
|
965
934
|
/** Settings whose fresh values can be used by later agent runs without changing rendered prompt bytes. */
|
|
966
935
|
export const LIVE_RELOAD_CONFIG_PATHS = [
|
|
936
|
+
"cache_ttl",
|
|
967
937
|
"toast_duration_ms",
|
|
968
|
-
"historian.
|
|
969
|
-
"historian.
|
|
970
|
-
"historian.
|
|
971
|
-
"historian.
|
|
972
|
-
"historian.pi.fallback_models",
|
|
973
|
-
"historian.pi.thinking_level",
|
|
938
|
+
"historian.model",
|
|
939
|
+
"historian.fallback_models",
|
|
940
|
+
"historian.variant",
|
|
941
|
+
"historian.thinking_level",
|
|
974
942
|
"historian.two_pass",
|
|
975
943
|
"historian.expand_tools",
|
|
976
944
|
"historian.maxTokens",
|
package/src/config/variable.ts
CHANGED
|
@@ -31,6 +31,14 @@ export interface SubstituteResult {
|
|
|
31
31
|
* user via logger/toast/startup notification.
|
|
32
32
|
*/
|
|
33
33
|
warnings: string[];
|
|
34
|
+
/**
|
|
35
|
+
* The subset of {@link warnings} that are unresolved references: a missing
|
|
36
|
+
* or empty env var, a missing file, or an unreadable file that fell back to
|
|
37
|
+
* empty string. Purely advisory to the runtime (which keeps the lenient
|
|
38
|
+
* warning behavior); `config-check` treats these as hard config errors.
|
|
39
|
+
* Does not include the sensitive-path warning.
|
|
40
|
+
*/
|
|
41
|
+
failures: string[];
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
const ENV_PATTERN = /\{env:([^}]+)\}/g;
|
|
@@ -78,6 +86,7 @@ function sensitiveFilePathReason(resolvedPath: string): string | null {
|
|
|
78
86
|
*/
|
|
79
87
|
export function substituteConfigVariables(input: SubstituteInput): SubstituteResult {
|
|
80
88
|
const warnings: string[] = [];
|
|
89
|
+
const failures: string[] = [];
|
|
81
90
|
let text = input.text;
|
|
82
91
|
|
|
83
92
|
if (input.isProjectConfig) {
|
|
@@ -96,7 +105,7 @@ export function substituteConfigVariables(input: SubstituteInput): SubstituteRes
|
|
|
96
105
|
`Project-level config no longer supports ${tokenTypes} tokens for security reasons; leaving tokens literal. Move secret expansion to user-level config.`,
|
|
97
106
|
);
|
|
98
107
|
}
|
|
99
|
-
return { text, warnings };
|
|
108
|
+
return { text, warnings, failures };
|
|
100
109
|
}
|
|
101
110
|
|
|
102
111
|
// Strip JSONC comments before substitution so tokens in comments cannot
|
|
@@ -108,9 +117,9 @@ export function substituteConfigVariables(input: SubstituteInput): SubstituteRes
|
|
|
108
117
|
const varName = rawName.trim();
|
|
109
118
|
const value = varName ? process.env[varName] : undefined;
|
|
110
119
|
if (value === undefined || value === "") {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
);
|
|
120
|
+
const message = `Environment variable ${varName} is not set (referenced via {env:${varName}}); using empty string`;
|
|
121
|
+
warnings.push(message);
|
|
122
|
+
failures.push(message);
|
|
114
123
|
return "";
|
|
115
124
|
}
|
|
116
125
|
|
|
@@ -119,7 +128,7 @@ export function substituteConfigVariables(input: SubstituteInput): SubstituteRes
|
|
|
119
128
|
|
|
120
129
|
const fileMatches = Array.from(text.matchAll(FILE_PATTERN));
|
|
121
130
|
if (fileMatches.length === 0) {
|
|
122
|
-
return { text, warnings };
|
|
131
|
+
return { text, warnings, failures };
|
|
123
132
|
}
|
|
124
133
|
|
|
125
134
|
const configDir = input.configPath ? dirname(input.configPath) : process.cwd();
|
|
@@ -164,9 +173,9 @@ export function substituteConfigVariables(input: SubstituteInput): SubstituteRes
|
|
|
164
173
|
}
|
|
165
174
|
|
|
166
175
|
if (!existsSync(filePath)) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
);
|
|
176
|
+
const message = `File not found for ${token} (resolved to ${filePath}); using empty string`;
|
|
177
|
+
warnings.push(message);
|
|
178
|
+
failures.push(message);
|
|
170
179
|
continue;
|
|
171
180
|
}
|
|
172
181
|
|
|
@@ -175,9 +184,9 @@ export function substituteConfigVariables(input: SubstituteInput): SubstituteRes
|
|
|
175
184
|
contents = readFileSync(filePath, "utf-8").trim();
|
|
176
185
|
} catch (error) {
|
|
177
186
|
const message = error instanceof Error ? error.message : String(error);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
);
|
|
187
|
+
const warning = `Failed to read file for ${token} (${filePath}): ${message}; using empty string`;
|
|
188
|
+
warnings.push(warning);
|
|
189
|
+
failures.push(warning);
|
|
181
190
|
continue;
|
|
182
191
|
}
|
|
183
192
|
|
|
@@ -188,5 +197,5 @@ export function substituteConfigVariables(input: SubstituteInput): SubstituteRes
|
|
|
188
197
|
}
|
|
189
198
|
|
|
190
199
|
output += text.slice(cursor);
|
|
191
|
-
return { text: output, warnings };
|
|
200
|
+
return { text: output, warnings, failures };
|
|
192
201
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const pending = new Map<string, Set<AbortController>>();
|
|
2
|
+
|
|
3
|
+
/** Cleanup cancels optional searches and backfill, not durable served decisions. */
|
|
4
|
+
export function registerAutoSearchWork(sessionId: string): {
|
|
5
|
+
signal: AbortSignal;
|
|
6
|
+
done: () => void;
|
|
7
|
+
} {
|
|
8
|
+
const controller = new AbortController();
|
|
9
|
+
const work = pending.get(sessionId) ?? new Set<AbortController>();
|
|
10
|
+
pending.set(sessionId, work);
|
|
11
|
+
work.add(controller);
|
|
12
|
+
return {
|
|
13
|
+
signal: controller.signal,
|
|
14
|
+
done: () => {
|
|
15
|
+
work.delete(controller);
|
|
16
|
+
if (pending.get(sessionId) === work && work.size === 0) pending.delete(sessionId);
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function cancelAutoSearchWork(sessionId?: string): void {
|
|
22
|
+
for (const [id, work] of pending) {
|
|
23
|
+
if (sessionId !== undefined && id !== sessionId) continue;
|
|
24
|
+
pending.delete(id);
|
|
25
|
+
for (const controller of work) controller.abort();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -45,7 +45,7 @@ describe("resolveCacheTtlDisplay", () => {
|
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
expect(configured.source).toBe("config");
|
|
48
|
-
expect(session).toEqual({ value: "
|
|
48
|
+
expect(session).toEqual({ value: "1h", source: "config", modelKey });
|
|
49
49
|
expect(fallback).toEqual({ value: "5m", source: "default", modelKey });
|
|
50
50
|
});
|
|
51
51
|
|
|
@@ -10,7 +10,7 @@ export interface CacheTtlDisplay {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export interface ResolveCacheTtlDisplayArgs {
|
|
13
|
-
frozen?: ResolvedCacheTtl;
|
|
13
|
+
frozen?: ResolvedCacheTtl & { builtInDefault?: ResolvedCacheTtl };
|
|
14
14
|
configured: MagicContextConfig["cache_ttl"];
|
|
15
15
|
configuredExplicitly: boolean;
|
|
16
16
|
modelKey: string | undefined;
|
|
@@ -20,12 +20,22 @@ export interface ResolveCacheTtlDisplayArgs {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* Resolve
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* Resolve the lifetime shown in status without changing the value saved for the scheduler.
|
|
24
|
+
* The next pass uses current settings; a saved built-in lifetime applies only to the same
|
|
25
|
+
* model, even after an override is removed.
|
|
26
26
|
*/
|
|
27
27
|
export function resolveCacheTtlDisplay(args: ResolveCacheTtlDisplayArgs): CacheTtlDisplay {
|
|
28
|
-
|
|
28
|
+
const resolved = resolveModelCacheTtl(
|
|
29
|
+
args.configured,
|
|
30
|
+
args.modelKey,
|
|
31
|
+
args.configuredExplicitly,
|
|
32
|
+
);
|
|
33
|
+
if (resolved.source === "config") return resolved;
|
|
34
|
+
if (args.frozen && (!args.modelKey || args.frozen.modelKey === args.modelKey)) {
|
|
35
|
+
return args.frozen.source === "config"
|
|
36
|
+
? (args.frozen.builtInDefault ?? resolved)
|
|
37
|
+
: args.frozen;
|
|
38
|
+
}
|
|
29
39
|
if (
|
|
30
40
|
(args.sessionModelKey && (!args.modelKey || args.sessionModelKey === args.modelKey)) ||
|
|
31
41
|
(!args.modelKey && !args.sessionModelKey && args.sessionValue !== "5m")
|
|
@@ -37,22 +47,13 @@ export function resolveCacheTtlDisplay(args: ResolveCacheTtlDisplayArgs): CacheT
|
|
|
37
47
|
};
|
|
38
48
|
}
|
|
39
49
|
|
|
40
|
-
const resolved = resolveModelCacheTtl(args.configured, args.modelKey);
|
|
41
|
-
if (
|
|
42
|
-
resolved.source === "default" &&
|
|
43
|
-
typeof args.configured === "string" &&
|
|
44
|
-
args.configuredExplicitly
|
|
45
|
-
)
|
|
46
|
-
return { ...resolved, source: "config" };
|
|
47
50
|
return resolved;
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
export function formatCacheTtlDisplay(display: CacheTtlDisplay): string {
|
|
51
|
-
if (display.source === "OpenAI GPT-5.6+ default")
|
|
52
|
-
return `Cache TTL: ${display.value} (${display.source})`;
|
|
53
54
|
if (display.source === "session") return `Cache TTL: ${display.value} (session)`;
|
|
54
55
|
if (display.source === "config") {
|
|
55
|
-
return `Cache TTL: ${display.value} (config
|
|
56
|
+
return `Cache TTL: ${display.value} (your config)`;
|
|
56
57
|
}
|
|
57
|
-
return `Cache TTL: ${display.value} (default
|
|
58
|
+
return `Cache TTL: ${display.value} (built-in default, frozen for this session)`;
|
|
58
59
|
}
|
|
@@ -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 ?? "")
|