opencode-swarm 7.138.4 → 7.139.1
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 +7 -6
- package/dist/cli/{config-doctor-31yppse4.js → config-doctor-tgnr91q3.js} +2 -2
- package/dist/cli/{core-65c7rvqf.js → core-g2dfh9fq.js} +1 -1
- package/dist/cli/{curation-policy-hs9pc1rp.js → curation-policy-2qnhgdtt.js} +7 -7
- package/dist/cli/{curator-drift-jpap6hv4.js → curator-drift-vfh07mqy.js} +5 -2
- package/dist/cli/{curator-llm-factory-wm27ra25.js → curator-llm-factory-1ftzece0.js} +28 -28
- package/dist/cli/{curator-54n1y4j8.js → curator-nbsag633.js} +28 -28
- package/dist/cli/{evidence-summary-service-hrxcf29a.js → evidence-summary-service-kzxr71yd.js} +9 -9
- package/dist/cli/{gate-evidence-ecx4djaw.js → gate-evidence-z2b1ymnw.js} +5 -5
- package/dist/cli/{guardrail-explain-1729nse8.js → guardrail-explain-vb9k9zwm.js} +29 -29
- package/dist/cli/{guardrail-log-yjj5srkw.js → guardrail-log-0djnvfas.js} +3 -3
- package/dist/cli/{hive-promoter-es2x2b0e.js → hive-promoter-bpt26yew.js} +28 -28
- package/dist/cli/{index-mycqmsz5.js → index-0wp67gqj.js} +452 -159
- package/dist/cli/{index-c60whfgh.js → index-0ymhx85c.js} +2 -2
- package/dist/cli/{index-5q009kc4.js → index-15526t16.js} +8 -3
- package/dist/cli/{index-smsy2p8n.js → index-3eddtgxt.js} +1 -1
- package/dist/cli/{index-4fmztnrq.js → index-4xbyy6aw.js} +2 -2
- package/dist/cli/{index-xybtaph7.js → index-5j6chvj8.js} +1 -1
- package/dist/cli/{index-39k6y018.js → index-5w7ekpy3.js} +2 -2
- package/dist/cli/{index-z7jgvm9b.js → index-5zyk8qgv.js} +2 -2
- package/dist/cli/{index-en4fb04r.js → index-668dpw5e.js} +1 -1
- package/dist/cli/{index-m8txs2a9.js → index-91s653xx.js} +1 -1
- package/dist/cli/{index-y28n2wmq.js → index-a12906mj.js} +1 -1
- package/dist/cli/{index-10mz5js6.js → index-a5eba0t8.js} +2 -2
- package/dist/cli/{index-57stye65.js → index-aymt7hzw.js} +6 -3
- package/dist/cli/{index-1g6xpjk3.js → index-db7wf6ke.js} +7 -7
- package/dist/cli/{index-m1pwkwfe.js → index-dw09fz3w.js} +1 -1
- package/dist/cli/{index-fsrp8wp3.js → index-ed5ykebp.js} +25 -2
- package/dist/cli/{index-jbge0dyh.js → index-en6qq954.js} +3 -3
- package/dist/cli/{index-tqshdzaw.js → index-gvhvz176.js} +2 -2
- package/dist/cli/{index-e1kgxchq.js → index-hgrkhxbk.js} +2 -2
- package/dist/cli/{index-33q2gmgd.js → index-hn0mdcmj.js} +1 -1
- package/dist/cli/{index-a9xny52r.js → index-ht4q3548.js} +2 -2
- package/dist/cli/{index-q344kj84.js → index-prmb5qfp.js} +2 -2
- package/dist/cli/{index-x20cgr2q.js → index-q7ezzgwq.js} +16 -2
- package/dist/cli/{index-ngqxzkqm.js → index-s608d3hw.js} +2 -2
- package/dist/cli/{index-50mwt8fx.js → index-vxbppwvf.js} +5 -5
- package/dist/cli/{index-rrxcfxrd.js → index-wrt6m5ze.js} +1 -1
- package/dist/cli/{index-4qzeef9h.js → index-x9q4bbhd.js} +1 -1
- package/dist/cli/{index-m40ea3zk.js → index-xec724kg.js} +2 -2
- package/dist/cli/{index-k27a4e5g.js → index-xka8s8jw.js} +30 -30
- package/dist/cli/{index-a18hk2fw.js → index-xr07r80d.js} +513 -483
- package/dist/cli/{index-gm3pjfhb.js → index-y1zcsf2a.js} +1 -1
- package/dist/cli/{index-tjwz5tct.js → index-ywysg26s.js} +4 -4
- package/dist/cli/index.js +28 -28
- package/dist/cli/{knowledge-escalator-s6z1x65b.js → knowledge-escalator-pjg2x75c.js} +8 -8
- package/dist/cli/{knowledge-events-nnyn6hst.js → knowledge-events-vxheptk8.js} +6 -6
- package/dist/cli/{knowledge-link-xc6yhxmz.js → knowledge-link-3tq8w6gs.js} +5 -5
- package/dist/cli/{knowledge-store-x4yfc7v3.js → knowledge-store-36mascwz.js} +6 -6
- package/dist/cli/{knowledge-validator-1v047gsa.js → knowledge-validator-anats6rj.js} +9 -9
- package/dist/cli/{pending-delegations-7dbc0j2a.js → pending-delegations-tmyf18p4.js} +5 -5
- package/dist/cli/{pr-subscriptions-m943zn6g.js → pr-subscriptions-hhx6yk24.js} +5 -5
- package/dist/cli/{runner-x1hy047y.js → runner-w30gazew.js} +6 -6
- package/dist/cli/{scan-cursor-jxajj6s7.js → scan-cursor-apbz9eez.js} +7 -7
- package/dist/cli/{schema-fj32eyae.js → schema-x9fr2ey8.js} +3 -1
- package/dist/cli/{scope-persistence-w7zen2wz.js → scope-persistence-3f0d4fwv.js} +4 -4
- package/dist/cli/{skill-generator-rt0jqcsa.js → skill-generator-20czn4kd.js} +10 -10
- package/dist/cli/{telemetry-0yqed3jv.js → telemetry-4tgrfhaz.js} +1 -1
- package/dist/cli/{worktree-collision-ownership-hjrt5hx2.js → worktree-collision-ownership-vexb0b6r.js} +38 -8
- package/dist/config/context-window.d.ts +210 -0
- package/dist/config/schema.d.ts +18 -0
- package/dist/evaluation/ephemeral-agent-dispatcher.d.ts +18 -0
- package/dist/evaluation/model-dispatcher.d.ts +1 -0
- package/dist/hooks/delegate-ack-collector.d.ts +1 -1
- package/dist/hooks/delegation-gate/worktree-collision-ownership.d.ts +7 -0
- package/dist/hooks/delegation-gate/worktree-isolation.d.ts +2 -1
- package/dist/hooks/delegation-gate/worktree-provisioning-owner.d.ts +6 -0
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/init-orphan-recovery.d.ts +4 -1
- package/dist/hooks/knowledge-application-gate.d.ts +2 -1
- package/dist/hooks/knowledge-application.d.ts +5 -4
- package/dist/hooks/knowledge-injector.d.ts +16 -0
- package/dist/hooks/knowledge-types.d.ts +1 -1
- package/dist/hooks/messages-transform.d.ts +18 -0
- package/dist/hooks/model-limits.d.ts +88 -30
- package/dist/index.js +501 -499
- package/dist/memory/injector.d.ts +2 -0
- package/dist/plan/manager.d.ts +2 -0
- package/dist/services/context-budget-service.d.ts +6 -1
- package/dist/services/run-memory.d.ts +53 -5
- package/dist/services/status-service.d.ts +14 -0
- package/dist/state.d.ts +37 -0
- package/dist/tools/context-status.d.ts +3 -1
- package/dist/tools/update-task-status.d.ts +2 -0
- package/dist/turbo/lean/runner.d.ts +10 -0
- package/dist/utils/ephemeral-session-teardown.d.ts +98 -0
- package/dist/utils/path-security.d.ts +95 -1
- package/dist/utils/swarm-artifact-cache.d.ts +13 -0
- package/dist/worktree/index.d.ts +1 -1
- package/dist/worktree/merge.d.ts +36 -3
- package/package.json +1 -1
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context-window denominator resolution — the SINGLE derivation.
|
|
3
|
+
*
|
|
4
|
+
* Every "how many tokens does this model's context window hold?" question in
|
|
5
|
+
* the plugin resolves here: the context-budget denominator (`budgetTokens` in
|
|
6
|
+
* `src/hooks/system-enhancer.ts` Path A and Path B), the hard-enforcement
|
|
7
|
+
* threshold in `src/hooks/context-budget.ts`, the knowledge-injector headroom
|
|
8
|
+
* gate, the `context_status` tool, and the `/swarm status` render.
|
|
9
|
+
*
|
|
10
|
+
* ## Why this exists
|
|
11
|
+
*
|
|
12
|
+
* The denominator used to be a hardcoded 128 000. That number is stale:
|
|
13
|
+
* current frontier and mid-tier models ship 200k–1M windows, and 256k is
|
|
14
|
+
* common even for locally-hosted models. A budget that reports "87 % used"
|
|
15
|
+
* against a window that is really 1M does not just emit a spurious advisory —
|
|
16
|
+
* `context-budget.ts` HARD-PRUNES messages at `critical_threshold × limit`, so
|
|
17
|
+
* a too-small denominator silently deletes context the model still needed.
|
|
18
|
+
*
|
|
19
|
+
* The authoritative value is already in the host's hands. The
|
|
20
|
+
* `experimental.chat.system.transform` hook input carries
|
|
21
|
+
* `model: Model` (`@opencode-ai/plugin`), and `Model.limit.context`
|
|
22
|
+
* (`@opencode-ai/sdk`) is the live window for THAT provider's entry of THAT
|
|
23
|
+
* model. Provider-specific caps are already baked in, because the host's model
|
|
24
|
+
* catalog is keyed `providers[providerID].models[modelID]` — verified against
|
|
25
|
+
* the on-disk catalog, where `github-copilot`'s `claude-sonnet-4.5` and
|
|
26
|
+
* `anthropic`'s `claude-sonnet-4-5` carry DIFFERENT `limit.context` values.
|
|
27
|
+
* A user's `provider.<id>.models.<id>.limit.context` override in
|
|
28
|
+
* `opencode.json` is merged into the same object before it reaches the hook.
|
|
29
|
+
*
|
|
30
|
+
* ## Resolution order (first usable value wins)
|
|
31
|
+
*
|
|
32
|
+
* 1. `context_budget.model_limits["<providerID>/<modelID>"]`
|
|
33
|
+
* 2. `context_budget.model_limits["<modelID>"]`
|
|
34
|
+
* 3. `context_budget.model_limits.default`
|
|
35
|
+
* 4. the LIVE `model.limit.context` from the hook input
|
|
36
|
+
* 5. the static fallback table (`src/hooks/model-limits.ts`), injected as
|
|
37
|
+
* `fallbackLookup` — reachable only when no live value is available
|
|
38
|
+
* 6. `DEFAULT_MODEL_CONTEXT_TOKENS`
|
|
39
|
+
*
|
|
40
|
+
* Steps 1–3 are ABOVE the live value on purpose: a user who writes a
|
|
41
|
+
* `model_limits` entry is asking for a smaller *working* budget than the
|
|
42
|
+
* physical window, and that intent must not be overridden by the hardware.
|
|
43
|
+
* This is why `context_budget.model_limits` no longer carries a zod
|
|
44
|
+
* `.default({ default: … })` — a schema-injected value is not user intent, and
|
|
45
|
+
* would have shadowed the live window for every user who has a
|
|
46
|
+
* `context_budget` block at all. See `ContextBudgetConfigSchema` in
|
|
47
|
+
* `./schema.ts`.
|
|
48
|
+
*
|
|
49
|
+
* Steps 5–6 are last resorts, NOT a cap on step 4. The hand-maintained table
|
|
50
|
+
* is stale in the downward direction (it claims Copilot caps everything at
|
|
51
|
+
* 128 000; the live catalog shows Copilot Claude entries at 200 000 and
|
|
52
|
+
* 1 000 000), so min-capping the live value against it would reintroduce
|
|
53
|
+
* exactly the too-small denominator this module exists to remove.
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* LAST-RESORT context-budget denominator (tokens) — rung 6 above.
|
|
57
|
+
*
|
|
58
|
+
* Declared HERE rather than imported from `./schema`, deliberately: this module
|
|
59
|
+
* is loaded transitively by `src/hooks/model-limits.ts` and therefore by every
|
|
60
|
+
* `messages.transform` consumer, and several test files replace
|
|
61
|
+
* `src/config/schema` with a non-spreading `mock.module` factory. Importing a
|
|
62
|
+
* symbol from schema here would make Bun throw
|
|
63
|
+
* `SyntaxError: Export named 'DEFAULT_MODEL_CONTEXT_TOKENS' not found` in those
|
|
64
|
+
* files at import time (see the "mock.module() Export Completeness" section of
|
|
65
|
+
* the writing-tests skill). Keeping this module dependency-free removes the
|
|
66
|
+
* whole class. `./schema` re-exports the constant, so every existing importer
|
|
67
|
+
* is unaffected.
|
|
68
|
+
*
|
|
69
|
+
* It is reached only when the user configured no `model_limits` entry, the host
|
|
70
|
+
* supplied no usable `model.limit.context`, and the static fallback table in
|
|
71
|
+
* `src/hooks/model-limits.ts` had no opinion either. It is deliberately NOT the
|
|
72
|
+
* primary source: 128 000 is stale for current models, which routinely ship
|
|
73
|
+
* 200k–1M windows.
|
|
74
|
+
*
|
|
75
|
+
* Historical note: `budgetTokens` used to be derived from
|
|
76
|
+
* `context_budget.model_limits.default` in `src/hooks/system-enhancer.ts`, but
|
|
77
|
+
* `context_budget` is schema-OPTIONAL, so a user with no block fell back to
|
|
78
|
+
* `DEFAULT_CONTEXT_BUDGET_CONFIG.budgetTokens` in
|
|
79
|
+
* `src/services/context-budget-service.ts` instead. Those two numbers had
|
|
80
|
+
* drifted (128000 vs 40000), so the unconfigured default measured the swarm's
|
|
81
|
+
* architect system prompt — approximately 34.5k estimated tokens — against a
|
|
82
|
+
* 40k denominator and reported ~86% on turn one (34500/40000 = 86.25%; an
|
|
83
|
+
* earlier revision of this comment said 87%) — enough to fire the budget
|
|
84
|
+
* warning, the `CONTEXT PRESSURE`
|
|
85
|
+
* advisory (src/index.ts) and the compaction EMERGENCY tier
|
|
86
|
+
* (`observation/reflection/emergency` = 40/60/80) immediately.
|
|
87
|
+
*/
|
|
88
|
+
export declare const DEFAULT_MODEL_CONTEXT_TOKENS = 128000;
|
|
89
|
+
/**
|
|
90
|
+
* Smallest context window this module will accept from an untrusted source.
|
|
91
|
+
*
|
|
92
|
+
* Mirrors the `z.number().min(1000)` floor that `ContextBudgetConfigSchema`
|
|
93
|
+
* already enforces on user-authored `model_limits` values, so live catalog data
|
|
94
|
+
* and user config are held to one standard. This is not theoretical: a survey
|
|
95
|
+
* of the host's on-disk model catalog (`~/.cache/opencode/models.json`, ~6.2k
|
|
96
|
+
* entries; the file is a per-machine, auto-refreshing artifact, so the exact
|
|
97
|
+
* total moves) found 124 entries with `limit.context: 0`. Dividing by that
|
|
98
|
+
* yields `Infinity` percent and would fire the EMERGENCY compaction tier on
|
|
99
|
+
* turn one.
|
|
100
|
+
*/
|
|
101
|
+
export declare const MIN_PLAUSIBLE_CONTEXT_TOKENS = 1000;
|
|
102
|
+
/** Which rung of the resolution order produced the value. */
|
|
103
|
+
export type ContextWindowSource = 'user_provider_model' | 'user_model' | 'user_default' | 'live_model_limit' | 'static_table' | 'static_default';
|
|
104
|
+
export interface ContextWindowResolution {
|
|
105
|
+
/**
|
|
106
|
+
* The resolved denominator, in tokens. Always a finite integer ≥ 1, so it is
|
|
107
|
+
* never a divide-by-zero. Through a PARSED config it is additionally ≥ 1000:
|
|
108
|
+
* every rung except the user rungs is gated on
|
|
109
|
+
* {@link isUsableContextWindow} (≥ {@link MIN_PLAUSIBLE_CONTEXT_TOKENS}), and
|
|
110
|
+
* the user rungs are themselves floored at 1000 by
|
|
111
|
+
* `ContextBudgetConfigSchema`. A direct programmatic call may still supply a
|
|
112
|
+
* user value between 1 and 999 and get it back — that is deliberate
|
|
113
|
+
* (honouring explicit intent), and it is why the guarantee stated here is
|
|
114
|
+
* ≥ 1 rather than ≥ 1000.
|
|
115
|
+
*/
|
|
116
|
+
tokens: number;
|
|
117
|
+
/** Which rung produced `tokens` — surfaced in debug logs and tests. */
|
|
118
|
+
source: ContextWindowSource;
|
|
119
|
+
}
|
|
120
|
+
export interface ContextWindowInputs {
|
|
121
|
+
/**
|
|
122
|
+
* `config.context_budget?.model_limits` exactly as the user authored it.
|
|
123
|
+
* Pass `undefined` when the user has no `context_budget` block.
|
|
124
|
+
*/
|
|
125
|
+
userLimits?: Record<string, number> | undefined;
|
|
126
|
+
/** Model identifier, when known (e.g. `claude-sonnet-4-6`). */
|
|
127
|
+
modelID?: string | undefined;
|
|
128
|
+
/** Provider identifier, when known (e.g. `github-copilot`). */
|
|
129
|
+
providerID?: string | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* The live `model.limit.context` for this turn. Deliberately `unknown`:
|
|
132
|
+
* it crosses the plugin-host boundary, and the survey above shows the
|
|
133
|
+
* catalog really does ship `0` for some entries.
|
|
134
|
+
*/
|
|
135
|
+
liveContextLimit?: unknown;
|
|
136
|
+
/**
|
|
137
|
+
* Last-resort static lookup. Injected rather than imported so this module
|
|
138
|
+
* stays free of any dependency on `src/hooks/`. Returning `undefined` means
|
|
139
|
+
* "no opinion" and falls through to `DEFAULT_MODEL_CONTEXT_TOKENS`.
|
|
140
|
+
*/
|
|
141
|
+
fallbackLookup?: ((modelID?: string, providerID?: string) => number | undefined) | undefined;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* True when `value` can be used as a divisor at all: a finite number strictly
|
|
145
|
+
* greater than zero.
|
|
146
|
+
*
|
|
147
|
+
* This is the bar applied to USER-AUTHORED `model_limits` values. It is
|
|
148
|
+
* deliberately weaker than {@link isUsableContextWindow}: `ContextBudgetConfigSchema`
|
|
149
|
+
* already enforces `z.number().min(1000)` on that record, so anything smaller
|
|
150
|
+
* cannot reach here through a parsed config — and silently DISCARDING a value a
|
|
151
|
+
* user explicitly wrote would be worse than honouring it. What this does reject
|
|
152
|
+
* is the set that breaks arithmetic outright (`NaN`, `±Infinity`, `0`,
|
|
153
|
+
* negatives, non-numbers), which a direct programmatic call can still supply.
|
|
154
|
+
*
|
|
155
|
+
* The bar is `>= 1`, not `> 0` (#1619 review round 4). `resolveContextWindow`
|
|
156
|
+
* applies `Math.floor` to whatever this admits, so a fractional value in
|
|
157
|
+
* `(0, 1)` — e.g. `{ default: 0.5 }` from a programmatic caller — passed a
|
|
158
|
+
* `> 0` test and then floored to a **zero denominator**, producing the exact
|
|
159
|
+
* `Infinity %` this guard exists to prevent. `>= 1` closes that without
|
|
160
|
+
* discarding any value a user could author through a parsed config (the schema
|
|
161
|
+
* floor is 1000) and without changing the verdict for any previously-accepted
|
|
162
|
+
* integer.
|
|
163
|
+
*/
|
|
164
|
+
export declare function isUsableConfiguredWindow(value: unknown): value is number;
|
|
165
|
+
/**
|
|
166
|
+
* True when `value` is a plausible context-window size reported by an
|
|
167
|
+
* UNTRUSTED source: a finite number at or above
|
|
168
|
+
* {@link MIN_PLAUSIBLE_CONTEXT_TOKENS}.
|
|
169
|
+
*
|
|
170
|
+
* Applied to the live `model.limit.context` and to the static fallback table.
|
|
171
|
+
* Stricter than {@link isUsableConfiguredWindow} because nothing validates the
|
|
172
|
+
* host's model catalog on the way in and no real model ships a sub-1000-token
|
|
173
|
+
* window — so a small value there is corrupt data, not intent. Rejects, by
|
|
174
|
+
* construction, `undefined`, `null`, non-numbers, `NaN`, `Infinity`,
|
|
175
|
+
* `-Infinity`, `0` and every negative: the shapes that turn a percentage into
|
|
176
|
+
* `NaN` / `Infinity` and drive spurious EMERGENCY compaction directives.
|
|
177
|
+
*/
|
|
178
|
+
export declare function isUsableContextWindow(value: unknown): value is number;
|
|
179
|
+
/**
|
|
180
|
+
* Safely read `model.limit.context` off the `experimental.chat.system.transform`
|
|
181
|
+
* hook input's `model` object.
|
|
182
|
+
*
|
|
183
|
+
* Typed as `unknown` on purpose. The plugin `.d.ts` declares `model: Model`
|
|
184
|
+
* (non-optional), but this hook runs inside the host's transform chain: a throw
|
|
185
|
+
* here takes down ALL system enhancement for the turn, so the read never
|
|
186
|
+
* assumes the declared shape actually arrived.
|
|
187
|
+
*
|
|
188
|
+
* @returns the raw value, or `undefined` when the path is absent.
|
|
189
|
+
*/
|
|
190
|
+
export declare function readModelContextLimit(model: unknown): unknown;
|
|
191
|
+
/**
|
|
192
|
+
* Safely read `model.id` / `model.providerID` off the hook input's `model`.
|
|
193
|
+
*
|
|
194
|
+
* Same defensive posture as {@link readModelContextLimit}: the declared type
|
|
195
|
+
* says these are strings, but this runs on the host boundary. Empty strings are
|
|
196
|
+
* normalised to `undefined` so a blank identity never becomes a config-lookup
|
|
197
|
+
* key like `"/"`.
|
|
198
|
+
*/
|
|
199
|
+
export declare function readModelIdentity(model: unknown, key: 'id' | 'providerID'): string | undefined;
|
|
200
|
+
/**
|
|
201
|
+
* Resolve the context-window denominator and report which rung produced it.
|
|
202
|
+
*
|
|
203
|
+
* @see the module header for the full resolution order and its rationale.
|
|
204
|
+
*/
|
|
205
|
+
export declare function resolveContextWindow(inputs: ContextWindowInputs): ContextWindowResolution;
|
|
206
|
+
/**
|
|
207
|
+
* Convenience wrapper around {@link resolveContextWindow} for call sites that
|
|
208
|
+
* only need the number.
|
|
209
|
+
*/
|
|
210
|
+
export declare function resolveContextWindowTokens(inputs: ContextWindowInputs): number;
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -220,6 +220,24 @@ export declare const ScoringConfigSchema: z.ZodObject<{
|
|
|
220
220
|
}, z.core.$strip>>;
|
|
221
221
|
}, z.core.$strip>;
|
|
222
222
|
export type ScoringConfig = z.infer<typeof ScoringConfigSchema>;
|
|
223
|
+
/**
|
|
224
|
+
* LAST-RESORT context-budget denominator (tokens), used only when nothing
|
|
225
|
+
* better is available — rung 6 of the resolution order.
|
|
226
|
+
*
|
|
227
|
+
* DEFINED in `./context-window.ts` and re-exported here for the existing
|
|
228
|
+
* importers. It cannot live in this file: `context-window.ts` is loaded
|
|
229
|
+
* transitively by every context-budget consumer, and several test files replace
|
|
230
|
+
* `src/config/schema` with a non-spreading `mock.module` factory, so an import
|
|
231
|
+
* edge from `context-window.ts` into this module would make Bun throw
|
|
232
|
+
* `SyntaxError: Export named 'DEFAULT_MODEL_CONTEXT_TOKENS' not found` at
|
|
233
|
+
* import time. See the constant's own doc comment for the full history.
|
|
234
|
+
*
|
|
235
|
+
* A hardcoded denominator is wrong for any model whose window is not 128k. The
|
|
236
|
+
* budget denominator is derived from the live `model.limit.context` the host
|
|
237
|
+
* hands to `experimental.chat.system.transform`; this constant survives only as
|
|
238
|
+
* the no-information floor.
|
|
239
|
+
*/
|
|
240
|
+
export { DEFAULT_MODEL_CONTEXT_TOKENS } from './context-window';
|
|
223
241
|
export declare const ContextBudgetConfigSchema: z.ZodObject<{
|
|
224
242
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
225
243
|
warn_threshold: z.ZodDefault<z.ZodNumber>;
|
|
@@ -4,6 +4,14 @@ import { log } from '../utils/logger.js';
|
|
|
4
4
|
import type { ModelOverride } from '../utils/model-dispatch-fallback.js';
|
|
5
5
|
export declare const DEFAULT_EPHEMERAL_TIMEOUT_MS = 120000;
|
|
6
6
|
export declare const DEFAULT_EPHEMERAL_CLEANUP_TIMEOUT_MS = 500;
|
|
7
|
+
/**
|
|
8
|
+
* Bounded timeout for the graceful `session.abort()` step that precedes delete
|
|
9
|
+
* in the ephemeral teardown (#2123). opencode's `SessionProcessor.cleanup` can
|
|
10
|
+
* take up to ~250 ms under interruption (it awaits each pending tool-call
|
|
11
|
+
* deferred with a 250 ms timeout), so this must stay well above that or the
|
|
12
|
+
* abort would give up before the final part/message flush lands.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DEFAULT_EPHEMERAL_ABORT_TIMEOUT_MS = 5000;
|
|
7
15
|
export declare const DEFAULT_EPHEMERAL_PROMPT_BYTE_LIMIT: number;
|
|
8
16
|
export declare const MAX_EPHEMERAL_PROMPT_BYTE_LIMIT: number;
|
|
9
17
|
export declare const DEFAULT_EPHEMERAL_RESPONSE_BYTE_LIMIT: number;
|
|
@@ -48,8 +56,18 @@ export type EphemeralAgentDispatchResult = {
|
|
|
48
56
|
responseBytes: number;
|
|
49
57
|
costFields?: DelegationCostFields;
|
|
50
58
|
};
|
|
59
|
+
/**
|
|
60
|
+
* Bounded graceful abort of an ephemeral session. opencode's
|
|
61
|
+
* `POST /session/{id}/abort` resolves only after `Fiber.interrupt` on the
|
|
62
|
+
* run-loop fiber — which runs `SessionProcessor.cleanup` (the final
|
|
63
|
+
* `updatePart`/`updateMessage` flush) as a finalizer. Awaiting this BEFORE the
|
|
64
|
+
* delete is what closes the FOREIGN KEY constraint race (#2123). If the session
|
|
65
|
+
* is already idle, abort is a fast no-op. Best-effort: never throws.
|
|
66
|
+
*/
|
|
67
|
+
export declare function boundedAbortEphemeralSession(client: OpencodeClient, sessionId: string, timeoutMs?: number): Promise<void>;
|
|
51
68
|
export declare function boundedDeleteEphemeralSession(client: OpencodeClient, sessionId: string, timeoutMs?: number): Promise<void>;
|
|
52
69
|
export declare const _internals: {
|
|
70
|
+
boundedAbort: typeof boundedAbortEphemeralSession;
|
|
53
71
|
boundedDelete: typeof boundedDeleteEphemeralSession;
|
|
54
72
|
log: typeof log;
|
|
55
73
|
};
|
|
@@ -48,6 +48,7 @@ export declare function resolveEvaluationAgentName(agents: readonly Pick<Agent,
|
|
|
48
48
|
* primitive remains the single owner of cleanup and logging behavior.
|
|
49
49
|
*/
|
|
50
50
|
export declare const _internals: {
|
|
51
|
+
boundedAbort: typeof ephemeralDispatcherInternals.boundedAbort;
|
|
51
52
|
boundedDelete: typeof ephemeralDispatcherInternals.boundedDelete;
|
|
52
53
|
log: typeof ephemeralDispatcherInternals.log;
|
|
53
54
|
};
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* prompt) against the ack markers in the subagent's transcript:
|
|
8
8
|
*
|
|
9
9
|
* - For every ack whose ID was actually shown, emit a receipt event of the
|
|
10
|
-
* matching type (applied / ignored / violated / n_a). Acks for IDs that were
|
|
10
|
+
* matching type (applied / ignored / contradicted / violated / n_a). Acks for IDs that were
|
|
11
11
|
* never shown are DROPPED (anti-spoofing).
|
|
12
12
|
* - For every CRITICAL directive that was shown but never acknowledged, emit a
|
|
13
13
|
* `violated` event with reason `unacknowledged` and append an audit line to
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import { removeWorktreeProvisioningOwner } from './worktree-provisioning-owner';
|
|
3
|
+
/** File-operation seam for deterministic fail-closed recovery tests. */
|
|
4
|
+
export declare const _internals: {
|
|
5
|
+
statSync: fs.StatSyncFn;
|
|
6
|
+
removeWorktreeProvisioningOwner: typeof removeWorktreeProvisioningOwner;
|
|
7
|
+
};
|
|
1
8
|
export interface StandardWorktreeCollisionIdentity {
|
|
2
9
|
directory: string;
|
|
3
10
|
parentSessionId: string;
|
|
@@ -12,7 +12,7 @@ import type { PluginConfig, WorktreeIsolationConfig } from '../../config';
|
|
|
12
12
|
import { tryAcquireLock } from '../../parallel/file-locks';
|
|
13
13
|
import { bunSpawn } from '../../utils/bun-compat';
|
|
14
14
|
import type { WorktreeHandle } from '../../worktree';
|
|
15
|
-
import { attemptMergeBackFromDirty, cleanupOrphanedBranches, postMergeCleanup, provisionWorktree, removeWorktree, startupOrphanRecovery } from '../../worktree';
|
|
15
|
+
import { attemptMergeBackFromDirty, cleanupOrphanedBranches, postMergeCleanup, provisionWorktree, pruneStaleWorktreeMetadata, removeWorktree, startupOrphanRecovery } from '../../worktree';
|
|
16
16
|
import type { DirtyMergeOptions, MergeOperationProvenance } from '../../worktree/merge';
|
|
17
17
|
import { recordWorktreeProvisioningOwner, removeWorktreeProvisioningOwner } from './worktree-provisioning-owner';
|
|
18
18
|
/**
|
|
@@ -301,6 +301,7 @@ export declare const _internals: {
|
|
|
301
301
|
removeWorktree: typeof removeWorktree;
|
|
302
302
|
attemptMergeBackFromDirty: typeof attemptMergeBackFromDirty;
|
|
303
303
|
postMergeCleanup: typeof postMergeCleanup;
|
|
304
|
+
pruneStaleWorktreeMetadata: typeof pruneStaleWorktreeMetadata;
|
|
304
305
|
/** FR-201: read lane runtime profile from disk for spawn injection. */
|
|
305
306
|
readLaneEnvFileFromDisk: typeof readLaneEnvFileFromDisk;
|
|
306
307
|
/** FR-104: exposes serializationStateBySessionID for test setup (SC-111/SC-112/SC-113). */
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A provisional marker covers the bounded gap before `git worktree add`
|
|
3
|
+
* materializes the exact lane path. Once that path exists, path liveness wins
|
|
4
|
+
* and the marker remains protected regardless of age.
|
|
5
|
+
*/
|
|
6
|
+
export declare const WORKTREE_PROVISIONING_OWNER_LEASE_MS: number;
|
|
1
7
|
export declare const WORKTREE_LIFECYCLE_LOCK_FILE = ".swarm/locks/init-orphan-recovery.lock";
|
|
2
8
|
export interface WorktreeProvisioningOwner {
|
|
3
9
|
schemaVersion: 1 | 2;
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -11,8 +11,8 @@ export { extractCurrentPhase, extractCurrentPhaseFromPlan, extractCurrentTask, e
|
|
|
11
11
|
export { createFullAutoInterceptHook } from './full-auto-intercept';
|
|
12
12
|
export { checkFileAuthority, createGuardrailsHooks, DEFAULT_AGENT_AUTHORITY_RULES, } from './guardrails';
|
|
13
13
|
export { classifyMessage, classifyMessages, containsPlanContent, getCompletedToolOutputs, getToolNames, getToolParts, isDuplicateToolRead, isStaleError, isToolResult, MessagePriority, type MessagePriorityType, type MessageWithParts, } from './message-priority';
|
|
14
|
-
export { consolidateSystemMessages } from './messages-transform';
|
|
15
|
-
export { extractModelInfo, NATIVE_MODEL_LIMITS, PROVIDER_CAPS, resolveModelLimit, } from './model-limits';
|
|
14
|
+
export { consolidateSystemMessages, consolidateSystemMessagesInPlace, } from './messages-transform';
|
|
15
|
+
export { extractModelInfo, extractSessionId, lookupStaticModelLimit, NATIVE_MODEL_LIMITS, PROVIDER_CAPS, resolveModelLimit, } from './model-limits';
|
|
16
16
|
export { type CuratorDelegateFactory, createPhaseMonitorHook, } from './phase-monitor';
|
|
17
17
|
export { createPipelineTrackerHook } from './pipeline-tracker';
|
|
18
18
|
export { createRepoGraphBuilderHook, type RepoGraphBuilderHook, } from './repo-graph-builder';
|
|
@@ -18,8 +18,9 @@ import * as fs from 'node:fs';
|
|
|
18
18
|
import { scanDelegationFallbacksForRecovery, scanDelegationsForRecovery } from '../background/pending-delegations.js';
|
|
19
19
|
import { isLocked, listActiveLocks, tryAcquireLock } from '../parallel/file-locks';
|
|
20
20
|
import { removeWorktree } from '../worktree/core';
|
|
21
|
+
import { scanRegisteredWorktreeLiveness } from '../worktree/merge';
|
|
21
22
|
import { scanWorktreeMergeFailuresForRecovery } from './delegation-gate/worktree-merge-status';
|
|
22
|
-
import { scanWorktreeProvisioningOwnersForRecovery } from './delegation-gate/worktree-provisioning-owner';
|
|
23
|
+
import { removeWorktreeProvisioningOwner, scanWorktreeProvisioningOwnersForRecovery } from './delegation-gate/worktree-provisioning-owner';
|
|
23
24
|
type OwnershipTagSessionScan = {
|
|
24
25
|
status: 'ok';
|
|
25
26
|
sessionIds: string[];
|
|
@@ -49,6 +50,8 @@ export declare const _internals: {
|
|
|
49
50
|
scanDelegationFallbacksForRecovery: typeof scanDelegationFallbacksForRecovery;
|
|
50
51
|
scanWorktreeMergeFailuresForRecovery: typeof scanWorktreeMergeFailuresForRecovery;
|
|
51
52
|
scanWorktreeProvisioningOwnersForRecovery: typeof scanWorktreeProvisioningOwnersForRecovery;
|
|
53
|
+
scanRegisteredWorktreeLiveness: typeof scanRegisteredWorktreeLiveness;
|
|
54
|
+
removeWorktreeProvisioningOwner: typeof removeWorktreeProvisioningOwner;
|
|
52
55
|
};
|
|
53
56
|
export interface InitOrphanRecoveryResult {
|
|
54
57
|
attempted: boolean;
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Two integration points:
|
|
5
5
|
*
|
|
6
6
|
* 1. `experimental.chat.messages.transform` — scans the latest
|
|
7
|
-
* architect-authored message for
|
|
7
|
+
* architect-authored message for
|
|
8
|
+
* `KNOWLEDGE_APPLIED|IGNORED|CONTRADICTED|VIOLATED`
|
|
8
9
|
* markers and records them via `recordAcknowledgmentDeduped`. This
|
|
9
10
|
* runs BEFORE the architect's next tool call so the toolBefore gate
|
|
10
11
|
* sees the ack.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Knowledge application tracking — distinguishes shown / acknowledged / applied
|
|
3
|
-
* / ignored / violated outcomes for injected knowledge directives.
|
|
3
|
+
* / ignored / contradicted / violated outcomes for injected knowledge directives.
|
|
4
4
|
*
|
|
5
5
|
* Writes one JSONL line per outcome to `.swarm/knowledge-application.jsonl`,
|
|
6
6
|
* and updates per-entry retrieval-outcome counters on the source knowledge file.
|
|
@@ -13,12 +13,13 @@ export declare const MAX_LEGACY_APPLICATION_LOG_ENTRIES = 5000;
|
|
|
13
13
|
* Recognised forms (case-insensitive, line-anchored or inline):
|
|
14
14
|
* KNOWLEDGE_APPLIED: <id>
|
|
15
15
|
* KNOWLEDGE_IGNORED: <id> reason=<reason>
|
|
16
|
+
* KNOWLEDGE_CONTRADICTED: <id> reason=<observable conflict>
|
|
16
17
|
* KNOWLEDGE_VIOLATED: <id> reason=<reason>
|
|
17
18
|
* KNOWLEDGE_N_A: <id> reason=<reason> (delegate contract, Change 1)
|
|
18
19
|
*/
|
|
19
20
|
export interface ParsedAcknowledgment {
|
|
20
21
|
id: string;
|
|
21
|
-
result: 'applied' | 'ignored' | 'violated' | 'n_a';
|
|
22
|
+
result: 'applied' | 'ignored' | 'contradicted' | 'violated' | 'n_a';
|
|
22
23
|
reason?: string;
|
|
23
24
|
}
|
|
24
25
|
export declare function parseAcknowledgments(text: string): ParsedAcknowledgment[];
|
|
@@ -32,7 +33,7 @@ export interface RecordContext {
|
|
|
32
33
|
}
|
|
33
34
|
/** Record one or more knowledge IDs as "shown" (injected into context). */
|
|
34
35
|
export declare function recordKnowledgeShown(directory: string, ids: string[], ctx: RecordContext): Promise<void>;
|
|
35
|
-
/** Record an explicit acknowledgment outcome (applied / ignored / violated).
|
|
36
|
+
/** Record an explicit acknowledgment outcome (applied / ignored / contradicted / violated).
|
|
36
37
|
* Per-(sessionId, knowledgeId, result) dedup is enforced by the
|
|
37
38
|
* caller via swarmState.knowledgeAckDedup; this fn always records when
|
|
38
39
|
* invoked, so test code can trigger duplicates if needed. The runtime
|
|
@@ -57,7 +58,7 @@ export interface ShownNotAppliedQuery {
|
|
|
57
58
|
}
|
|
58
59
|
/**
|
|
59
60
|
* Returns the subset of `knowledgeIds` that have at least one "shown" record
|
|
60
|
-
* in the audit log without a subsequent "applied"/"ignored"/"violated" record
|
|
61
|
+
* in the audit log without a subsequent "applied"/"ignored"/"contradicted"/"violated" record
|
|
61
62
|
* in the same task or phase scope.
|
|
62
63
|
*/
|
|
63
64
|
export declare function getShownButNotAcknowledged(directory: string, q: ShownNotAppliedQuery): Promise<string[]>;
|
|
@@ -92,6 +92,10 @@ export declare function defaultExpectedToolsForAgent(agentName: string): string[
|
|
|
92
92
|
* are stripped on both sides so `mega_coder` matches a bare `coder`.
|
|
93
93
|
*/
|
|
94
94
|
export declare function matchesDelegateScope(entry: Pick<RankedEntry, 'applies_to_agents' | 'applies_to_tools'>, role: string, expectedTools: readonly string[]): boolean;
|
|
95
|
+
/** Inserts the knowledge block just before the last user message (recency position). */
|
|
96
|
+
declare function injectKnowledgeMessage(output: {
|
|
97
|
+
messages?: MessageWithParts[];
|
|
98
|
+
}, text: string): void;
|
|
95
99
|
/**
|
|
96
100
|
* Creates a knowledge injection hook that injects relevant knowledge into the
|
|
97
101
|
* architect's message context at phase start. Supports caching for re-injection
|
|
@@ -114,3 +118,15 @@ export declare const _internals: {
|
|
|
114
118
|
recordLessonsShown: typeof recordLessonsShown;
|
|
115
119
|
confirmEntriesPhase: typeof confirmEntriesPhase;
|
|
116
120
|
};
|
|
121
|
+
/**
|
|
122
|
+
* Tier-0 test seam (see `.opencode/skills/writing-tests/SKILL.md`). Exposes the
|
|
123
|
+
* real injection primitive and its sentinel so the
|
|
124
|
+
* `consolidateSystemMessages` interaction test (issue #1619) exercises the
|
|
125
|
+
* production splice position and message shape instead of a hand-copied fixture
|
|
126
|
+
* that could silently drift from this module.
|
|
127
|
+
*/
|
|
128
|
+
export declare const _test_exports: {
|
|
129
|
+
injectKnowledgeMessage: typeof injectKnowledgeMessage;
|
|
130
|
+
INJECTION_SENTINEL: string;
|
|
131
|
+
};
|
|
132
|
+
export {};
|
|
@@ -549,7 +549,7 @@ export interface KnowledgeRetrievalContext {
|
|
|
549
549
|
planConstraints?: string[];
|
|
550
550
|
mode?: RetrievalMode;
|
|
551
551
|
}
|
|
552
|
-
export type KnowledgeApplicationResult = 'shown' | 'acknowledged' | 'applied' | 'ignored' | 'violated';
|
|
552
|
+
export type KnowledgeApplicationResult = 'shown' | 'acknowledged' | 'applied' | 'ignored' | 'contradicted' | 'violated';
|
|
553
553
|
/** One line of .swarm/knowledge-application.jsonl. */
|
|
554
554
|
export interface KnowledgeApplicationRecord {
|
|
555
555
|
timestamp: string;
|
|
@@ -31,4 +31,22 @@ type PartsMessage = {
|
|
|
31
31
|
};
|
|
32
32
|
export type Message = FlatMessage | PartsMessage;
|
|
33
33
|
export declare function consolidateSystemMessages(messages: Message[]): Message[];
|
|
34
|
+
/**
|
|
35
|
+
* In-place variant of {@link consolidateSystemMessages} for use inside an
|
|
36
|
+
* `experimental.chat.messages.transform` handler.
|
|
37
|
+
*
|
|
38
|
+
* The OpenCode host invokes each plugin hook as `M(input, output)`, **discards
|
|
39
|
+
* the handler's return value**, and afterwards reads its OWN local message
|
|
40
|
+
* array (host binary offset ~100,667,665:
|
|
41
|
+
* `yield* d.trigger("experimental.chat.messages.transform",{},{messages:C})`
|
|
42
|
+
* followed by `Me.toModelMessagesEffect(C,Z)`). Therefore
|
|
43
|
+
* `output.messages = consolidateSystemMessages(output.messages)` is a *rebind*
|
|
44
|
+
* that the host never observes — it silently did nothing in production from the
|
|
45
|
+
* day it was written until issue #1619. Only mutating the array the host handed
|
|
46
|
+
* us is observable.
|
|
47
|
+
*
|
|
48
|
+
* The consolidated result is computed BEFORE the array is cleared, because
|
|
49
|
+
* `consolidateSystemMessages` reads the same array it is passed.
|
|
50
|
+
*/
|
|
51
|
+
export declare function consolidateSystemMessagesInPlace(messages: Message[]): void;
|
|
34
52
|
export {};
|
|
@@ -1,19 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provider-Aware Model Limit Resolution
|
|
2
|
+
* Provider-Aware Model Limit Resolution — STATIC FALLBACK ONLY.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* The
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* > **The two tables below are a last resort, not the source of truth.**
|
|
5
|
+
* > The authoritative context window is the live `model.limit.context` the host
|
|
6
|
+
* > hands to `experimental.chat.system.transform`, resolved through
|
|
7
|
+
* > `src/config/context-window.ts`. That value is already provider-specific:
|
|
8
|
+
* > the host's model catalog is keyed `providers[providerID].models[modelID]`,
|
|
9
|
+
* > and the on-disk catalog shows `github-copilot`'s `claude-sonnet-4.5` and
|
|
10
|
+
* > `anthropic`'s `claude-sonnet-4-5` carrying different `limit.context`
|
|
11
|
+
* > values. These tables are consulted only when no live value reached the
|
|
12
|
+
* > call site (the `experimental.chat.messages.transform` paths on the very
|
|
13
|
+
* > first turn of a session, before any `system.transform` has run).
|
|
14
|
+
*
|
|
15
|
+
* **These tables are known-stale and are deliberately NOT used to cap the live
|
|
16
|
+
* value.** `PROVIDER_CAPS` claims Copilot caps everything at 128 000; the live
|
|
17
|
+
* catalog shows Copilot Claude entries at 200 000 (`claude-sonnet-4.5`,
|
|
18
|
+
* `claude-sonnet-4.6`) and 1 000 000 (`claude-fable-5`), with only `gpt-4.1`
|
|
19
|
+
* actually at 128 000. Min-capping a correct live value against that would
|
|
20
|
+
* reintroduce the too-small denominator the live derivation exists to remove.
|
|
21
|
+
* `NATIVE_MODEL_LIMITS` is stale in the same direction (`claude-sonnet-4` is
|
|
22
|
+
* listed at 200 000; the catalog reports 216 000).
|
|
23
|
+
*
|
|
24
|
+
* Do not "refresh" these tables by hand — that is the maintenance treadmill the
|
|
25
|
+
* live derivation replaced. They exist so a first-turn `messages.transform`
|
|
26
|
+
* consumer degrades to a plausible number instead of the flat 128 000 floor.
|
|
9
27
|
*/
|
|
10
28
|
/**
|
|
11
29
|
* Native model context limits (in tokens) when used on their native platform.
|
|
30
|
+
*
|
|
31
|
+
* Static fallback only — see the module header.
|
|
12
32
|
*/
|
|
13
33
|
export declare const NATIVE_MODEL_LIMITS: Record<string, number>;
|
|
14
34
|
/**
|
|
15
35
|
* Provider-specific context caps that override native limits.
|
|
16
|
-
*
|
|
36
|
+
*
|
|
37
|
+
* Static fallback only, and known-stale — see the module header. This is NOT
|
|
38
|
+
* applied as a ceiling over the live `model.limit.context`.
|
|
17
39
|
*/
|
|
18
40
|
export declare const PROVIDER_CAPS: Record<string, number>;
|
|
19
41
|
/**
|
|
@@ -51,46 +73,82 @@ export declare function extractModelInfo(messages: MessageWithParts[]): {
|
|
|
51
73
|
modelID?: string;
|
|
52
74
|
providerID?: string;
|
|
53
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* Extracts the sessionID from a `experimental.chat.messages.transform` message
|
|
78
|
+
* array, scanning newest-first.
|
|
79
|
+
*
|
|
80
|
+
* The messages hooks receive no `input.sessionID` (the plugin type declares
|
|
81
|
+
* `input: {}`), but every message's `info` carries one. This is the key used to
|
|
82
|
+
* look up the live `model.limit.context` that the `system.transform` hook
|
|
83
|
+
* recorded for the session — see `getLiveContextWindow` in `src/state.ts`.
|
|
84
|
+
*
|
|
85
|
+
* @returns the sessionID, or `undefined` when no message carries one.
|
|
86
|
+
*/
|
|
87
|
+
export declare function extractSessionId(messages: MessageWithParts[] | undefined): string | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Static-table lookup used as `fallbackLookup` for
|
|
90
|
+
* {@link resolveContextWindow}. Preserves the historical precedence of
|
|
91
|
+
* the two tables relative to each other (provider cap first, then a
|
|
92
|
+
* longest-prefix native match), and is reachable only when no live
|
|
93
|
+
* `model.limit.context` was available.
|
|
94
|
+
*/
|
|
95
|
+
export declare function lookupStaticModelLimit(modelID?: string, providerID?: string): number | undefined;
|
|
54
96
|
/**
|
|
55
97
|
* Resolves the context limit for a given model/provider combination.
|
|
56
98
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
99
|
+
* Thin adapter over the single derivation in `src/config/context-window.ts` —
|
|
100
|
+
* this function exists so the `experimental.chat.messages.transform` consumers
|
|
101
|
+
* (`context-budget.ts`, `knowledge-injector.ts`, `tools/context-status.ts`)
|
|
102
|
+
* keep their existing `(modelID, providerID, overrides)` call shape. All
|
|
103
|
+
* ordering logic lives in the shared resolver; see its module header.
|
|
104
|
+
*
|
|
105
|
+
* Resolution order (first usable value wins):
|
|
106
|
+
* 1. `configOverrides["<providerID>/<modelID>"]`
|
|
107
|
+
* 2. `configOverrides["<modelID>"]`
|
|
108
|
+
* 3. `configOverrides.default`
|
|
109
|
+
* 4. `liveContextLimit` — the host's live `model.limit.context` for this session
|
|
110
|
+
* 5. `PROVIDER_CAPS[providerID]`, else a longest-prefix `NATIVE_MODEL_LIMITS`
|
|
111
|
+
* match (both known-stale; see the module header)
|
|
112
|
+
* 6. `DEFAULT_MODEL_CONTEXT_TOKENS` (128000)
|
|
113
|
+
*
|
|
114
|
+
* Two ordering changes vs. the pre-#1619 implementation, both deliberate:
|
|
115
|
+
* - `configOverrides.default` moved from below the static tables to above
|
|
116
|
+
* them. An explicitly authored user value losing to a hardcoded table was a
|
|
117
|
+
* defect; it is now consistent with the compound and model-only keys, which
|
|
118
|
+
* already outranked the tables.
|
|
119
|
+
* - The live `model.limit.context` was inserted above both tables, which is
|
|
120
|
+
* the entire point of this change.
|
|
121
|
+
*
|
|
122
|
+
* Any value that is not a finite number ≥ 1000 is skipped rather than used, so
|
|
123
|
+
* a malformed override or a catalog entry with `limit.context: 0` can never
|
|
124
|
+
* produce a `NaN` / `Infinity` percentage.
|
|
64
125
|
*
|
|
65
126
|
* @param modelID - The model identifier (e.g., "claude-sonnet-4-6", "gpt-5")
|
|
66
|
-
* @param providerID - The provider identifier (e.g., "copilot", "anthropic")
|
|
67
|
-
* @param configOverrides - User configuration overrides
|
|
127
|
+
* @param providerID - The provider identifier (e.g., "github-copilot", "anthropic")
|
|
128
|
+
* @param configOverrides - User configuration overrides (`context_budget.model_limits`)
|
|
129
|
+
* @param liveContextLimit - The live `model.limit.context` recorded for this
|
|
130
|
+
* session by the `system.transform` hook, when one has been seen
|
|
68
131
|
* @returns The resolved context limit in tokens
|
|
69
132
|
*
|
|
70
133
|
* @example
|
|
71
|
-
* //
|
|
72
|
-
* resolveModelLimit("claude-sonnet-4-6", "copilot", {})
|
|
73
|
-
* // Returns: 128000
|
|
74
|
-
*
|
|
75
|
-
* @example
|
|
76
|
-
* // Native limit (anthropic)
|
|
77
|
-
* resolveModelLimit("claude-sonnet-4-6", "anthropic", {})
|
|
134
|
+
* // Live value wins over the stale static tables
|
|
135
|
+
* resolveModelLimit("claude-sonnet-4-6", "github-copilot", {}, 200000)
|
|
78
136
|
* // Returns: 200000
|
|
79
137
|
*
|
|
80
138
|
* @example
|
|
81
|
-
* //
|
|
82
|
-
* resolveModelLimit("gpt-5", "copilot", { "copilot/gpt-5":
|
|
83
|
-
* // Returns:
|
|
139
|
+
* // Explicit user override beats the live value
|
|
140
|
+
* resolveModelLimit("gpt-5", "github-copilot", { "github-copilot/gpt-5": 60000 }, 400000)
|
|
141
|
+
* // Returns: 60000
|
|
84
142
|
*
|
|
85
143
|
* @example
|
|
86
|
-
* //
|
|
144
|
+
* // No live value: falls back to the static table (prefix match)
|
|
87
145
|
* resolveModelLimit("claude-sonnet-4-6-20260301", "anthropic", {})
|
|
88
146
|
* // Returns: 200000
|
|
89
147
|
*
|
|
90
148
|
* @example
|
|
91
|
-
* //
|
|
92
|
-
* resolveModelLimit(undefined, undefined, {})
|
|
149
|
+
* // Malformed live value is ignored, not divided by
|
|
150
|
+
* resolveModelLimit(undefined, undefined, {}, 0)
|
|
93
151
|
* // Returns: 128000
|
|
94
152
|
*/
|
|
95
|
-
export declare function resolveModelLimit(modelID?: string, providerID?: string, configOverrides?: Record<string, number
|
|
153
|
+
export declare function resolveModelLimit(modelID?: string, providerID?: string, configOverrides?: Record<string, number>, liveContextLimit?: unknown): number;
|
|
96
154
|
export {};
|