@jslee124/forge 0.3.0 → 0.3.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/dist/index.js +1177 -90
- package/package.json +2 -1
- package/resources/docs/en/ARCHITECTURE.md +519 -0
- package/resources/docs/en/AUTHENTICATION.md +224 -0
- package/resources/docs/en/CLI_UI.md +266 -0
- package/resources/docs/en/CONFIGURATION.md +263 -0
- package/resources/docs/en/CONTEXT_MANAGEMENT.md +692 -0
- package/resources/docs/en/GETTING_STARTED.md +241 -0
- package/resources/docs/en/PLUGINS.md +622 -0
- package/resources/docs/en/PRODUCT.md +157 -0
- package/resources/docs/en/PROJECT_CONTEXT.md +225 -0
- package/resources/docs/en/RELEASING.md +94 -0
- package/resources/docs/en/SECURITY.md +272 -0
- package/resources/docs/en/SESSIONS.md +134 -0
- package/resources/docs/en/TROUBLESHOOTING.md +256 -0
- package/resources/docs/index.json +24334 -0
- package/resources/docs/zh-CN/ARCHITECTURE.md +174 -0
- package/resources/docs/zh-CN/AUTHENTICATION.md +96 -0
- package/resources/docs/zh-CN/CLI_UI.md +112 -0
- package/resources/docs/zh-CN/CONFIGURATION.md +221 -0
- package/resources/docs/zh-CN/CONTEXT_MANAGEMENT.md +200 -0
- package/resources/docs/zh-CN/GETTING_STARTED.md +193 -0
- package/resources/docs/zh-CN/PLUGINS.md +286 -0
- package/resources/docs/zh-CN/PRODUCT.md +86 -0
- package/resources/docs/zh-CN/PROJECT_CONTEXT.md +130 -0
- package/resources/docs/zh-CN/RELEASING.md +86 -0
- package/resources/docs/zh-CN/SECURITY.md +92 -0
- package/resources/docs/zh-CN/SESSIONS.md +69 -0
- package/resources/docs/zh-CN/TROUBLESHOOTING.md +185 -0
- package/resources/skills/forge-plugin-creator/SKILL.md +70 -0
- package/resources/skills/forge-plugin-creator/references/plugin-api.md +36 -0
- package/resources/skills/forge-plugin-creator/templates/index.mjs +30 -0
- package/resources/skills/forge-plugin-creator/templates/plugin.json +8 -0
- package/resources/skills/forge-plugin-creator/templates/plugin.test-template.ts +14 -0
- package/resources/skills/forge-product-help/SKILL.md +16 -0
|
@@ -0,0 +1,692 @@
|
|
|
1
|
+
# Context Management Improvement Plan
|
|
2
|
+
|
|
3
|
+
简体中文 · Documentation index
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
Roadmap Milestone 10 is implemented. This document records the design,
|
|
8
|
+
invariants, rollout decision, and follow-up live-evaluation gates. The default
|
|
9
|
+
remains `warn`; automatic checkpoint generation is opt-in until the published
|
|
10
|
+
provider-quality gates pass.
|
|
11
|
+
|
|
12
|
+
The first shipped Forge checkpoint uses a deterministic, redacted extractive
|
|
13
|
+
summarizer so default tests and manual `/compact` make no paid model call. It
|
|
14
|
+
allocates bounded space across every eligible historical message, removes
|
|
15
|
+
authority-like approval claims, and labels verification text as historical.
|
|
16
|
+
The checkpoint schema and adapter capability contract support opaque
|
|
17
|
+
provider-native state, but the current OpenAI AI SDK and DeepSeek adapters
|
|
18
|
+
advertise native compaction as unsupported because their active transports do
|
|
19
|
+
not yet expose a safe compact-item round trip.
|
|
20
|
+
|
|
21
|
+
## Why this work is next
|
|
22
|
+
|
|
23
|
+
Forge already separates project instructions, completed conversation turns,
|
|
24
|
+
the current user request, and provider continuation data. It also bounds
|
|
25
|
+
instruction files, tool output, model steps, tool calls, and persisted session
|
|
26
|
+
size. These controls make execution inspectable, but they do not manage a
|
|
27
|
+
model's token window.
|
|
28
|
+
|
|
29
|
+
Today, every completed user/assistant turn is sent again on the next native
|
|
30
|
+
Forge request. A long session can therefore fail at the provider boundary even
|
|
31
|
+
when its persisted JSON remains within the session size limit. During a run,
|
|
32
|
+
assistant tool calls and tool results also accumulate through provider
|
|
33
|
+
continuation data. Forge currently has no request preflight, token-aware history
|
|
34
|
+
selection, durable summary checkpoint, or automatic compaction.
|
|
35
|
+
|
|
36
|
+
The next improvement should solve those concrete problems before adding vector
|
|
37
|
+
retrieval. Repository retrieval and conversation compaction are different:
|
|
38
|
+
|
|
39
|
+
- Repository retrieval decides which source files to inspect. Forge already has
|
|
40
|
+
bounded `list_files`, `search`, and `read_file` tools for this.
|
|
41
|
+
- Conversation management decides which prior turns and run observations fit in
|
|
42
|
+
the next model request.
|
|
43
|
+
- Persistent semantic memory decides what knowledge should survive beyond the
|
|
44
|
+
transcript. That remains out of scope for Milestone 10.
|
|
45
|
+
|
|
46
|
+
## Market review
|
|
47
|
+
|
|
48
|
+
This plan was reviewed on 2026-08-19 against current first-party documentation
|
|
49
|
+
for OpenAI's Responses API, OpenCode V2, and Claude Code. Public OpenAI
|
|
50
|
+
documentation establishes the compaction mechanisms available to Codex-like
|
|
51
|
+
clients, but does not document Codex's exact client-side automatic threshold;
|
|
52
|
+
this plan does not infer that private implementation detail.
|
|
53
|
+
|
|
54
|
+
| System | Confirmed approach | Lesson for Forge |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| OpenAI Responses API | Supports threshold-based server-side compaction and a standalone compact endpoint. The returned compaction item is encrypted, opaque, and carried forward as provider state. | Make compaction an adapter capability; do not require all providers to expose a human-readable summary. |
|
|
57
|
+
| OpenCode V2 | Estimates the rendered prompt, messages, and tools; compacts before a call; keeps a recent serialized tail; preserves durable messages; and retries one clean provider overflow. | Budget the final request, retain a bounded tail, preserve the transcript, and add one-shot recovery without duplicate input. |
|
|
58
|
+
| Claude Code | Clears older tool outputs before summarizing conversation history, exposes `/context` and `/compact`, reloads persistent instructions, defers some tool schemas, and stops repeated ineffective compaction. | Treat tool output and tool definitions as first-class budget consumers and add a no-progress guard. |
|
|
59
|
+
|
|
60
|
+
Primary references:
|
|
61
|
+
|
|
62
|
+
- [OpenAI API compaction](https://developers.openai.com/api/docs/guides/compaction)
|
|
63
|
+
- [OpenAI API conversation state](https://developers.openai.com/api/docs/guides/conversation-state)
|
|
64
|
+
- [OpenCode V2 compaction](https://opencode.ai/v2/docs/compaction)
|
|
65
|
+
- [OpenCode V2 configuration](https://opencode.ai/v2/docs/config#compaction)
|
|
66
|
+
- [Claude Code context management](https://code.claude.com/docs/en/how-claude-code-works#the-context-window)
|
|
67
|
+
- [Claude Agent SDK compaction](https://code.claude.com/docs/en/agent-sdk/agent-loop#automatic-compaction)
|
|
68
|
+
- [Claude Code memory](https://code.claude.com/docs/en/memory)
|
|
69
|
+
|
|
70
|
+
### Review conclusions
|
|
71
|
+
|
|
72
|
+
The original direction remains sound: Forge should retain a lossless transcript,
|
|
73
|
+
derive a bounded active view, keep summaries below current instructions, and
|
|
74
|
+
delay vector RAG. The review changes the implementation in six ways:
|
|
75
|
+
|
|
76
|
+
1. Reserve `max(requested output, buffer)` rather than subtracting both values
|
|
77
|
+
independently and wasting usable input capacity.
|
|
78
|
+
2. Support two compaction strategies: provider-native opaque compaction and a
|
|
79
|
+
Forge-generated inspectable checkpoint.
|
|
80
|
+
3. Prune completed old tool outputs before summarizing the broader conversation.
|
|
81
|
+
4. Recover once from a clean provider-classified overflow, then fail honestly.
|
|
82
|
+
5. Detect compaction thrashing instead of repeatedly paying for summaries that
|
|
83
|
+
reclaim too little space.
|
|
84
|
+
6. Measure tool-schema cost and defer or narrow advertised tools only when the
|
|
85
|
+
trace data shows it is worthwhile.
|
|
86
|
+
|
|
87
|
+
### Forge engine coverage
|
|
88
|
+
|
|
89
|
+
Milestone 10 must cover two different execution paths:
|
|
90
|
+
|
|
91
|
+
- **Native Forge Engine:** `runAgent` sends structured instructions,
|
|
92
|
+
conversation messages, tools, and adapter-owned continuation. It can use a
|
|
93
|
+
Forge checkpoint or an adapter's provider-native compaction.
|
|
94
|
+
- **Codex Engine:** the current CLI serializes the entire Forge conversation as
|
|
95
|
+
JSON inside each new Codex prompt. Context management inside Codex App Server
|
|
96
|
+
cannot remove the cost of that newly injected wrapper. The first fix is to
|
|
97
|
+
feed `codexPrompt` the same bounded active view used by native engines and
|
|
98
|
+
report the wrapper cost. A later experiment may map a Forge session to a
|
|
99
|
+
persistent App Server thread so only the new user turn is submitted, but that
|
|
100
|
+
requires explicit lifecycle, resume, and security semantics.
|
|
101
|
+
|
|
102
|
+
Forge must not claim control over Codex's internal compaction threshold. It may
|
|
103
|
+
record App Server context or compaction events when the public protocol exposes
|
|
104
|
+
them, but otherwise treats that layer as engine-owned and opaque.
|
|
105
|
+
|
|
106
|
+
## Goals
|
|
107
|
+
|
|
108
|
+
Milestone 10 should:
|
|
109
|
+
|
|
110
|
+
1. Prevent predictable context-window failures before a paid provider request.
|
|
111
|
+
2. Make every context-selection decision visible in structured events and
|
|
112
|
+
`forge inspect`.
|
|
113
|
+
3. Preserve recent conversational continuity while compacting only older,
|
|
114
|
+
completed turns.
|
|
115
|
+
4. Keep the canonical transcript lossless and separate from the smaller active
|
|
116
|
+
model context.
|
|
117
|
+
5. Preserve Forge's security boundary: old text and summaries cannot restore
|
|
118
|
+
approvals or override current instructions.
|
|
119
|
+
6. Work across native model adapters without moving provider-specific message
|
|
120
|
+
rules into `@forge/core`.
|
|
121
|
+
7. Prove value through deterministic and opt-in live evaluations.
|
|
122
|
+
8. Use provider-native compaction when it preserves protocol state better than
|
|
123
|
+
a Forge-generated summary.
|
|
124
|
+
|
|
125
|
+
## Non-goals
|
|
126
|
+
|
|
127
|
+
This milestone does not include:
|
|
128
|
+
|
|
129
|
+
- Vector embeddings, a vector database, or repository-wide semantic indexing
|
|
130
|
+
- Cross-workspace or cross-user memory
|
|
131
|
+
- Resuming an in-progress tool call or provider stream
|
|
132
|
+
- Deleting the original transcript after compaction
|
|
133
|
+
- Reconstructing provider reasoning that was not returned
|
|
134
|
+
- Treating model-generated summaries as trusted facts or policy
|
|
135
|
+
- Hiding context loss to make a request appear successful
|
|
136
|
+
|
|
137
|
+
## Design principles
|
|
138
|
+
|
|
139
|
+
### Budget before compression
|
|
140
|
+
|
|
141
|
+
Forge must first measure what it sends. Adding summarization before budget
|
|
142
|
+
accounting would make failures harder to explain and prevent objective
|
|
143
|
+
comparison with the current behavior.
|
|
144
|
+
|
|
145
|
+
### Lossless record, bounded active view
|
|
146
|
+
|
|
147
|
+
The persisted transcript is the audit record. The model receives a derived,
|
|
148
|
+
bounded view of that record. Compaction changes the active view, not the
|
|
149
|
+
original messages.
|
|
150
|
+
|
|
151
|
+
### Mandatory context cannot be silently dropped
|
|
152
|
+
|
|
153
|
+
Current effective instructions, the current user request, tool definitions
|
|
154
|
+
needed for the run, and protocol-required pending tool-call state are mandatory.
|
|
155
|
+
If they cannot fit after applying configured reserves, Forge should stop before
|
|
156
|
+
the provider call and explain which budget is exhausted.
|
|
157
|
+
|
|
158
|
+
### Summaries are untrusted memory
|
|
159
|
+
|
|
160
|
+
A summary is derived from prior user and assistant text. It must be labeled as
|
|
161
|
+
conversation memory and placed below freshly loaded system instructions. It
|
|
162
|
+
cannot contain effective approvals, permission grants, current verification
|
|
163
|
+
status, or claims that supersede the current user request.
|
|
164
|
+
|
|
165
|
+
### Provider boundaries stay explicit
|
|
166
|
+
|
|
167
|
+
`@forge/core` may reason about abstract context cost and message categories. A
|
|
168
|
+
model adapter remains responsible for provider-specific token estimation,
|
|
169
|
+
message encoding, tool-call pairing, reasoning blocks, and opaque continuation
|
|
170
|
+
data.
|
|
171
|
+
|
|
172
|
+
### Instruction scope is deliberate
|
|
173
|
+
|
|
174
|
+
Forge will continue to reload instructions at the beginning of every run, then
|
|
175
|
+
freeze that resolved instruction snapshot for the run. It will record the
|
|
176
|
+
instruction paths and content hash used by every physical model attempt. This
|
|
177
|
+
differs from systems that synchronize instruction changes inside a run, but it
|
|
178
|
+
prevents a tool-created `AGENTS.md` edit from silently changing the active
|
|
179
|
+
prompt halfway through the same task. A later milestone may evaluate dynamic
|
|
180
|
+
instruction epochs as an explicit behavior.
|
|
181
|
+
|
|
182
|
+
## Context model
|
|
183
|
+
|
|
184
|
+
Forge should classify request content instead of treating it as one string:
|
|
185
|
+
|
|
186
|
+
| Class | Examples | Retention rule |
|
|
187
|
+
| --- | --- | --- |
|
|
188
|
+
| Mandatory instructions | Current `AGENTS.md`, bounded Skill catalog/selection directives, plugin prompt contributions | Reload every run; never summarized; loaded Skill bodies enter as bounded tool results |
|
|
189
|
+
| Current request | The active user prompt and referenced paths | Never summarized or dropped |
|
|
190
|
+
| Protocol state | Pending assistant tool call, matching tool result, provider continuation | Preserve exactly as required by the adapter |
|
|
191
|
+
| Recent conversation | Most recent completed user/assistant turns | Keep verbatim within a configurable tail budget |
|
|
192
|
+
| Older conversation | A completed prefix of earlier turns | Eligible for checkpoint summarization |
|
|
193
|
+
| Repository observations | File reads, searches, command output | Run-scoped; bounded at tool boundaries and re-read when needed |
|
|
194
|
+
| Advertised tools | Built-in and plugin tool names, descriptions, and schemas | Count every request; narrow or defer only through an explicit capability |
|
|
195
|
+
| Audit evidence | Full transcript and JSONL run traces | Persist separately; not automatically injected |
|
|
196
|
+
|
|
197
|
+
The initial request order remains conceptually:
|
|
198
|
+
|
|
199
|
+
```text
|
|
200
|
+
current effective instructions
|
|
201
|
+
derived conversation-memory checkpoint, if any
|
|
202
|
+
recent verbatim conversation turns
|
|
203
|
+
current user request
|
|
204
|
+
tool definitions
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Within a run, adapter-owned continuation and Forge tool results extend that
|
|
208
|
+
initial request according to the provider protocol.
|
|
209
|
+
|
|
210
|
+
## Token budget
|
|
211
|
+
|
|
212
|
+
### Capability contract
|
|
213
|
+
|
|
214
|
+
Add a provider-neutral capability description exposed by each adapter:
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
type JsonValue =
|
|
218
|
+
| null
|
|
219
|
+
| boolean
|
|
220
|
+
| number
|
|
221
|
+
| string
|
|
222
|
+
| readonly JsonValue[]
|
|
223
|
+
| { readonly [key: string]: JsonValue };
|
|
224
|
+
|
|
225
|
+
interface ModelContextCapabilities {
|
|
226
|
+
contextWindowTokens: number;
|
|
227
|
+
maxOutputTokens?: number;
|
|
228
|
+
estimateRequestTokens(request: ModelRequest): Promise<TokenEstimate>;
|
|
229
|
+
nativeCompaction: "unsupported" | "opaque-provider-item";
|
|
230
|
+
continuationProjection: "unsupported" | "adapter-owned";
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
interface TokenEstimate {
|
|
234
|
+
tokens: number;
|
|
235
|
+
method: "provider-tokenizer" | "sdk" | "conservative-fallback";
|
|
236
|
+
confidence: "exact" | "estimated";
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Capabilities must come from an explicit, tested adapter table or provider API.
|
|
241
|
+
Unknown models must not inherit an optimistic window. They should use a
|
|
242
|
+
conservative configured fallback and expose that provenance.
|
|
243
|
+
|
|
244
|
+
### Budget calculation
|
|
245
|
+
|
|
246
|
+
Before each model step, calculate:
|
|
247
|
+
|
|
248
|
+
```text
|
|
249
|
+
available input budget
|
|
250
|
+
= model context window
|
|
251
|
+
- max(requested output tokens, safety buffer tokens)
|
|
252
|
+
|
|
253
|
+
remaining history budget
|
|
254
|
+
= available input budget
|
|
255
|
+
- current instructions
|
|
256
|
+
- current request
|
|
257
|
+
- tool definitions
|
|
258
|
+
- protocol-required continuation
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Initial configuration should expose only values users can reason about:
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
{
|
|
265
|
+
"context": {
|
|
266
|
+
"mode": "warn",
|
|
267
|
+
"reservedOutputTokens": 4096,
|
|
268
|
+
"bufferTokens": 8192,
|
|
269
|
+
"recentTailTokens": 12000,
|
|
270
|
+
"summaryTargetTokens": 1200
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Recommended modes:
|
|
276
|
+
|
|
277
|
+
- `off`: preserve current behavior but continue reporting provider usage.
|
|
278
|
+
- `warn`: run preflight and warn; reject only when mandatory context cannot fit.
|
|
279
|
+
- `compact`: use a valid checkpoint and create a new one when thresholds require
|
|
280
|
+
it. This remains opt-in until evaluation gates pass.
|
|
281
|
+
|
|
282
|
+
Project configuration may lower budgets or select a stricter mode, but it must
|
|
283
|
+
not increase user-defined ceilings or disable a user-required guard.
|
|
284
|
+
|
|
285
|
+
`bufferTokens` is not an additional output reserve. The larger of the output
|
|
286
|
+
allowance and buffer is subtracted once. This follows the practical pattern in
|
|
287
|
+
OpenCode and avoids the original plan's unnecessarily conservative double
|
|
288
|
+
reservation while still leaving room for reasoning and provider variance.
|
|
289
|
+
|
|
290
|
+
### Estimation accuracy
|
|
291
|
+
|
|
292
|
+
Every completed provider step should compare the preflight estimate with
|
|
293
|
+
provider-reported input tokens when available. Store aggregate error, not raw
|
|
294
|
+
secret material. A model whose estimator repeatedly undercounts beyond the
|
|
295
|
+
safety buffer should be blocked from automatic compaction rollout until its
|
|
296
|
+
adapter is corrected.
|
|
297
|
+
|
|
298
|
+
## Conversation compaction
|
|
299
|
+
|
|
300
|
+
### Selection algorithm
|
|
301
|
+
|
|
302
|
+
For the first compaction implementation:
|
|
303
|
+
|
|
304
|
+
1. Reload current instructions and compute mandatory cost.
|
|
305
|
+
2. Keep the current request untouched.
|
|
306
|
+
3. Keep a bounded recent serialized tail up to `recentTailTokens`, ending only
|
|
307
|
+
at a safe message or tool-protocol boundary.
|
|
308
|
+
4. Select only a contiguous completed prefix older than that window.
|
|
309
|
+
5. Reuse an existing checkpoint when its source range, tail range, and hashes
|
|
310
|
+
still match.
|
|
311
|
+
6. Use provider-native compaction when the adapter supports it; otherwise
|
|
312
|
+
summarize that prefix to the target budget.
|
|
313
|
+
7. Re-estimate the complete request.
|
|
314
|
+
8. If it still does not fit, reduce the recent tail only down to a documented
|
|
315
|
+
hard floor; never remove the current turn or protocol-required state.
|
|
316
|
+
9. If safe reduction is impossible, stop with `limit_reached` and report the
|
|
317
|
+
context budget breakdown.
|
|
318
|
+
|
|
319
|
+
A contiguous prefix makes provenance understandable and avoids a summary built
|
|
320
|
+
from unexplained holes in the conversation.
|
|
321
|
+
|
|
322
|
+
### Checkpoint schema
|
|
323
|
+
|
|
324
|
+
Session schema version 2 should retain `messages` as the canonical transcript
|
|
325
|
+
and add an optional derived checkpoint:
|
|
326
|
+
|
|
327
|
+
```ts
|
|
328
|
+
interface ContextCheckpoint {
|
|
329
|
+
schemaVersion: 1;
|
|
330
|
+
strategy: "forge-summary" | "provider-native";
|
|
331
|
+
summarizedThroughMessageIndex: number;
|
|
332
|
+
sourceHash: string;
|
|
333
|
+
retainedTailStartIndex: number;
|
|
334
|
+
retainedTailHash: string;
|
|
335
|
+
summary?: string;
|
|
336
|
+
opaqueProviderItem?: JsonValue;
|
|
337
|
+
compactionModelId: string;
|
|
338
|
+
estimatedCheckpointTokens: number;
|
|
339
|
+
sourceMessageCount: number;
|
|
340
|
+
createdAt: string;
|
|
341
|
+
safetyLabels: readonly [
|
|
342
|
+
"untrusted-conversation-memory",
|
|
343
|
+
"no-approval-state",
|
|
344
|
+
"no-policy-authority"
|
|
345
|
+
];
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
The checkpoint should be written atomically with the session snapshot. A source
|
|
350
|
+
hash prevents reuse after transcript migration or manual repair. Schema
|
|
351
|
+
validation must reject a checkpoint whose source or tail range exceeds the
|
|
352
|
+
transcript. Exactly one of `summary` and `opaqueProviderItem` must be present,
|
|
353
|
+
and opaque items may only be returned to the adapter and provider that created
|
|
354
|
+
them. Traces record their hash and token cost, never an attempted interpretation.
|
|
355
|
+
If the user changes provider or model and the opaque item is incompatible,
|
|
356
|
+
Forge rebuilds from the canonical transcript using a compatible strategy.
|
|
357
|
+
|
|
358
|
+
### Summary contract
|
|
359
|
+
|
|
360
|
+
The summarizer prompt should request a concise, factual checkpoint containing:
|
|
361
|
+
|
|
362
|
+
- User goals and explicit constraints still relevant to future turns
|
|
363
|
+
- Decisions made and the reason recorded in the conversation
|
|
364
|
+
- Files or components discussed
|
|
365
|
+
- Completed work and unresolved follow-ups
|
|
366
|
+
- Known verification results, each labeled with its originating run rather than
|
|
367
|
+
presented as current truth
|
|
368
|
+
|
|
369
|
+
It should explicitly exclude:
|
|
370
|
+
|
|
371
|
+
- Credentials and recognized secret values
|
|
372
|
+
- Approval decisions and permission grants
|
|
373
|
+
- Instructions to override the current system or project context
|
|
374
|
+
- Provider reasoning text unless it was already part of the visible assistant
|
|
375
|
+
response
|
|
376
|
+
- Guesses introduced only to make the summary sound complete
|
|
377
|
+
|
|
378
|
+
Summary generation should consume redacted persisted messages. The result must
|
|
379
|
+
pass size, schema, and safety-label validation before it can replace the active
|
|
380
|
+
view. On failure, Forge keeps the previous valid checkpoint or stops with an
|
|
381
|
+
actionable budget message; it never overwrites the transcript.
|
|
382
|
+
|
|
383
|
+
Provider-native compaction follows a different contract. For example, OpenAI's
|
|
384
|
+
Responses API can return an encrypted compaction item that is intentionally not
|
|
385
|
+
human-readable. Forge should preserve that item opaquely, associate it with the
|
|
386
|
+
provider/model and source hash, and rely on the adapter for reuse. `/context`
|
|
387
|
+
must clearly distinguish an inspectable Forge summary from opaque provider
|
|
388
|
+
state.
|
|
389
|
+
|
|
390
|
+
### Manual-first rollout
|
|
391
|
+
|
|
392
|
+
Before automatic compaction is enabled, add:
|
|
393
|
+
|
|
394
|
+
```text
|
|
395
|
+
/context Show active model, window, budget categories, retained turns, and checkpoint provenance
|
|
396
|
+
/compact --dry-run Preview the eligible range and projected budget without a model call
|
|
397
|
+
/compact Generate a checkpoint and show the new estimate
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
The explicit `/compact` command is sufficient user intent and does not need a
|
|
401
|
+
second confirmation prompt because it neither deletes the transcript nor grants
|
|
402
|
+
authority. Manual compaction is not a security approval for later tools. The
|
|
403
|
+
output must make clear that the full transcript is retained.
|
|
404
|
+
|
|
405
|
+
## In-run context pressure
|
|
406
|
+
|
|
407
|
+
Conversation checkpoints solve pressure between completed runs. Tool-heavy runs
|
|
408
|
+
can still grow through assistant calls, provider reasoning blocks, and tool
|
|
409
|
+
results.
|
|
410
|
+
|
|
411
|
+
The initial safe behavior should be:
|
|
412
|
+
|
|
413
|
+
1. Bound tool output at execution as Forge already does.
|
|
414
|
+
2. Ask adapters to estimate the complete next request, including continuation.
|
|
415
|
+
3. Keep pending tool calls and their results intact.
|
|
416
|
+
4. For older completed tool interactions, let the adapter replace large output
|
|
417
|
+
with an explicit bounded projection containing the tool name, success state,
|
|
418
|
+
truncation marker, content hash, and a short result excerpt.
|
|
419
|
+
5. Avoid adding a second copy of tool output outside the canonical tool result.
|
|
420
|
+
6. Prefer a targeted `read_file` or `search` retry over retaining a larger
|
|
421
|
+
observation indefinitely.
|
|
422
|
+
7. Include every advertised tool schema in the estimate. If schemas become a
|
|
423
|
+
material fixed cost, evaluate a provider-supported tool-search/catalog
|
|
424
|
+
mechanism or a deterministic task-specific subset; never silently hide a
|
|
425
|
+
tool the runtime already promised to the model.
|
|
426
|
+
8. Stop with `limit_reached` before a request that cannot fit safely.
|
|
427
|
+
|
|
428
|
+
Do not generically rewrite opaque continuation objects in `@forge/core`.
|
|
429
|
+
Provider-specific in-run compaction may be added later only when an adapter can
|
|
430
|
+
prove that it preserves tool-call/result pairing and required reasoning blocks.
|
|
431
|
+
Until then, stopping honestly is safer than sending a malformed continuation.
|
|
432
|
+
|
|
433
|
+
### Overflow recovery
|
|
434
|
+
|
|
435
|
+
Preflight estimation is approximate, so adapters should classify provider
|
|
436
|
+
context-overflow errors. Forge may compact and retry the physical model attempt
|
|
437
|
+
once only when the failed attempt produced no assistant text, tool call, tool
|
|
438
|
+
result, or other externally visible retry evidence. The retry must reuse the
|
|
439
|
+
same admitted user input rather than append it again. A second overflow becomes
|
|
440
|
+
an ordinary failure with the estimate and provider limit in the trace.
|
|
441
|
+
|
|
442
|
+
### No-progress guard
|
|
443
|
+
|
|
444
|
+
Compaction must not loop when fixed instructions, the current request, or tool
|
|
445
|
+
schemas dominate the window. Track reclaimed tokens and compaction attempts for
|
|
446
|
+
the active input. Stop when any of these occurs:
|
|
447
|
+
|
|
448
|
+
- The same source hash has already been compacted for the same attempt.
|
|
449
|
+
- The checkpoint reclaims less than the runtime minimum useful tokens.
|
|
450
|
+
- The request remains over budget after one overflow recovery.
|
|
451
|
+
- The run reaches its compaction-attempt limit.
|
|
452
|
+
|
|
453
|
+
This mirrors the practical failure handling documented by OpenCode and Claude
|
|
454
|
+
Code while keeping Forge's terminal status explicit.
|
|
455
|
+
|
|
456
|
+
## Events, traces, and inspection
|
|
457
|
+
|
|
458
|
+
Add versioned events such as:
|
|
459
|
+
|
|
460
|
+
```text
|
|
461
|
+
context.budgeted
|
|
462
|
+
context.warning
|
|
463
|
+
context.compaction.started
|
|
464
|
+
context.compaction.completed
|
|
465
|
+
context.compaction.failed
|
|
466
|
+
context.limit_reached
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
The budget event should include:
|
|
470
|
+
|
|
471
|
+
- Adapter, model ID, context-window source, and estimation method
|
|
472
|
+
- Estimated tokens by category
|
|
473
|
+
- Requested output allowance, safety buffer, and effective single reserve
|
|
474
|
+
- Retained verbatim message count
|
|
475
|
+
- Summarized source range and checkpoint ID, when present
|
|
476
|
+
- Compaction strategy, reclaimed tokens, and retry reason
|
|
477
|
+
- Instruction snapshot hash and advertised-tool schema cost
|
|
478
|
+
- Provider-reported input usage after completion
|
|
479
|
+
|
|
480
|
+
Traces should record the selection decision and hashes/provenance, not duplicate
|
|
481
|
+
the entire transcript or summary in every event. `forge inspect` should render a
|
|
482
|
+
compact budget table and estimation error.
|
|
483
|
+
|
|
484
|
+
## Security and correctness invariants
|
|
485
|
+
|
|
486
|
+
The implementation must preserve these invariants:
|
|
487
|
+
|
|
488
|
+
1. Fresh user/project instructions always outrank historical conversation and
|
|
489
|
+
summaries.
|
|
490
|
+
2. Compaction never restores approvals, trust decisions, environment values, or
|
|
491
|
+
permission profiles.
|
|
492
|
+
3. A summary cannot mark a previously failing verification as currently
|
|
493
|
+
passing.
|
|
494
|
+
4. Only completed conversation turns are eligible for cross-run compaction.
|
|
495
|
+
5. Pending tool calls and results remain paired according to adapter rules.
|
|
496
|
+
6. The canonical transcript is not mutated or deleted by compaction.
|
|
497
|
+
7. Configured secrets are redacted before checkpoint generation and persistence.
|
|
498
|
+
8. Plugin observers receive redacted context events and cannot replace the
|
|
499
|
+
selected checkpoint or weaken context limits.
|
|
500
|
+
9. Context failure is reported as a real terminal condition, never disguised as
|
|
501
|
+
a successful assistant answer.
|
|
502
|
+
10. A provider overflow retry cannot duplicate admitted input or repeat a tool
|
|
503
|
+
side effect.
|
|
504
|
+
11. Instructions are frozen for one run and their hash is stable across its
|
|
505
|
+
physical model attempts.
|
|
506
|
+
12. Opaque provider items are sensitive session state: plugin observers and
|
|
507
|
+
ordinary trace events receive only metadata and hashes.
|
|
508
|
+
|
|
509
|
+
## Package boundaries
|
|
510
|
+
|
|
511
|
+
Recommended ownership:
|
|
512
|
+
|
|
513
|
+
| Package | Responsibility |
|
|
514
|
+
| --- | --- |
|
|
515
|
+
| `@forge/core` | Context categories, abstract budget policy, events, and stop decisions |
|
|
516
|
+
| Model adapters | Model capabilities, token estimation, provider message encoding, continuation rules |
|
|
517
|
+
| `@forge/config` | Versioned context configuration, provenance, and strictness merge |
|
|
518
|
+
| `@forge/persistence` | Session v2 migration, checkpoint validation, atomic storage |
|
|
519
|
+
| `apps/cli` | `/context`, `/compact`, warnings, inspection rendering, and Codex wrapper budgeting |
|
|
520
|
+
| Codex App Server client | Expose public engine-owned usage or compaction events and optional persistent-thread lifecycle |
|
|
521
|
+
| `evals` | Long-session fixtures, metrics, comparison reports, release gates |
|
|
522
|
+
|
|
523
|
+
A separate package should be created only if tokenization dependencies cannot
|
|
524
|
+
remain adapter-local without duplication.
|
|
525
|
+
|
|
526
|
+
## Implementation sequence
|
|
527
|
+
|
|
528
|
+
### Phase A: Measurement foundation
|
|
529
|
+
|
|
530
|
+
1. Add context capability and estimator contracts.
|
|
531
|
+
2. Implement deterministic fake estimators for runtime tests.
|
|
532
|
+
3. Add adapter capability tables and conservative unknown-model behavior.
|
|
533
|
+
4. Emit `context.budgeted` before each provider request.
|
|
534
|
+
5. Compare estimates with returned usage and extend `forge inspect`.
|
|
535
|
+
6. Count advertised tool schemas and instruction snapshots separately.
|
|
536
|
+
7. Measure the serialized Forge conversation wrapper sent to Codex App Server.
|
|
537
|
+
8. Ship `warn` mode with no history mutation.
|
|
538
|
+
|
|
539
|
+
Exit gate: all requests have an inspectable budget, and mandatory-context
|
|
540
|
+
overflow fails before contacting the provider.
|
|
541
|
+
|
|
542
|
+
### Phase B: Derived active context
|
|
543
|
+
|
|
544
|
+
1. Separate canonical session messages from the active request view.
|
|
545
|
+
2. Implement deterministic recent-turn selection without summary generation.
|
|
546
|
+
3. Use that derived active view for both native adapters and `codexPrompt`.
|
|
547
|
+
4. Add session v1-to-v2 migration and checkpoint validation.
|
|
548
|
+
5. Add `/context` and dry-run compaction previews.
|
|
549
|
+
|
|
550
|
+
Exit gate: tests prove the transcript is unchanged and selection is stable
|
|
551
|
+
across resume.
|
|
552
|
+
|
|
553
|
+
### Phase C: Checkpoint generation
|
|
554
|
+
|
|
555
|
+
1. Implement the constrained summarizer behind an interface and fake.
|
|
556
|
+
2. Add an adapter hook for provider-native opaque compaction.
|
|
557
|
+
3. Add source/tail hashing, redaction, validation, and atomic persistence.
|
|
558
|
+
4. Add `/compact --dry-run`, `/compact`, and failure-safe checkpoint
|
|
559
|
+
replacement.
|
|
560
|
+
5. Add opt-in `compact` mode.
|
|
561
|
+
|
|
562
|
+
Exit gate: manual compaction reduces estimated input tokens, preserves required
|
|
563
|
+
facts in fixtures, and cannot carry authority from historical text.
|
|
564
|
+
|
|
565
|
+
### Phase D: In-run guards
|
|
566
|
+
|
|
567
|
+
1. Re-estimate before every model step.
|
|
568
|
+
2. Include adapter-owned continuation cost.
|
|
569
|
+
3. Add safe adapter-owned projection of old completed tool output.
|
|
570
|
+
4. Add one-shot clean-overflow recovery and no-progress detection.
|
|
571
|
+
5. Add typed context-limit stop reasons.
|
|
572
|
+
6. Add tool-heavy and tool-schema-heavy deterministic fixtures.
|
|
573
|
+
7. Prototype lazy tool advertisement only if measured schema cost justifies the
|
|
574
|
+
added complexity.
|
|
575
|
+
|
|
576
|
+
Exit gate: no known over-budget request is sent silently, and tool protocols
|
|
577
|
+
remain valid.
|
|
578
|
+
|
|
579
|
+
### Phase E: Evaluation and default decision
|
|
580
|
+
|
|
581
|
+
1. Run `off`, `warn`, and `compact` modes on identical fixtures and live trials.
|
|
582
|
+
2. Publish aggregate context and task-quality metrics.
|
|
583
|
+
3. Define acceptable regression and estimator-error thresholds.
|
|
584
|
+
4. Enable automatic compaction by default only if those thresholds pass.
|
|
585
|
+
|
|
586
|
+
Exit gate: the default is chosen from published evidence rather than feature
|
|
587
|
+
availability.
|
|
588
|
+
|
|
589
|
+
## Test plan
|
|
590
|
+
|
|
591
|
+
### Unit tests
|
|
592
|
+
|
|
593
|
+
- Budget arithmetic at exact boundaries
|
|
594
|
+
- Conservative fallback for unknown models
|
|
595
|
+
- Turn selection with empty, odd, and maximum-sized histories
|
|
596
|
+
- Checkpoint source range and hash validation
|
|
597
|
+
- Configuration strictness and provenance
|
|
598
|
+
- Secret redaction before summary generation
|
|
599
|
+
- Summary failure preserving the last valid checkpoint
|
|
600
|
+
|
|
601
|
+
### Runtime and adapter tests
|
|
602
|
+
|
|
603
|
+
- Estimate emitted before every model step
|
|
604
|
+
- Provider-reported token usage correlated with the correct estimate
|
|
605
|
+
- OpenAI and DeepSeek tool-call continuations remain valid
|
|
606
|
+
- Provider-native compacted items remain opaque and provider-bound
|
|
607
|
+
- Mandatory context overflow performs no provider call
|
|
608
|
+
- A clean overflow retries once without duplicating input
|
|
609
|
+
- An overflow after partial assistant output does not retry
|
|
610
|
+
- Repeated low-value compaction stops instead of thrashing
|
|
611
|
+
- Cancellation during summary generation leaves the session valid
|
|
612
|
+
- Resume reloads current instructions but reuses a matching checkpoint
|
|
613
|
+
- Codex Engine receives the bounded active view instead of an unbounded full
|
|
614
|
+
Forge transcript
|
|
615
|
+
- Switching away from a provider-native checkpoint rebuilds from the canonical
|
|
616
|
+
transcript
|
|
617
|
+
|
|
618
|
+
### End-to-end fixtures
|
|
619
|
+
|
|
620
|
+
1. **Long recall:** an early user constraint remains available after more turns
|
|
621
|
+
than the verbatim window.
|
|
622
|
+
2. **Instruction change:** a changed `AGENTS.md` overrides contradictory old
|
|
623
|
+
conversation after resume.
|
|
624
|
+
3. **Hostile history:** historical text requesting unrestricted access remains
|
|
625
|
+
inert after summarization.
|
|
626
|
+
4. **Verification freshness:** an old passing test result is not treated as
|
|
627
|
+
evidence after later code changes.
|
|
628
|
+
5. **Tool pressure:** repeated bounded reads approach the window and stop or
|
|
629
|
+
compact according to adapter capability.
|
|
630
|
+
6. **Recovery:** a process restart restores the same transcript and checkpoint
|
|
631
|
+
provenance.
|
|
632
|
+
7. **Schema pressure:** a large plugin tool catalog is measured accurately and
|
|
633
|
+
cannot crowd out mandatory context silently.
|
|
634
|
+
8. **Overflow retry:** one clean overflow compacts and retries without replaying
|
|
635
|
+
user input or tool side effects.
|
|
636
|
+
9. **Codex wrapper:** a long Forge session bounds the JSON wrapper sent to Codex
|
|
637
|
+
App Server and preserves the same seeded constraints as the native engine.
|
|
638
|
+
|
|
639
|
+
## Evaluation metrics and release gates
|
|
640
|
+
|
|
641
|
+
Record at least:
|
|
642
|
+
|
|
643
|
+
- Task and grader pass rate
|
|
644
|
+
- Provider-reported input/output tokens
|
|
645
|
+
- Estimated input tokens and absolute/relative estimation error
|
|
646
|
+
- Summary-generation tokens, latency, and failures
|
|
647
|
+
- Number of compactions and summarized messages
|
|
648
|
+
- Verbatim recent turns retained
|
|
649
|
+
- Context-limit stops and provider context errors
|
|
650
|
+
- Overflow recovery attempts and duplicate-input checks
|
|
651
|
+
- Tool-output and advertised-schema token cost
|
|
652
|
+
- Tokens reclaimed per compaction and no-progress stops
|
|
653
|
+
- Recall accuracy for seeded constraints and decisions
|
|
654
|
+
- Safety-invariant failures
|
|
655
|
+
|
|
656
|
+
Proposed gates before `compact` becomes the default:
|
|
657
|
+
|
|
658
|
+
- No safety-invariant regression in deterministic tests
|
|
659
|
+
- No transcript corruption across failure, cancellation, or resume tests
|
|
660
|
+
- No known provider request exceeds its declared input budget
|
|
661
|
+
- Median input-token reduction of at least 30% on long-session fixtures
|
|
662
|
+
- No more than a 5 percentage-point task pass-rate regression against `warn`
|
|
663
|
+
- At least 95% recall of explicitly seeded durable constraints in the
|
|
664
|
+
long-session evaluation set
|
|
665
|
+
|
|
666
|
+
These thresholds are initial hypotheses. The checked-in report may revise them,
|
|
667
|
+
but the revision must be made before interpreting the final trial results.
|
|
668
|
+
|
|
669
|
+
## Risks and mitigations
|
|
670
|
+
|
|
671
|
+
| Risk | Mitigation |
|
|
672
|
+
| --- | --- |
|
|
673
|
+
| Summary loses a critical constraint | Keep recent turns verbatim, use seeded-recall evals, retain full transcript |
|
|
674
|
+
| Summary carries prompt injection | Label as untrusted memory, place below current instructions, test hostile history |
|
|
675
|
+
| Token estimator undercounts | Conservative fallback, safety buffer, compare with provider usage |
|
|
676
|
+
| Summary generation adds cost and latency | Reuse hashed checkpoints, compact only past thresholds, report overhead |
|
|
677
|
+
| Provider tool protocol breaks | Keep continuation adapter-owned; stop rather than generically rewrite it |
|
|
678
|
+
| Opaque compaction becomes provider lock-in | Bind it to the adapter/model and retain the canonical transcript for fallback |
|
|
679
|
+
| Configuration becomes too complex | Start with three modes and a small documented budget surface |
|
|
680
|
+
| Trace leaks duplicated sensitive text | Store budget metadata and hashes; keep normal redaction pipeline |
|
|
681
|
+
| Compaction hides what happened | Preserve canonical transcript and expose summarized ranges in `/context` and traces |
|
|
682
|
+
| Compaction repeatedly reclaims too little | Enforce minimum reclaimed tokens and a per-input attempt limit |
|
|
683
|
+
|
|
684
|
+
## Decision on RAG
|
|
685
|
+
|
|
686
|
+
Do not add vector RAG as part of Milestone 10. First measure whether long-session
|
|
687
|
+
failures come from conversation growth, repeated tool observations, or poor
|
|
688
|
+
repository discovery. If later evaluations show that lexical `search` and
|
|
689
|
+
targeted file reads miss relevant code, run a separate retrieval experiment
|
|
690
|
+
comparing lexical, semantic, and hybrid approaches on task success, retrieval
|
|
691
|
+
accuracy, tokens, latency, and index cost. Only promote that experiment into the
|
|
692
|
+
Roadmap when it beats the simpler baseline.
|