dsh-lcx-codex 0.4.1 → 0.4.2
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/ARCHITECTURE.md +24 -0
- package/CHANGELOG.md +15 -0
- package/README.md +177 -125
- package/README_EN.md +180 -116
- package/cordis.patch.yml +1 -0
- package/lib/client.js +15 -18
- package/lib/compact-v2.js +21 -37
- package/lib/dsh-responses.js +13 -6
- package/lib/index.js +69 -43
- package/lib/native-checkpoint.js +18 -7
- package/lib/responses-replay.js +63 -276
- package/lib/responses-request.js +145 -0
- package/lib/responses-stream.js +539 -0
- package/lib/route.js +58 -43
- package/lib/transport.js +10 -4
- package/lib/web-search-alpha.js +5 -2
- package/package.json +4 -4
package/README_EN.md
CHANGED
|
@@ -1,64 +1,105 @@
|
|
|
1
|
-
|
|
1
|
+
# dsh-lcx-codex
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[](https://www.npmjs.com/package/dsh-lcx-codex)
|
|
3
|
+
[](https://www.npmjs.com/package/dsh-lcx-codex)
|
|
6
4
|
[](https://github.com/kk3ya03-star/dsh-lcx-codex/actions/workflows/publish.yml)
|
|
7
5
|

|
|
8
|
-

|
|
7
|
+

|
|
9
8
|

|
|
10
9
|
|
|
11
|
-
[简体中文](README.md) · **English** · [Architecture](ARCHITECTURE.md) · [Changelog](CHANGELOG.md)
|
|
10
|
+
[简体中文](README.md) · **English** · [Architecture](ARCHITECTURE.md) · [Changelog](CHANGELOG.md) · [Releases](https://github.com/kk3ya03-star/dsh-lcx-codex/releases)
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
> **Keep a DSH GPT Responses conversation on one final Responses wire owner from the first ordinary turn through tools, Native V2 Compact / Replay, restart recovery, and GPT model switching.**
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
`dsh-lcx-codex` does not replace DSH. DSH still owns the Agent, Session, model selection, tool execution, attachments, and compaction policy. When **LCX is ON**, LCX owns the final request / SSE wire for the selected GPT Responses conversation.
|
|
16
15
|
|
|
17
16
|
## Current stable release
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
**`0.4.2`** is the current stable release and a **zero-functional-change stable promotion** of the fully validated `0.4.2-pre.1` runtime.
|
|
20
19
|
|
|
21
20
|
```powershell
|
|
22
21
|
dsh plugin --profile web add dsh-lcx-codex
|
|
23
22
|
dsh web
|
|
24
23
|
```
|
|
25
24
|
|
|
26
|
-
npm
|
|
25
|
+
- npm dist-tag: `latest`
|
|
26
|
+
- DSH: `0.1.1-rc.2`
|
|
27
|
+
- Plugin Pi: `0.84.3`
|
|
28
|
+
- Node.js: `^22.19.0 || >=24.0.0`
|
|
29
|
+
|
|
30
|
+
`0.4.2-pre.1` remains a historical prerelease; new users should install `latest`.
|
|
31
|
+
|
|
32
|
+
## Product contract
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
LCX OFF
|
|
36
|
+
= use the native DSH LLM path
|
|
37
|
+
|
|
38
|
+
LCX ON
|
|
39
|
+
= LCX owns the final Responses request / SSE wire
|
|
40
|
+
for the selected GPT Responses conversation starting at ordinary turn 1
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Turn LCX off before switching to Claude, Gemini, DeepSeek, or another non-GPT model. Model switching itself does not require a DSH restart.
|
|
27
44
|
|
|
28
|
-
##
|
|
45
|
+
## Why LCX exists
|
|
29
46
|
|
|
30
|
-
|
|
47
|
+
DSH already owns the Agent, Session, tools, and compaction lifecycle. LCX addresses the final provider-native GPT Responses layer: ordinary requests, tools, Native Compact, Replay, restart/resume, and GPT route migration no longer switch final wire owners inside one conversation.
|
|
31
48
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
49
|
+
```text
|
|
50
|
+
DSH
|
|
51
|
+
Agent / Session / Tools
|
|
52
|
+
│
|
|
53
|
+
llm / stream seam
|
|
54
|
+
│
|
|
55
|
+
┌──────────┴──────────┐
|
|
56
|
+
│ │
|
|
57
|
+
LCX OFF LCX ON
|
|
58
|
+
│ │
|
|
59
|
+
native DSH adapter LCX Responses Core
|
|
60
|
+
│
|
|
61
|
+
ordinary turn 1
|
|
62
|
+
↓
|
|
63
|
+
tools
|
|
64
|
+
↓
|
|
65
|
+
Native V2 Compact
|
|
66
|
+
↓
|
|
67
|
+
Replay
|
|
68
|
+
↓
|
|
69
|
+
Restart / Resume
|
|
70
|
+
↓
|
|
71
|
+
GPT Model Migration
|
|
72
|
+
```
|
|
38
73
|
|
|
39
|
-
|
|
74
|
+
Compact therefore changes history representation without also changing request ownership.
|
|
40
75
|
|
|
41
76
|
## Core capabilities
|
|
42
77
|
|
|
43
|
-
### GPT
|
|
78
|
+
### 1. Full GPT Responses lifecycle ownership
|
|
44
79
|
|
|
45
|
-
|
|
80
|
+
With LCX ON, ordinary requests, tool continuations, Native Compact, Native Replay, restart/resume, and portable GPT migration use one LCX Responses request-builder / transport owner.
|
|
46
81
|
|
|
47
|
-
|
|
82
|
+
DSH remains the canonical session/history owner. LCX does not create a second conversation database or replace the DSH Tool Executor.
|
|
48
83
|
|
|
49
|
-
|
|
84
|
+
### 2. GPT-5.6 Prompt Cache
|
|
50
85
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
86
|
+
`0.4.2` uses the current GPT-5.6 cache-options path and maintains stable cache identity inside a session:
|
|
87
|
+
|
|
88
|
+
- implicit caching by default;
|
|
89
|
+
- the supported route sends `prompt_cache_options.ttl = 30m`;
|
|
90
|
+
- ordinary consecutive turns and tool-heavy workloads can reuse warm prefixes;
|
|
91
|
+
- Native Compact intentionally creates a new history/cache epoch, so the old uncompressed prefix is not promised to remain reusable;
|
|
92
|
+
- real long-session validation repeatedly observed near-complete prefix reuse while request topology remained stable.
|
|
54
93
|
|
|
55
|
-
|
|
94
|
+
Cache reuse depends on provider behavior, model, request prefix, tool schemas, and session state; it is not a fixed performance guarantee.
|
|
56
95
|
|
|
57
|
-
`0.
|
|
96
|
+
One confirmed boundary: activating a skill at runtime can change the top-level tool schema and cause a one-time cache reset. The new topology warms again on the next request. The currently supported route rejects content-level `prompt_cache_breakpoint`, and DSH `0.1.1-rc.2` does not expose authoritative dynamic-tool provenance, so `0.4.2` preserves the safe one-time reset instead of guessing tool history.
|
|
58
97
|
|
|
59
|
-
### Native V2
|
|
98
|
+
### 3. Native V2 Compact + Replay
|
|
60
99
|
|
|
61
|
-
|
|
100
|
+
DSH still decides **when to compact, what range to compact, transaction boundaries, and recovery**. LCX owns only the provider-native Responses V2 wire.
|
|
101
|
+
|
|
102
|
+
Default pressure coordination:
|
|
62
103
|
|
|
63
104
|
```text
|
|
64
105
|
0% ─────────────────── 90% ───── 95% ───── 100%
|
|
@@ -66,132 +107,156 @@ LCX does not create a second compaction engine. DSH still owns pressure, compact
|
|
|
66
107
|
V2 DSH prune
|
|
67
108
|
```
|
|
68
109
|
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
- provider-confirmed
|
|
72
|
-
- manual `/compact
|
|
110
|
+
- `90%`: prefer Native V2;
|
|
111
|
+
- `95%`: allow emergency DSH tool-result pruning;
|
|
112
|
+
- provider-confirmed overflow stays with DSH recovery;
|
|
113
|
+
- manual `/compact` keeps the native DSH compaction transaction.
|
|
73
114
|
|
|
74
|
-
Native
|
|
115
|
+
Native checkpoint v5 persists provider-native compaction state plus the portable retained history needed for fidelity. Compatible same-session routes can use Native replay; incompatible routes never reuse unsafe opaque state.
|
|
75
116
|
|
|
76
|
-
|
|
117
|
+
### 4. Restart / Resume + hot GPT switching
|
|
77
118
|
|
|
78
|
-
|
|
119
|
+
A single DSH session can continue through:
|
|
79
120
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
121
|
+
```text
|
|
122
|
+
Terra
|
|
123
|
+
→ Compact
|
|
124
|
+
→ Replay
|
|
125
|
+
→ Restart DSH
|
|
126
|
+
→ Resume same session
|
|
127
|
+
→ Switch to Sol
|
|
128
|
+
→ Continue
|
|
129
|
+
```
|
|
86
130
|
|
|
87
|
-
|
|
131
|
+
Compatible route/model resumes may restore Native opaque state. An incompatible GPT model / route drops unsafe opaque state and reconstructs portable history while remaining on LCX Responses transport.
|
|
88
132
|
|
|
89
|
-
|
|
133
|
+
### 5. Hosted Search + stateful Web Actions
|
|
90
134
|
|
|
91
|
-
|
|
135
|
+
Ordinary web search still uses DSH's native `web_search`. LCX can map its SearchProvider to the active GPT Hosted Search route instead of exposing a second ordinary-search tool.
|
|
92
136
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
137
|
+
| Need | Entry |
|
|
138
|
+
|---|---|
|
|
139
|
+
| Ordinary web search | DSH `web_search` |
|
|
140
|
+
| Advanced Hosted Search controls | `websearch_gpt_advanced` |
|
|
141
|
+
| Stateful page / PDF actions | `websearch_alpha` |
|
|
97
142
|
|
|
98
|
-
|
|
143
|
+
Alpha supports:
|
|
99
144
|
|
|
100
|
-
```
|
|
101
|
-
|
|
145
|
+
```text
|
|
146
|
+
search → open → find / click → screenshot
|
|
102
147
|
```
|
|
103
148
|
|
|
104
|
-
|
|
149
|
+
Alpha is off by default and is registered only after the current endpoint / provider / model / schema passes a capability probe. Unknown deployments fail closed.
|
|
105
150
|
|
|
106
|
-
###
|
|
151
|
+
### 6. Isolated Pi 0.84.3 upgrade
|
|
152
|
+
|
|
153
|
+
The plugin uses `@earendil-works/pi-ai 0.84.3` without overriding the DSH host dependency:
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
DSH 0.1.1-rc.2
|
|
157
|
+
└─ host Pi 0.82.1 ← unchanged
|
|
107
158
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
| Use GPT Hosted Search | On when needed |
|
|
112
|
-
| Advanced Hosted Search | Off until needed |
|
|
113
|
-
| Alpha Search | Off until route capability is confirmed |
|
|
114
|
-
| Native V2 remote compaction | On only when upstream supports it |
|
|
115
|
-
| Native-first auto compaction | On when using Native V2 |
|
|
159
|
+
dsh-lcx-codex 0.4.2
|
|
160
|
+
└─ plugin Pi 0.84.3 ← isolated plugin dependency
|
|
161
|
+
```
|
|
116
162
|
|
|
117
|
-
|
|
163
|
+
Pi owns canonical Responses message/tool serialization, reasoning, IDs, strict/grammar/custom tools, `additional_tools`, `tool_search`, namespace, and stream semantics. LCX does not maintain a second generic provider framework.
|
|
118
164
|
|
|
119
|
-
##
|
|
165
|
+
## Configure in 30 seconds
|
|
120
166
|
|
|
121
|
-
|
|
122
|
-
|---|---|
|
|
123
|
-
| GPT Hosted Search | Ordinary entry remains DSH `web_search`; the request follows the active GPT Responses route |
|
|
124
|
-
| Advanced Hosted | `websearch_gpt_advanced` appears only when enabled |
|
|
125
|
-
| Alpha Web Actions | `websearch_alpha` appears only after capability validation |
|
|
126
|
-
| Native V2 | Compaction follows the provider-native checkpoint path; Basic Compaction is not mislabeled as Native V2 |
|
|
167
|
+
### Requirements
|
|
127
168
|
|
|
128
|
-
|
|
169
|
+
- Node.js `^22.19.0 || >=24.0.0`
|
|
170
|
+
- DSH `0.1.1-rc.2`
|
|
171
|
+
- a working GPT Responses route in DSH
|
|
172
|
+
- actual upstream support for the Hosted Search / Native V2 / Alpha capabilities you enable
|
|
129
173
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
|
133
|
-
|
|
134
|
-
|
|
|
174
|
+
### Suggested first-run settings
|
|
175
|
+
|
|
176
|
+
| Setting | Suggested | Notes |
|
|
177
|
+
|---|---:|---|
|
|
178
|
+
| Enable LCX | **On** | Own the current GPT Responses conversation |
|
|
179
|
+
| Use GPT Hosted Search | As needed | Use GPT Hosted Search behind DSH `web_search` |
|
|
180
|
+
| Advanced Hosted Search | Off | Enable only for advanced Hosted parameters |
|
|
181
|
+
| Alpha Search | Off | Enable after capability validation |
|
|
182
|
+
| Native-first auto compaction | On | Use Native-first pressure coordination |
|
|
183
|
+
| Native threshold | `90%` | Proactive Native V2 threshold |
|
|
184
|
+
| Emergency DSH prune | `95%` | Emergency prune threshold |
|
|
185
|
+
| Fallback to Basic Compaction | On | Allow bounded fallback after Native failure |
|
|
186
|
+
| `web_search` timeout | `240s` | Avoid premature timeout on slower Hosted Search |
|
|
135
187
|
|
|
136
|
-
|
|
188
|
+
### Verify observable behavior
|
|
137
189
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
190
|
+
| Capability | Expected behavior |
|
|
191
|
+
|---|---|
|
|
192
|
+
| LCX ownership | With LCX ON, the first GPT ordinary request already uses the LCX Responses path |
|
|
193
|
+
| Prompt Cache | Stable warm turns may report provider `cached_tokens` |
|
|
194
|
+
| Hosted Search | Ordinary entry remains DSH `web_search` |
|
|
195
|
+
| Advanced Hosted | `websearch_gpt_advanced` appears when enabled |
|
|
196
|
+
| Alpha | `websearch_alpha` appears only after capability validation |
|
|
197
|
+
| Native V2 | Compact produces provider-native checkpoint behavior rather than relabeling Basic Compaction |
|
|
198
|
+
| Replay | The same DSH session continues after Compact and remains resumable after restart |
|
|
144
199
|
|
|
145
|
-
|
|
200
|
+
## DSH / LCX responsibility boundary
|
|
146
201
|
|
|
147
|
-
|
|
202
|
+
| Component | Owns |
|
|
203
|
+
|---|---|
|
|
204
|
+
| **DSH** | Agent loop, Session/history, GenerateOptions, model/credential selection, tool execution, AttachmentStore, pressure policy, compaction transaction |
|
|
205
|
+
| **DSH compatibility seam** | Projects DSH messages / GenerateOptions into Pi Context and bridges results back to DSH |
|
|
206
|
+
| **Plugin Pi 0.84.3** | Canonical Responses serialization / parser semantics |
|
|
207
|
+
| **LCX** | ON/OFF ownership, final Responses body + HTTP/SSE wire, ordinary/compact/replay orchestration, Native opaque state, Search capabilities |
|
|
148
208
|
|
|
149
|
-
|
|
209
|
+
See [ARCHITECTURE.md](ARCHITECTURE.md) for checkpoint, portable replay, cache identity, RefStore, pressure coordination, and protocol details.
|
|
150
210
|
|
|
151
|
-
|
|
211
|
+
## Compatibility
|
|
152
212
|
|
|
153
213
|
| Plugin | DSH | DSH host Pi | Plugin Pi | Status |
|
|
154
214
|
|---|---|---|---|---|
|
|
155
|
-
| `0.4.
|
|
215
|
+
| `0.4.2` | `0.1.1-rc.2` | `0.82.1` | `0.84.3` | **VERIFIED STABLE** |
|
|
216
|
+
| `0.4.1` | `0.1.1-rc.2` | `0.82.1` | `0.82.1` | historical stable |
|
|
217
|
+
|
|
218
|
+
DSH `0.1.2-alpha.1` and newer Pi versions are not part of the formal `0.4.2` compatibility claim. They will be validated by affected seam rather than assumed compatible automatically.
|
|
219
|
+
|
|
220
|
+
## Current boundaries
|
|
221
|
+
|
|
222
|
+
- The supported route uses implicit Prompt Cache. Content-level explicit breakpoints are rejected on that route and are not exposed as a product setting.
|
|
223
|
+
- Dynamic skills/plugins that change the top-level tool schema can trigger a one-time prompt-cache reset; functionality remains correct and the new topology warms again.
|
|
224
|
+
- `reasoning.context` / `reasoning.mode` remain host/Pi exposure boundaries; LCX does not invent a second control surface.
|
|
225
|
+
- The normal operational context profile remains in the ~`262K` class; 1.05M long context is not enabled by default.
|
|
226
|
+
- Credentialed `ALPHA-004` runtime coverage remains `NOT_COVERED`, while fail-closed behavior is covered by tests.
|
|
227
|
+
- Programmatic Tool Calling is not currently advertised as supported.
|
|
156
228
|
|
|
157
|
-
|
|
229
|
+
## FAQ
|
|
158
230
|
|
|
159
231
|
<details>
|
|
160
|
-
<summary><strong>
|
|
232
|
+
<summary><strong>Why do I need to turn LCX off before switching to a non-GPT model?</strong></summary>
|
|
161
233
|
|
|
162
|
-
|
|
163
|
-
|---|---:|---|
|
|
164
|
-
| Enable plugin | On | Enables LCX |
|
|
165
|
-
| Use GPT Hosted Search | As needed | Routes DSH `web_search` through GPT Hosted Search |
|
|
166
|
-
| Advanced Hosted Search | Off | Enable only for advanced Hosted parameters |
|
|
167
|
-
| Alpha Search | Off | Enable after capability verification |
|
|
168
|
-
| Native V2 remote compaction | On* | *When the upstream route actually supports Native V2 |
|
|
169
|
-
| Native-first auto compaction | On | Enables automatic pressure coordination |
|
|
170
|
-
| Native threshold | 90% | Prefer Native V2 from 90% |
|
|
171
|
-
| Emergency DSH prune | 95% | Allow emergency prune from 95% |
|
|
172
|
-
| `web_search` timeout | 240 s | Avoid false timeout on longer searches |
|
|
234
|
+
LCX ON is a GPT Responses lifecycle ownership switch, not a universal multi-model proxy. Non-GPT models continue through native DSH adapters.
|
|
173
235
|
|
|
174
236
|
</details>
|
|
175
237
|
|
|
176
238
|
<details>
|
|
177
|
-
<summary><strong>
|
|
239
|
+
<summary><strong>Why is web_search still the same tool?</strong></summary>
|
|
178
240
|
|
|
179
|
-
|
|
180
|
-
Make sure the plugin and Hosted Search are enabled and that the active Agent resolves to a compatible GPT `openai-responses` route.
|
|
241
|
+
By design. LCX changes the SearchProvider behind DSH `web_search` instead of exposing two ordinary search tools to the model.
|
|
181
242
|
|
|
182
|
-
|
|
183
|
-
That is expected fail-closed behavior. Alpha is registered only after a trusted capability probe succeeds for the current route/schema.
|
|
243
|
+
</details>
|
|
184
244
|
|
|
185
|
-
|
|
186
|
-
|
|
245
|
+
<details>
|
|
246
|
+
<summary><strong>Why is Alpha sometimes missing?</strong></summary>
|
|
187
247
|
|
|
188
|
-
|
|
189
|
-
Make sure you are on `0.4.1` or later and restart/refresh DSH Web. `0.4.1` includes the installed settings lifecycle fix.
|
|
248
|
+
That is fail-closed behavior. `websearch_alpha` is not registered until the active route/schema passes capability probing.
|
|
190
249
|
|
|
191
250
|
</details>
|
|
192
251
|
|
|
193
252
|
<details>
|
|
194
|
-
<summary><strong>
|
|
253
|
+
<summary><strong>Why can a skill load cause the cache to warm again?</strong></summary>
|
|
254
|
+
|
|
255
|
+
Some skills dynamically register new top-level tools. Tool schemas are part of the cacheable prompt prefix, so a topology change can establish a new cache epoch. `0.4.2` prioritizes correct tool definitions instead of guessing provenance to force reuse of an old cache.
|
|
256
|
+
|
|
257
|
+
</details>
|
|
258
|
+
|
|
259
|
+
## Development and verification
|
|
195
260
|
|
|
196
261
|
```bash
|
|
197
262
|
npm run typecheck
|
|
@@ -200,12 +265,11 @@ npm run test:schema
|
|
|
200
265
|
npm pack --ignore-scripts
|
|
201
266
|
```
|
|
202
267
|
|
|
203
|
-
-
|
|
204
|
-
-
|
|
268
|
+
- Architecture: [ARCHITECTURE.md](ARCHITECTURE.md)
|
|
269
|
+
- Changelog: [CHANGELOG.md](CHANGELOG.md)
|
|
270
|
+
- GitHub Releases: [Releases](https://github.com/kk3ya03-star/dsh-lcx-codex/releases)
|
|
205
271
|
- npm: [`dsh-lcx-codex`](https://www.npmjs.com/package/dsh-lcx-codex)
|
|
206
272
|
|
|
207
|
-
</details>
|
|
208
|
-
|
|
209
273
|
## License
|
|
210
274
|
|
|
211
275
|
MIT
|
package/cordis.patch.yml
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
baseURL: https://api.lcxbot.com/v1
|
|
11
11
|
apiKeyEnv: LCX_API_KEY
|
|
12
12
|
model: gpt-5.6-sol
|
|
13
|
+
supportsExplicitPromptCacheMode: true
|
|
13
14
|
legacyCheckpointPath: !!js dshHomePath('storages/lcx-codex/checkpoints-v3.json')
|
|
14
15
|
alphaCapabilityPath: !!js dshHomePath('storages/lcx-codex/web-alpha-capabilities.json')
|
|
15
16
|
alphaRefPath: !!js dshHomePath('storages/lcx-codex/web-alpha-refs.json')
|
package/lib/client.js
CHANGED
|
@@ -32,8 +32,9 @@ window.__ModuleLoader__.load({
|
|
|
32
32
|
const copy = {
|
|
33
33
|
zh: {
|
|
34
34
|
title: 'Responses / Codex 能力',
|
|
35
|
-
desc: '
|
|
36
|
-
enabled: '
|
|
35
|
+
desc: 'LCX 开启后从第一轮普通请求开始接管当前 GPT Responses 会话,并统一管理普通请求、工具、Native V2 压缩和续接。',
|
|
36
|
+
enabled: '启用 LCX(接管当前 GPT Responses 会话)',
|
|
37
|
+
enabledHelp: '切换 Claude、Gemini、DeepSeek 等非 GPT 模型前先关闭 LCX;模型切换本身不需要重启 DSH。',
|
|
37
38
|
web: '使用 GPT Hosted Search 作为 DSH web_search 后端',
|
|
38
39
|
webHelp: '不会新增第二个普通搜索工具;普通 web_search 自动跟随当前 Agent 的 GPT Responses 模型。',
|
|
39
40
|
searchTimeout: 'web_search 超时(秒)',
|
|
@@ -42,8 +43,6 @@ window.__ModuleLoader__.load({
|
|
|
42
43
|
advancedHelp: '只在需要域名过滤、位置、search context、图片等原生 Hosted 参数时使用;默认关闭以保持工具 schema 稳定。',
|
|
43
44
|
alpha: '启用 Alpha command(websearch_alpha)',
|
|
44
45
|
alphaHelp: '仅 capability probe 对当前 endpoint/provider/model/schema 验证通过后才真正注册。',
|
|
45
|
-
compact: '启用 Native V2 远程压缩',
|
|
46
|
-
compactHelp: 'DSH 仍负责范围、事务和 /compact;Native state 保存在 DSH session log。',
|
|
47
46
|
autoCompact: '启用 Native-first 自动压缩',
|
|
48
47
|
autoCompactHelp: '到主动阈值前不让 DSH 的 80% tool-result prune 改写历史;到主动阈值后优先 Native V2。',
|
|
49
48
|
autoThreshold: 'Native 自动压缩阈值(%)',
|
|
@@ -52,14 +51,15 @@ window.__ModuleLoader__.load({
|
|
|
52
51
|
emergencyThresholdHelp: '建议 95%。达到这里才允许 DSH tool-result-pruner 先救场;必须高于 Native 阈值。',
|
|
53
52
|
fallback: 'Native 失败后回退 DSH basic compaction',
|
|
54
53
|
fallbackHelp: 'Remote-first:只有 Native 请求失败才调用 basic summary,不并行双跑。',
|
|
55
|
-
endpoint: '
|
|
56
|
-
model: '
|
|
54
|
+
endpoint: 'Responses 地址',
|
|
55
|
+
model: 'GPT 模型',
|
|
57
56
|
save: '保存', discard: '放弃修改', saving: '保存中…',
|
|
58
57
|
},
|
|
59
58
|
en: {
|
|
60
59
|
title: 'Responses / Codex capabilities',
|
|
61
|
-
desc: '
|
|
62
|
-
enabled: 'Enable
|
|
60
|
+
desc: 'When enabled, LCX owns the selected GPT Responses conversation from the first ordinary turn through tools, Native V2 compaction and continuation.',
|
|
61
|
+
enabled: 'Enable LCX (own current GPT Responses conversation)',
|
|
62
|
+
enabledHelp: 'Turn LCX off before switching to Claude, Gemini, DeepSeek, or another non-GPT model. Model switching itself does not require a DSH restart.',
|
|
63
63
|
web: 'Use GPT Hosted Search as DSH web_search backend',
|
|
64
64
|
webHelp: 'Keeps DSH web_search as the single ordinary search tool and follows the active Agent GPT Responses model.',
|
|
65
65
|
searchTimeout: 'web_search timeout (seconds)',
|
|
@@ -68,8 +68,6 @@ window.__ModuleLoader__.load({
|
|
|
68
68
|
advancedHelp: 'Only for native Hosted controls such as domains, location, context size and image search; off by default for stable tool schemas.',
|
|
69
69
|
alpha: 'Enable Alpha command (websearch_alpha)',
|
|
70
70
|
alphaHelp: 'Registered only after a matching capability probe.',
|
|
71
|
-
compact: 'Enable Native V2 remote compaction',
|
|
72
|
-
compactHelp: 'DSH still owns range/transactions and /compact; native state is persisted in the DSH session log.',
|
|
73
71
|
autoCompact: 'Enable Native-first automatic compaction',
|
|
74
72
|
autoCompactHelp: 'Suppresses the stock 80% tool-result prune before the proactive threshold, then prefers Native V2.',
|
|
75
73
|
autoThreshold: 'Native auto-compaction threshold (%)',
|
|
@@ -78,7 +76,7 @@ window.__ModuleLoader__.load({
|
|
|
78
76
|
emergencyThresholdHelp: 'Default 95%. DSH tool-result pruning is allowed only in this emergency zone; must exceed the Native threshold.',
|
|
79
77
|
fallback: 'Fall back to DSH basic compaction on Native failure',
|
|
80
78
|
fallbackHelp: 'Remote-first: basic summary runs only after Native failure, never in parallel.',
|
|
81
|
-
endpoint: '
|
|
79
|
+
endpoint: 'Responses endpoint', model: 'GPT model',
|
|
82
80
|
save: 'Save', discard: 'Discard', saving: 'Saving…',
|
|
83
81
|
},
|
|
84
82
|
}
|
|
@@ -96,7 +94,7 @@ window.__ModuleLoader__.load({
|
|
|
96
94
|
field(name) { return this.draftValue()[name] }
|
|
97
95
|
projection() {
|
|
98
96
|
const s = this.snapshot()
|
|
99
|
-
const bools = ['enabled','webSearch','advancedHostedSearch','alphaSearch','
|
|
97
|
+
const bools = ['enabled','webSearch','advancedHostedSearch','alphaSearch','fallbackToBasicCompaction','autoCompaction']
|
|
100
98
|
return {
|
|
101
99
|
available: s.status === 'ready', writable: s.writable, dirty: this.dirty, saving: this.saving,
|
|
102
100
|
...Object.fromEntries(bools.map((f) => [f, { value: f === 'fallbackToBasicCompaction' || f === 'autoCompaction' ? this.field(f) !== false : Boolean(this.field(f)) }])),
|
|
@@ -139,18 +137,17 @@ window.__ModuleLoader__.load({
|
|
|
139
137
|
React.createElement('button', { className:'lcx-head', type:'button', onClick:()=>setOpen(!open) }, React.createElement('strong',null,t.title), React.createElement('span',null,open?'⌃':'⌄')),
|
|
140
138
|
open ? React.createElement('div', { className:'lcx-body' },
|
|
141
139
|
React.createElement('p', { className:'lcx-help' }, t.desc),
|
|
142
|
-
React.createElement(Row, { id:'lcx-enabled', label:t.enabled, checked:s.enabled.value, disabled, onChange:v=>props.edit('enabled',v) }),
|
|
140
|
+
React.createElement(Row, { id:'lcx-enabled', label:t.enabled, help:t.enabledHelp, checked:s.enabled.value, disabled, onChange:v=>props.edit('enabled',v) }),
|
|
143
141
|
React.createElement(Row, { id:'lcx-web', label:t.web, help:t.webHelp, checked:s.webSearch.value, disabled:disabled||!s.enabled.value, onChange:v=>props.edit('webSearch',v) }),
|
|
144
142
|
React.createElement('div', { className:'lcx-fields' },
|
|
145
143
|
React.createElement(Field, { label:t.searchTimeout, help:t.searchTimeoutHelp, type:'number', min:30, max:600, step:30, value:s.webSearchTimeoutSeconds, disabled:disabled||!s.enabled.value||!s.webSearch.value, onChange:numeric('webSearchTimeoutSeconds') })),
|
|
146
144
|
React.createElement(Row, { id:'lcx-advanced', label:t.advanced, help:t.advancedHelp, checked:s.advancedHostedSearch.value, disabled:disabled||!s.enabled.value||!s.webSearch.value, onChange:v=>props.edit('advancedHostedSearch',v) }),
|
|
147
145
|
React.createElement(Row, { id:'lcx-alpha', label:t.alpha, help:t.alphaHelp, checked:s.alphaSearch.value, disabled:disabled||!s.enabled.value, onChange:v=>props.edit('alphaSearch',v) }),
|
|
148
|
-
React.createElement(Row, { id:'lcx-compact', label:t.
|
|
149
|
-
React.createElement(Row, { id:'lcx-auto-compact', label:t.autoCompact, help:t.autoCompactHelp, checked:s.autoCompaction.value, disabled:disabled||!s.enabled.value||!s.remoteCompaction.value, onChange:v=>props.edit('autoCompaction',v) }),
|
|
146
|
+
React.createElement(Row, { id:'lcx-auto-compact', label:t.autoCompact, help:t.autoCompactHelp, checked:s.autoCompaction.value, disabled:disabled||!s.enabled.value, onChange:v=>props.edit('autoCompaction',v) }),
|
|
150
147
|
React.createElement('div', { className:'lcx-fields' },
|
|
151
|
-
React.createElement(Field, { label:t.autoThreshold, help:t.autoThresholdHelp, type:'number', min:85, max:95, step:1, value:s.autoCompactionThresholdPercent, disabled:disabled||!s.enabled.value||!s.
|
|
152
|
-
React.createElement(Field, { label:t.emergencyThreshold, help:t.emergencyThresholdHelp, type:'number', min:90, max:99, step:1, value:s.emergencyPruneThresholdPercent, disabled:disabled||!s.enabled.value||!s.
|
|
153
|
-
React.createElement(Row, { id:'lcx-fallback', label:t.fallback, help:t.fallbackHelp, checked:s.fallbackToBasicCompaction.value, disabled:disabled||!s.enabled.value
|
|
148
|
+
React.createElement(Field, { label:t.autoThreshold, help:t.autoThresholdHelp, type:'number', min:85, max:95, step:1, value:s.autoCompactionThresholdPercent, disabled:disabled||!s.enabled.value||!s.autoCompaction.value, onChange:numeric('autoCompactionThresholdPercent') }),
|
|
149
|
+
React.createElement(Field, { label:t.emergencyThreshold, help:t.emergencyThresholdHelp, type:'number', min:90, max:99, step:1, value:s.emergencyPruneThresholdPercent, disabled:disabled||!s.enabled.value||!s.autoCompaction.value, onChange:numeric('emergencyPruneThresholdPercent') })),
|
|
150
|
+
React.createElement(Row, { id:'lcx-fallback', label:t.fallback, help:t.fallbackHelp, checked:s.fallbackToBasicCompaction.value, disabled:disabled||!s.enabled.value, onChange:v=>props.edit('fallbackToBasicCompaction',v) }),
|
|
154
151
|
React.createElement('div', { className:'lcx-fields' },
|
|
155
152
|
React.createElement(Field, { label:t.endpoint, value:s.baseURL, disabled, onChange:e=>props.edit('baseURL',e.target.value) }),
|
|
156
153
|
React.createElement(Field, { label:t.model, value:s.model, disabled, onChange:e=>props.edit('model',e.target.value) })),
|
package/lib/compact-v2.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import { consumeSse, fetchSseWithRetry } from './transport.js'
|
|
4
|
-
import {
|
|
4
|
+
import { buildCompactionResponsesBody, responsesGenerationEnvelope as standardGenerationEnvelope } from './responses-request.js'
|
|
5
5
|
|
|
6
6
|
/** @typedef {Record<string, unknown>} UnknownRecord */
|
|
7
7
|
/** @typedef {Record<string, string>} HeaderMap */
|
|
@@ -16,11 +16,13 @@ import { responsesTools } from './dsh-responses.js'
|
|
|
16
16
|
/**
|
|
17
17
|
* @typedef {object} NativeCompactionBodyOptions
|
|
18
18
|
* @property {string} model
|
|
19
|
+
* @property {unknown} [modelDescriptor]
|
|
19
20
|
* @property {unknown[]} input
|
|
20
21
|
* @property {string} [instructions]
|
|
21
22
|
* @property {unknown} [tools]
|
|
22
23
|
* @property {string} [promptCacheKey]
|
|
23
24
|
* @property {string} [promptCacheRetention]
|
|
25
|
+
* @property {'none' | 'short' | 'long'} [cacheRetention]
|
|
24
26
|
* @property {unknown} [reasoningEffort]
|
|
25
27
|
* @property {unknown} [temperature]
|
|
26
28
|
* @property {unknown} [maxTokens]
|
|
@@ -37,6 +39,7 @@ import { responsesTools } from './dsh-responses.js'
|
|
|
37
39
|
* @property {unknown[]} [tools]
|
|
38
40
|
* @property {string} [prompt_cache_key]
|
|
39
41
|
* @property {string} [prompt_cache_retention]
|
|
42
|
+
* @property {{ mode?: 'explicit', ttl?: '30m' }} [prompt_cache_options]
|
|
40
43
|
* @property {{ effort: string, summary: 'auto' }} [reasoning]
|
|
41
44
|
* @property {string[]} [include]
|
|
42
45
|
* @property {number} [temperature]
|
|
@@ -97,46 +100,27 @@ export function mergeFeatureHeader(headers = {}) {
|
|
|
97
100
|
* @param {GenerationControls} [controls]
|
|
98
101
|
* @returns {GenerationEnvelope}
|
|
99
102
|
*/
|
|
100
|
-
export function responsesGenerationEnvelope(
|
|
101
|
-
|
|
102
|
-
const result = {}
|
|
103
|
-
if (reasoningEffort !== undefined && reasoningEffort !== 'off') {
|
|
104
|
-
result.reasoning = { effort: String(reasoningEffort), summary: 'auto' }
|
|
105
|
-
result.include = ['reasoning.encrypted_content']
|
|
106
|
-
}
|
|
107
|
-
if (temperature !== undefined) {
|
|
108
|
-
if (!Number.isFinite(temperature)) throw fail('Responses temperature must be finite', 'LCX_COMPACT_INVALID_INPUT')
|
|
109
|
-
result.temperature = Number(temperature)
|
|
110
|
-
}
|
|
111
|
-
if (maxTokens !== undefined) {
|
|
112
|
-
if (!Number.isSafeInteger(maxTokens) || /** @type {number} */ (maxTokens) <= 0) throw fail('Responses maxTokens must be a positive safe integer', 'LCX_COMPACT_INVALID_INPUT')
|
|
113
|
-
result.max_output_tokens = Math.max(16, /** @type {number} */ (maxTokens))
|
|
114
|
-
}
|
|
115
|
-
return result
|
|
103
|
+
export function responsesGenerationEnvelope(controls = {}) {
|
|
104
|
+
return standardGenerationEnvelope(controls)
|
|
116
105
|
}
|
|
117
106
|
|
|
118
107
|
/**
|
|
119
108
|
* @param {NativeCompactionBodyOptions} options
|
|
120
109
|
* @returns {NativeCompactionBody}
|
|
121
110
|
*/
|
|
122
|
-
export function buildNativeCompactionBody({ model, input, instructions, tools, promptCacheKey, promptCacheRetention, reasoningEffort, temperature, maxTokens }) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
...(nativeTools !== undefined ? { tools: nativeTools } : {}),
|
|
136
|
-
...(promptCacheKey ? { prompt_cache_key: String(promptCacheKey) } : {}),
|
|
137
|
-
...(promptCacheRetention ? { prompt_cache_retention: String(promptCacheRetention) } : {}),
|
|
138
|
-
...responsesGenerationEnvelope({ reasoningEffort, temperature, maxTokens }),
|
|
139
|
-
}
|
|
111
|
+
export function buildNativeCompactionBody({ model, modelDescriptor, input, instructions, tools, promptCacheKey, promptCacheRetention, cacheRetention, reasoningEffort, temperature, maxTokens }) {
|
|
112
|
+
return /** @type {NativeCompactionBody} */ (/** @type {unknown} */ (buildCompactionResponsesBody({
|
|
113
|
+
model: /** @type {any} */ (modelDescriptor ?? model),
|
|
114
|
+
input,
|
|
115
|
+
instructions,
|
|
116
|
+
tools,
|
|
117
|
+
promptCacheKey,
|
|
118
|
+
promptCacheRetention,
|
|
119
|
+
cacheRetention: cacheRetention ?? (promptCacheKey ? (promptCacheRetention ? 'long' : 'short') : 'none'),
|
|
120
|
+
reasoningEffort,
|
|
121
|
+
temperature,
|
|
122
|
+
maxTokens,
|
|
123
|
+
})))
|
|
140
124
|
}
|
|
141
125
|
|
|
142
126
|
/**
|
|
@@ -260,8 +244,8 @@ export async function parseNativeCompactionSse(response, options = {}) {
|
|
|
260
244
|
/**
|
|
261
245
|
* @param {NativeCompactionRequestOptions} options
|
|
262
246
|
*/
|
|
263
|
-
export async function requestNativeCompaction({ baseURL, model, input, instructions, tools, promptCacheKey, promptCacheRetention, reasoningEffort, temperature, maxTokens, idempotencyKey, headers, signal, timeoutMs, maxAttempts, maxResponseBytes }) {
|
|
264
|
-
const body = buildNativeCompactionBody({ model, input, instructions, tools, promptCacheKey, promptCacheRetention, reasoningEffort, temperature, maxTokens })
|
|
247
|
+
export async function requestNativeCompaction({ baseURL, model, modelDescriptor, input, instructions, tools, promptCacheKey, promptCacheRetention, cacheRetention, reasoningEffort, temperature, maxTokens, idempotencyKey, headers, signal, timeoutMs, maxAttempts, maxResponseBytes }) {
|
|
248
|
+
const body = buildNativeCompactionBody({ model, modelDescriptor, input, instructions, tools, promptCacheKey, promptCacheRetention, cacheRetention, reasoningEffort, temperature, maxTokens })
|
|
265
249
|
const requestHeaders = mergeFeatureHeader({ ...headers, ...(idempotencyKey ? { 'idempotency-key': String(idempotencyKey) } : {}) })
|
|
266
250
|
return fetchSseWithRetry(`${String(baseURL).replace(/\/+$/u, '')}/responses`, body, requestHeaders, signal, timeoutMs, {
|
|
267
251
|
maxAttempts,
|