@shuind/dsh-codex-harness 0.1.24 → 0.1.26
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 -5
- package/lib/client.js +56 -10
- package/lib/compaction.js +45 -0
- package/lib/index.js +70 -28
- package/lib/types/activity-types.d.ts +1 -1
- package/lib/types/activity.d.ts +4 -3
- package/lib/types/activity.js +30 -4
- package/lib/types/client/activity.d.ts +15 -2
- package/lib/types/client/activity.js +49 -1
- package/lib/types/client/index.d.ts +2 -1
- package/lib/types/client/index.js +23 -13
- package/lib/types/compaction.d.ts +18 -0
- package/lib/types/compaction.js +48 -0
- package/lib/types/exec.d.ts +1 -1
- package/lib/types/exec.js +9 -4
- package/lib/types/index.js +3 -2
- package/lib/types/patch.js +3 -11
- package/lib/types/remote.js +37 -5
- package/package.json +31 -1
- package/presets/codex/agent.cordis.yml +1 -1
- package/presets/codex-collaboration/agent.cordis.yml +1 -1
package/README.md
CHANGED
|
@@ -12,13 +12,15 @@
|
|
|
12
12
|
- **旧版 Web 兼容**:在未提供新版模型设置/上下文设置 slot 的 DSH Web 中,Fast 和上下文容量会自动回退到旧版 composer slot;client 注入不依赖纯类型 slot 包。
|
|
13
13
|
- **Responses 原生 apply_patch**:在 GPT Responses 请求的插件传输边界,把普通 JSON function tool 改写为 `type: "custom"` + OpenAI `lark` grammar;下一轮历史同步改写为 `custom_tool_call`。如果中转站拒绝 custom tool,则自动回退到普通 function tool,不改变 DSH 工具执行器。
|
|
14
14
|
- **远程搜索与压缩**:OpenAI Responses 请求默认优先使用 hosted `web_search` 和 `/responses/compact`;失败时回退到 DSH 的本地实现。
|
|
15
|
+
- **远程压缩用量**:`/responses/compact` 返回标准 `usage` 时,插件会把 `input_tokens`、缓存读写和 `output_tokens` 原样拆分为 DSH 的用量字段;不再把远程压缩伪造成 `0`。中转站缺失或返回不一致的 usage 时,插件不会编造数字。
|
|
15
16
|
- **上下文容量**:在 Web 中设置 `1K`–`1000K` tokens,设置值作用于下一次请求。
|
|
16
|
-
-
|
|
17
|
+
- **自动压缩阈值**:Codex preset 的自动压缩会读取最新请求持久化的有效上下文容量;例如设置 `400K` 时,默认 `80%` pressure threshold 是 `320K`,不会错误地按适配器默认 `262,144` 在约 `210K` 提前触发。
|
|
18
|
+
- **活动状态**:Codex 请求模型、接收模型回复或进行上下文压缩时,在 `Deep diving...` 右侧显示对应阶段和耗时,让长时间 Deep Diving 不再像卡住。
|
|
17
19
|
|
|
18
20
|
## 安装
|
|
19
21
|
|
|
20
22
|
```sh
|
|
21
|
-
dsh plugin --profile web add @shuind/dsh-codex-harness@0.1.
|
|
23
|
+
dsh plugin --profile web add @shuind/dsh-codex-harness@0.1.26
|
|
22
24
|
```
|
|
23
25
|
|
|
24
26
|
重启 Web,创建新会话,在模式菜单中选择 **Codex 模式**。
|
|
@@ -51,13 +53,13 @@ Fast 设置保存在 `codex` 命名空间,只对 Codex preset 生效。
|
|
|
51
53
|
|
|
52
54
|
### 上下文容量
|
|
53
55
|
|
|
54
|
-
点击 Web 顶部的上下文使用量指示器,可以设置下一次请求的上下文容量。上方 meter 显示当前请求的实际容量;修改设置后,需要发送下一次请求才会更新。
|
|
56
|
+
点击 Web 顶部的上下文使用量指示器,可以设置下一次请求的上下文容量。上方 meter 显示当前请求的实际容量;修改设置后,需要发送下一次请求才会更新。Codex preset 的自动压缩也使用这个已经持久化的有效容量。
|
|
55
57
|
|
|
56
58
|
上下文容量使用整数 K tokens,范围为 `1K` 到 `1000K`。实际可用上限仍取决于模型和中转站支持情况。
|
|
57
59
|
|
|
58
60
|
### 活动状态
|
|
59
61
|
|
|
60
|
-
Codex
|
|
62
|
+
Codex 发起模型请求时,Web 会在 `Deep diving...` 右侧显示 `请求模型... · Ns`;收到首个非空模型 token(非流式适配器则收到 `assistant/message`)后切换为 `模型回复... · Ns`。模型回复结束、进入工具调用、压缩结束或下一轮开始后自动隐藏。该状态由 Host 的 `sessionProjections` 投影驱动,因此本地压缩和远程 `/responses/compact` 都会显示同一种状态。
|
|
61
63
|
|
|
62
64
|
如果当前 DSH 组合没有加载 projection 服务,插件会跳过注册,客户端也会自动隐藏这行,不影响普通会话。
|
|
63
65
|
|
|
@@ -105,7 +107,7 @@ description: 使用 Codex 工具并开启可选协作提示词。
|
|
|
105
107
|
order: 10
|
|
106
108
|
```
|
|
107
109
|
|
|
108
|
-
然后在 Web 的 **Agent 预设** 中选择 `My Codex`,再新建会话。这个 preset 会加载 Codex 工具,并开启协作提示词;网页搜索、远程压缩、后台任务控制和 Skills 等其他功能需要在同一个 `agent.cordis.yml`
|
|
110
|
+
然后在 Web 的 **Agent 预设** 中选择 `My Codex`,再新建会话。这个 preset 会加载 Codex 工具,并开启协作提示词;网页搜索、远程压缩、后台任务控制和 Skills 等其他功能需要在同一个 `agent.cordis.yml` 中按需添加。若希望自定义 preset 也修正自动压缩阈值,请在 compaction 隔离组中使用 `@shuind/dsh-codex-harness/compaction` 替代 `@deepseek-ai/dsh-compaction-basic`。
|
|
109
111
|
|
|
110
112
|
### 可选协作提示词(私货)
|
|
111
113
|
|
package/lib/client.js
CHANGED
|
@@ -21,13 +21,52 @@ window.__ModuleLoader__.load({
|
|
|
21
21
|
//#endregion
|
|
22
22
|
//#region lib/types/client/activity.js
|
|
23
23
|
/** Client-only inference used while the host activity projection frame is in flight. */
|
|
24
|
-
/**
|
|
24
|
+
/** Equality for selector hooks, whose default is reference identity. */
|
|
25
|
+
function sameModelActivity(left, right) {
|
|
26
|
+
return left?.activity === right?.activity && left?.startedAt === right?.startedAt;
|
|
27
|
+
}
|
|
28
|
+
/** Infer the request-phase clock from the existing conversation snapshot. */
|
|
25
29
|
function awaitingModelStartedAt(snapshot) {
|
|
26
30
|
if (!snapshot.running || snapshot.runningCalls.length > 0) return void 0;
|
|
27
31
|
let latest;
|
|
28
32
|
for (const timing of snapshot.turnTimings.values()) if (timing.endTime === void 0) latest = timing.startTime;
|
|
29
33
|
return latest;
|
|
30
34
|
}
|
|
35
|
+
/** Infer the first non-empty model token timestamp from the current snapshot. */
|
|
36
|
+
function modelReplyStartedAt(snapshot) {
|
|
37
|
+
if (!snapshot.running || snapshot.runningCalls.length > 0) return void 0;
|
|
38
|
+
let openTurn;
|
|
39
|
+
for (const [turn, timing] of snapshot.turnTimings) if (timing.endTime === void 0) openTurn = {
|
|
40
|
+
turn,
|
|
41
|
+
startTime: timing.startTime
|
|
42
|
+
};
|
|
43
|
+
if (openTurn === void 0) return void 0;
|
|
44
|
+
if (snapshot.partial !== null && snapshot.partial.turn === openTurn.turn) {
|
|
45
|
+
const partialReplyStartedAt = snapshot.partial.replyStartedAt;
|
|
46
|
+
if (partialReplyStartedAt !== void 0) return partialReplyStartedAt;
|
|
47
|
+
}
|
|
48
|
+
const chat = snapshot.chat;
|
|
49
|
+
const step = (chat?.timeline.turns.get(openTurn.turn))?.steps.findLast((candidate) => candidate.end === void 0);
|
|
50
|
+
if (step === void 0) return void 0;
|
|
51
|
+
for (const node of [...chat?.nodes.values() ?? []].reverse()) {
|
|
52
|
+
if (node.kind !== "assistant-step") continue;
|
|
53
|
+
const data = node.data;
|
|
54
|
+
if (data.turn === openTurn.turn && data.step === step.step && typeof data.replyStartedAt === "number") return data.replyStartedAt;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Infer the two-phase model activity from the current client snapshot. */
|
|
58
|
+
function modelActivity(snapshot) {
|
|
59
|
+
const startedAt = awaitingModelStartedAt(snapshot);
|
|
60
|
+
if (startedAt === void 0) return void 0;
|
|
61
|
+
const replyStartedAt = modelReplyStartedAt(snapshot);
|
|
62
|
+
return replyStartedAt === void 0 ? {
|
|
63
|
+
activity: "requesting-model",
|
|
64
|
+
startedAt
|
|
65
|
+
} : {
|
|
66
|
+
activity: "model-reply",
|
|
67
|
+
startedAt: replyStartedAt
|
|
68
|
+
};
|
|
69
|
+
}
|
|
31
70
|
//#endregion
|
|
32
71
|
//#region lib/types/client/index.js
|
|
33
72
|
/** Browser controls for the Codex request settings mounted by the Host plugin. */
|
|
@@ -50,7 +89,8 @@ window.__ModuleLoader__.load({
|
|
|
50
89
|
contextSizeDescription: "Next request capacity in K tokens. The meter above is current.",
|
|
51
90
|
contextRestore: "Restore model default",
|
|
52
91
|
activityCompacting: "Compacting context...",
|
|
53
|
-
|
|
92
|
+
activityRequestingModel: "Requesting model...",
|
|
93
|
+
activityModelReply: "Model replying..."
|
|
54
94
|
};
|
|
55
95
|
const zh = {
|
|
56
96
|
fast: "Fast",
|
|
@@ -62,7 +102,8 @@ window.__ModuleLoader__.load({
|
|
|
62
102
|
contextSizeDescription: "设置下次请求的上下文容量,单位为 K tokens;上方是当前请求。",
|
|
63
103
|
contextRestore: "恢复模型默认值",
|
|
64
104
|
activityCompacting: "正在压缩上下文...",
|
|
65
|
-
|
|
105
|
+
activityRequestingModel: "请求模型...",
|
|
106
|
+
activityModelReply: "模型回复..."
|
|
66
107
|
};
|
|
67
108
|
function FastModeButton({ sessionId, useSessions, useSettings, setSetting, t }) {
|
|
68
109
|
const agentPreset = useSessions((state) => state.byId[sessionId]?.agentPreset);
|
|
@@ -283,11 +324,12 @@ window.__ModuleLoader__.load({
|
|
|
283
324
|
function ActivityLine({ sessionId, useSession, useSessions, useProjection, t }) {
|
|
284
325
|
const agentPreset = useSessions((state) => state.byId[sessionId]?.agentPreset);
|
|
285
326
|
const projectedActivity = useProjection("codexActivity");
|
|
286
|
-
const
|
|
287
|
-
const
|
|
288
|
-
activity: "
|
|
289
|
-
startedAt:
|
|
290
|
-
} :
|
|
327
|
+
const fallbackActivity = useSession(modelActivity, sameModelActivity);
|
|
328
|
+
const normalizedProjectedActivity = projectedActivity?.activity === "awaiting-model" ? {
|
|
329
|
+
activity: fallbackActivity?.activity ?? "requesting-model",
|
|
330
|
+
startedAt: fallbackActivity?.startedAt ?? projectedActivity.startedAt
|
|
331
|
+
} : projectedActivity;
|
|
332
|
+
const activity = projectedActivity !== void 0 ? normalizedProjectedActivity : isCodexPresetId(agentPreset) && fallbackActivity !== void 0 ? fallbackActivity : null;
|
|
291
333
|
const [now, setNow] = (0, react.useState)(() => Date.now());
|
|
292
334
|
(0, react.useEffect)(() => {
|
|
293
335
|
if (!isCodexPresetId(agentPreset) || activity === void 0 || activity === null) return void 0;
|
|
@@ -296,9 +338,13 @@ window.__ModuleLoader__.load({
|
|
|
296
338
|
setNow(Date.now());
|
|
297
339
|
}, 1e3);
|
|
298
340
|
return () => clearInterval(timer);
|
|
299
|
-
}, [
|
|
341
|
+
}, [
|
|
342
|
+
agentPreset,
|
|
343
|
+
activity?.activity,
|
|
344
|
+
activity?.startedAt
|
|
345
|
+
]);
|
|
300
346
|
if (!isCodexPresetId(agentPreset) || activity === void 0 || activity === null) return null;
|
|
301
|
-
const label = activity.activity === "
|
|
347
|
+
const label = activity.activity === "compaction" ? t("activityCompacting") : activity.activity === "model-reply" ? t("activityModelReply") : t("activityRequestingModel");
|
|
302
348
|
return (0, react_jsx_runtime.jsxs)("span", {
|
|
303
349
|
id: "codex-activity",
|
|
304
350
|
role: "status",
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import BasicCompactionEngine from "@deepseek-ai/dsh-compaction-basic";
|
|
3
|
+
//#region lib/types/compaction.js
|
|
4
|
+
/** Codex compaction backend that honors the latest durable request capacity. */
|
|
5
|
+
/** Overlay only the capacity lookup used by pressure compaction. */
|
|
6
|
+
function withDurableContextCapacity(llm, activeSession) {
|
|
7
|
+
return new Proxy(llm, { get(target, property) {
|
|
8
|
+
if (property === "resolveModelInfo") return async (provider, model, signal) => {
|
|
9
|
+
const info = await target.resolveModelInfo(provider, model, signal);
|
|
10
|
+
const requestContext = activeSession.getStore()?.requestContext();
|
|
11
|
+
if (requestContext?.provider !== provider || requestContext.model !== model || requestContext.contextWindow === void 0) return info;
|
|
12
|
+
return {
|
|
13
|
+
...info,
|
|
14
|
+
context: {
|
|
15
|
+
...info.context,
|
|
16
|
+
contextWindow: requestContext.contextWindow
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
const value = Reflect.get(target, property, target);
|
|
21
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
22
|
+
} });
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Keep the upstream compaction policy, retention, overflow recovery, and
|
|
26
|
+
* transaction implementation intact. The scoped LLM seam changes only the
|
|
27
|
+
* context metadata returned during a pressure check.
|
|
28
|
+
*/
|
|
29
|
+
var CodexCompactionEngine = class extends BasicCompactionEngine {
|
|
30
|
+
static inject = BasicCompactionEngine.inject;
|
|
31
|
+
static Config = BasicCompactionEngine.Config;
|
|
32
|
+
activeSession;
|
|
33
|
+
constructor(ctx, config = {}) {
|
|
34
|
+
const activeSession = new AsyncLocalStorage();
|
|
35
|
+
const llm = ctx.get("llm");
|
|
36
|
+
if (llm === void 0) throw new Error("codex compaction requires ctx.llm");
|
|
37
|
+
super(ctx.extend({ llm: withDurableContextCapacity(llm, activeSession) }), config);
|
|
38
|
+
this.activeSession = activeSession;
|
|
39
|
+
}
|
|
40
|
+
compactIfNeeded(agent, trigger, signal) {
|
|
41
|
+
return this.activeSession.run(agent.session, () => super.compactIfNeeded(agent, trigger, signal));
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { CodexCompactionEngine as default };
|
package/lib/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { randomBytes } from "node:crypto";
|
|
|
5
5
|
import { resolve } from "node:path";
|
|
6
6
|
import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
|
7
7
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
8
|
+
import { isTokenDelta } from "@deepseek-ai/dsh-llm/message";
|
|
8
9
|
import { z as z$1 } from "zod";
|
|
9
10
|
//#region lib/types/context.js
|
|
10
11
|
const CODEX_CONTEXT_MAX = 1e6;
|
|
@@ -13,9 +14,8 @@ const CODEX_CONTEXT_MAX = 1e6;
|
|
|
13
14
|
/** Parser and line-oriented applicator for Codex's `apply_patch` language. */
|
|
14
15
|
const APPLY_PATCH_DESCRIPTION = "Edits files using Codex patch syntax with Begin/End Patch markers and file update directives. In hunk lines, the first character is the operation marker; repeat a source-leading marker when the source line itself starts with one.";
|
|
15
16
|
/** The grammar sent to providers that support OpenAI custom grammar tools. */
|
|
16
|
-
const APPLY_PATCH_GRAMMAR = String.raw`start: begin_patch
|
|
17
|
+
const APPLY_PATCH_GRAMMAR = String.raw`start: begin_patch hunk+ end_patch
|
|
17
18
|
begin_patch: "*** Begin Patch" LF
|
|
18
|
-
environment_id: "*** Environment ID: " filename LF
|
|
19
19
|
end_patch: "*** End Patch" LF?
|
|
20
20
|
hunk: add_hunk | delete_hunk | update_hunk
|
|
21
21
|
add_hunk: "*** Add File: " filename LF add_line+
|
|
@@ -37,7 +37,6 @@ function isFileHeader(line) {
|
|
|
37
37
|
const trimmed = line.trim();
|
|
38
38
|
return trimmed.startsWith("*** Add File: ") || trimmed.startsWith("*** Delete File: ") || trimmed.startsWith("*** Update File: ");
|
|
39
39
|
}
|
|
40
|
-
const ENVIRONMENT_ID_MARKER = "*** Environment ID:";
|
|
41
40
|
function unwrapHeredoc(input) {
|
|
42
41
|
const normalized = input.replaceAll("\r\n", "\n").trim();
|
|
43
42
|
const lines = normalized.split("\n");
|
|
@@ -66,11 +65,7 @@ function parsePatch(input) {
|
|
|
66
65
|
const files = [];
|
|
67
66
|
let index = 1;
|
|
68
67
|
const end = lines.length - 1;
|
|
69
|
-
if (lines[index]?.trim().startsWith(
|
|
70
|
-
if (lines[index].trim().slice(19).trim().length === 0) invalid("environment id cannot be empty");
|
|
71
|
-
index++;
|
|
72
|
-
if (lines[index]?.trim().startsWith(ENVIRONMENT_ID_MARKER) === true) invalid("environment id cannot be specified more than once");
|
|
73
|
-
}
|
|
68
|
+
if (lines[index]?.trim().startsWith("*** Environment ID:") === true) invalid("environment selection is unavailable in this single-environment DSH plugin");
|
|
74
69
|
while (index < end) {
|
|
75
70
|
const header = lines[index++]?.trim();
|
|
76
71
|
if (header === void 0) invalid("unexpected end of input");
|
|
@@ -218,6 +213,7 @@ function applyPatchHunks(original, hunks, label = "file") {
|
|
|
218
213
|
/** Codex `exec_command` and `write_stdin` execution over dsh capability seams. */
|
|
219
214
|
const STATES = /* @__PURE__ */ new WeakMap();
|
|
220
215
|
const MIN_YIELD_TIME_MS = 250;
|
|
216
|
+
const WINDOWS_INITIAL_EXEC_YIELD_TIME_MS = 1e4;
|
|
221
217
|
const MIN_EMPTY_YIELD_TIME_MS = 5e3;
|
|
222
218
|
const MAX_YIELD_TIME_MS = 3e4;
|
|
223
219
|
const MAX_EMPTY_YIELD_TIME_MS = 3e5;
|
|
@@ -236,8 +232,9 @@ function stateFor(agent) {
|
|
|
236
232
|
function positiveFinite(name, value) {
|
|
237
233
|
if (value !== void 0 && (!Number.isFinite(value) || value < 0)) throw new Error(`${name} must be a non-negative finite number`);
|
|
238
234
|
}
|
|
239
|
-
function normalizeWaitMs(value, fallback, empty = false) {
|
|
240
|
-
|
|
235
|
+
function normalizeWaitMs(value, fallback, empty = false, initialExec = false) {
|
|
236
|
+
const lower = empty ? MIN_EMPTY_YIELD_TIME_MS : initialExec && process.platform === "win32" ? WINDOWS_INITIAL_EXEC_YIELD_TIME_MS : MIN_YIELD_TIME_MS;
|
|
237
|
+
return Math.max(lower, Math.min(empty ? MAX_EMPTY_YIELD_TIME_MS : MAX_YIELD_TIME_MS, Math.trunc(value ?? fallback)));
|
|
241
238
|
}
|
|
242
239
|
function outputLimit(maxOutputBytes, maxOutputTokens) {
|
|
243
240
|
const tokens = maxOutputTokens ?? DEFAULT_OUTPUT_TOKENS;
|
|
@@ -369,7 +366,7 @@ async function runExecCommand(ctx, args, exec, config) {
|
|
|
369
366
|
const sendRequest = {
|
|
370
367
|
text: commandFor(args),
|
|
371
368
|
submit: true,
|
|
372
|
-
waitMs: normalizeWaitMs(args.yield_time_ms, config.defaultYieldTimeMs),
|
|
369
|
+
waitMs: normalizeWaitMs(args.yield_time_ms, config.defaultYieldTimeMs, false, true),
|
|
373
370
|
signal: exec.signal
|
|
374
371
|
};
|
|
375
372
|
const result = await terminals.startSend(agent, spawned.sessionId, sendRequest).done;
|
|
@@ -432,7 +429,7 @@ async function runExecCommand(ctx, args, exec, config) {
|
|
|
432
429
|
signal: exec.signal
|
|
433
430
|
}));
|
|
434
431
|
try {
|
|
435
|
-
await waitForShell(process, normalizeWaitMs(args.yield_time_ms, config.defaultYieldTimeMs), exec.signal);
|
|
432
|
+
await waitForShell(process, normalizeWaitMs(args.yield_time_ms, config.defaultYieldTimeMs, false, true), exec.signal);
|
|
436
433
|
const output = readShellOutput(process.readOutput(), maxBytes);
|
|
437
434
|
if (process.status === "running") {
|
|
438
435
|
if (exec.agent === void 0) {
|
|
@@ -899,6 +896,29 @@ function compactText(body) {
|
|
|
899
896
|
const encrypted = text.join("\n\n").trim();
|
|
900
897
|
return encrypted.length === 0 ? "" : `${REMOTE_COMPACTION_OPEN}${encrypted}${REMOTE_COMPACTION_CLOSE}`;
|
|
901
898
|
}
|
|
899
|
+
function nonNegativeInteger(value) {
|
|
900
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
901
|
+
}
|
|
902
|
+
/** Map the Responses compact usage object without inventing missing counts. */
|
|
903
|
+
function compactUsage(body) {
|
|
904
|
+
if (typeof body.usage !== "object" || body.usage === null) return void 0;
|
|
905
|
+
const raw = body.usage;
|
|
906
|
+
const inputTokens = nonNegativeInteger(raw.input_tokens);
|
|
907
|
+
const outputTokens = nonNegativeInteger(raw.output_tokens);
|
|
908
|
+
if (inputTokens === void 0 || outputTokens === void 0) return void 0;
|
|
909
|
+
const details = typeof raw.input_tokens_details === "object" && raw.input_tokens_details !== null ? raw.input_tokens_details : void 0;
|
|
910
|
+
const cacheReadTokens = nonNegativeInteger(details?.cached_tokens);
|
|
911
|
+
const cacheWriteTokens = nonNegativeInteger(details?.cache_write_tokens);
|
|
912
|
+
const cached = cacheReadTokens ?? 0;
|
|
913
|
+
const writes = cacheWriteTokens ?? 0;
|
|
914
|
+
if (cached + writes > inputTokens) return void 0;
|
|
915
|
+
return {
|
|
916
|
+
inputTokens: inputTokens - cached - writes,
|
|
917
|
+
outputTokens,
|
|
918
|
+
...cacheReadTokens !== void 0 && cacheReadTokens > 0 ? { cacheReadTokens } : {},
|
|
919
|
+
...cacheWriteTokens !== void 0 && cacheWriteTokens > 0 ? { cacheWriteTokens } : {}
|
|
920
|
+
};
|
|
921
|
+
}
|
|
902
922
|
async function remoteCompact(ctx, options) {
|
|
903
923
|
const profile = profileOf(ctx, options.provider);
|
|
904
924
|
if (!supportsResponses(profile, options.provider) || profile?.baseURL === void 0) throw new Error("Codex remote compaction requires an OpenAI Responses provider with baseURL");
|
|
@@ -911,15 +931,20 @@ async function remoteCompact(ctx, options) {
|
|
|
911
931
|
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
912
932
|
});
|
|
913
933
|
if (!response.ok) throw new Error(`remote compaction returned HTTP ${response.status}`);
|
|
914
|
-
const
|
|
934
|
+
const body = await response.json();
|
|
935
|
+
const text = compactText(body);
|
|
915
936
|
if (text.length === 0) throw new Error("remote compaction returned no compaction text");
|
|
916
|
-
|
|
937
|
+
const usage = compactUsage(body);
|
|
938
|
+
return {
|
|
939
|
+
text,
|
|
940
|
+
...usage === void 0 ? {} : { usage }
|
|
941
|
+
};
|
|
917
942
|
}
|
|
918
943
|
/** Remote-first compaction waterfall with the existing DSH path as fallback. */
|
|
919
944
|
function remoteCompactStream(ctx, options, next) {
|
|
920
945
|
return (async function* () {
|
|
921
946
|
try {
|
|
922
|
-
const
|
|
947
|
+
const result = await remoteCompact(ctx, options);
|
|
923
948
|
yield {
|
|
924
949
|
type: "block-start",
|
|
925
950
|
index: 0,
|
|
@@ -928,22 +953,19 @@ function remoteCompactStream(ctx, options, next) {
|
|
|
928
953
|
yield {
|
|
929
954
|
type: "text-delta",
|
|
930
955
|
index: 0,
|
|
931
|
-
text
|
|
956
|
+
text: result.text
|
|
932
957
|
};
|
|
933
958
|
yield {
|
|
934
959
|
type: "block-end",
|
|
935
960
|
index: 0,
|
|
936
961
|
block: {
|
|
937
962
|
type: "text",
|
|
938
|
-
text
|
|
963
|
+
text: result.text
|
|
939
964
|
}
|
|
940
965
|
};
|
|
941
|
-
yield {
|
|
966
|
+
if (result.usage !== void 0) yield {
|
|
942
967
|
type: "usage",
|
|
943
|
-
usage:
|
|
944
|
-
inputTokens: 0,
|
|
945
|
-
outputTokens: 0
|
|
946
|
-
}
|
|
968
|
+
usage: result.usage
|
|
947
969
|
};
|
|
948
970
|
yield {
|
|
949
971
|
type: "finish",
|
|
@@ -959,13 +981,28 @@ function remoteCompactStream(ctx, options, next) {
|
|
|
959
981
|
}
|
|
960
982
|
//#endregion
|
|
961
983
|
//#region lib/types/activity.js
|
|
962
|
-
/** Host-side activity projection for the Codex
|
|
984
|
+
/** Host-side activity projection for the Codex status line. */
|
|
985
|
+
/** Only a non-empty model delta starts the reply phase; usage and finish frames do not. */
|
|
986
|
+
function startsModelReply(event) {
|
|
987
|
+
if (event.type === "assistant/message") return true;
|
|
988
|
+
if (event.type !== "assistant/chunk" || typeof event.data !== "object" || event.data === null) return false;
|
|
989
|
+
const chunk = event.data.chunk;
|
|
990
|
+
return chunk !== void 0 && isTokenDelta(chunk);
|
|
991
|
+
}
|
|
963
992
|
/** Persisted and wire shape of the Codex activity value. */
|
|
964
993
|
const codexActivitySchema = z$1.union([
|
|
965
994
|
z$1.object({
|
|
966
995
|
activity: z$1.literal("compaction"),
|
|
967
996
|
startedAt: z$1.number().int().nonnegative()
|
|
968
997
|
}),
|
|
998
|
+
z$1.object({
|
|
999
|
+
activity: z$1.literal("requesting-model"),
|
|
1000
|
+
startedAt: z$1.number().int().nonnegative()
|
|
1001
|
+
}),
|
|
1002
|
+
z$1.object({
|
|
1003
|
+
activity: z$1.literal("model-reply"),
|
|
1004
|
+
startedAt: z$1.number().int().nonnegative()
|
|
1005
|
+
}),
|
|
969
1006
|
z$1.object({
|
|
970
1007
|
activity: z$1.literal("awaiting-model"),
|
|
971
1008
|
startedAt: z$1.number().int().nonnegative()
|
|
@@ -979,11 +1016,15 @@ function applyCodexActivity(state, event) {
|
|
|
979
1016
|
startedAt: event.time
|
|
980
1017
|
};
|
|
981
1018
|
if (event.type === "step/start" || event.type === "llm/retry-started") return {
|
|
982
|
-
activity: "
|
|
1019
|
+
activity: "requesting-model",
|
|
1020
|
+
startedAt: event.time
|
|
1021
|
+
};
|
|
1022
|
+
if (startsModelReply(event) && (state?.activity === "requesting-model" || state?.activity === "awaiting-model")) return {
|
|
1023
|
+
activity: "model-reply",
|
|
983
1024
|
startedAt: event.time
|
|
984
1025
|
};
|
|
985
1026
|
if (event.type === "turn/start" || event.type === "turn/end" || event.type === "compaction/end") return null;
|
|
986
|
-
if (state?.activity === "awaiting-model" && (event.type === "llm/retry" || event.type === "tool/call" || event.type === "step/end")) return null;
|
|
1027
|
+
if ((state?.activity === "requesting-model" || state?.activity === "model-reply" || state?.activity === "awaiting-model") && (event.type === "llm/retry" || event.type === "tool/call" || event.type === "step/end")) return null;
|
|
987
1028
|
return state;
|
|
988
1029
|
}
|
|
989
1030
|
const codexActivityProjection = {
|
|
@@ -997,7 +1038,7 @@ const codexActivityProjection = {
|
|
|
997
1038
|
},
|
|
998
1039
|
schema: codexActivitySchema,
|
|
999
1040
|
view: (state) => state,
|
|
1000
|
-
stateVersion:
|
|
1041
|
+
stateVersion: 2
|
|
1001
1042
|
};
|
|
1002
1043
|
/** Register the optional activity unit without requiring the projection seam in every assembly. */
|
|
1003
1044
|
function registerCodexActivityProjection(ctx) {
|
|
@@ -1018,12 +1059,13 @@ const inject = [
|
|
|
1018
1059
|
"credentials",
|
|
1019
1060
|
"settings"
|
|
1020
1061
|
];
|
|
1062
|
+
const DEFAULT_MAX_OUTPUT_BYTES = 1048576;
|
|
1021
1063
|
/** Runtime configuration schema for the Codex tool bridge. */
|
|
1022
1064
|
const Config = z.object({
|
|
1023
1065
|
defaultYieldTimeMs: z.number().step(1).min(0).default(1e4),
|
|
1024
1066
|
pollYieldTimeMs: z.number().step(1).min(0).default(5e3),
|
|
1025
1067
|
writeYieldTimeMs: z.number().step(1).min(0).default(250),
|
|
1026
|
-
maxOutputBytes: z.number().step(1).min(1).default(
|
|
1068
|
+
maxOutputBytes: z.number().step(1).min(1).default(DEFAULT_MAX_OUTPUT_BYTES),
|
|
1027
1069
|
hostedWebSearch: z.boolean().default(true),
|
|
1028
1070
|
remoteCompact: z.boolean().default(true),
|
|
1029
1071
|
collaborationPrompt: z.boolean().default(false)
|
|
@@ -1566,7 +1608,7 @@ function apply(ctx, config = {}) {
|
|
|
1566
1608
|
defaultYieldTimeMs: config.defaultYieldTimeMs ?? 1e4,
|
|
1567
1609
|
pollYieldTimeMs: config.pollYieldTimeMs ?? 5e3,
|
|
1568
1610
|
writeYieldTimeMs: config.writeYieldTimeMs ?? 250,
|
|
1569
|
-
maxOutputBytes: config.maxOutputBytes ??
|
|
1611
|
+
maxOutputBytes: config.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
1570
1612
|
hostedWebSearch: config.hostedWebSearch ?? true,
|
|
1571
1613
|
remoteCompact: config.remoteCompact ?? true,
|
|
1572
1614
|
collaborationPrompt: config.collaborationPrompt ?? false
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Pure client/host-shared type for the Codex activity projection value. */
|
|
2
2
|
export type CodexActivity = {
|
|
3
|
-
activity: 'compaction' | 'awaiting-model';
|
|
3
|
+
activity: 'compaction' | 'requesting-model' | 'model-reply' | 'awaiting-model';
|
|
4
4
|
startedAt: number;
|
|
5
5
|
};
|
|
6
6
|
//# sourceMappingURL=activity-types.d.ts.map
|
package/lib/types/activity.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
/** Host-side activity projection for the Codex
|
|
1
|
+
/** Host-side activity projection for the Codex status line. */
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
3
|
import { z, type ZodType } from 'zod';
|
|
4
4
|
import type { CodexActivity } from './activity-types.ts';
|
|
5
5
|
export type { CodexActivity } from './activity-types.ts';
|
|
6
|
-
/**
|
|
6
|
+
/** Long-running Codex activities currently surfaced to the client. */
|
|
7
7
|
export type CodexActivityState = CodexActivity | null;
|
|
8
8
|
/** Minimal event shape needed by this projection; no compaction package import is required. */
|
|
9
9
|
export interface CodexActivityEvent {
|
|
10
10
|
type: string;
|
|
11
11
|
time: number;
|
|
12
|
+
data?: unknown;
|
|
12
13
|
}
|
|
13
14
|
/** Persisted and wire shape of the Codex activity value. */
|
|
14
15
|
export declare const codexActivitySchema: ZodType<CodexActivityState>;
|
|
@@ -25,7 +26,7 @@ export declare const codexActivityProjection: {
|
|
|
25
26
|
};
|
|
26
27
|
readonly schema: z.ZodType<CodexActivityState, unknown, z.core.$ZodTypeInternals<CodexActivityState, unknown>>;
|
|
27
28
|
readonly view: (state: CodexActivityState) => CodexActivityState;
|
|
28
|
-
readonly stateVersion:
|
|
29
|
+
readonly stateVersion: 2;
|
|
29
30
|
};
|
|
30
31
|
/** Register the optional activity unit without requiring the projection seam in every assembly. */
|
|
31
32
|
export declare function registerCodexActivityProjection(ctx: Context): void;
|
package/lib/types/activity.js
CHANGED
|
@@ -1,11 +1,31 @@
|
|
|
1
|
-
/** Host-side activity projection for the Codex
|
|
1
|
+
/** Host-side activity projection for the Codex status line. */
|
|
2
|
+
import { isTokenDelta } from '@deepseek-ai/dsh-llm/message';
|
|
2
3
|
import { z } from 'zod';
|
|
4
|
+
/** Only a non-empty model delta starts the reply phase; usage and finish frames do not. */
|
|
5
|
+
function startsModelReply(event) {
|
|
6
|
+
if (event.type === 'assistant/message')
|
|
7
|
+
return true;
|
|
8
|
+
if (event.type !== 'assistant/chunk' || typeof event.data !== 'object' || event.data === null)
|
|
9
|
+
return false;
|
|
10
|
+
const chunk = event.data.chunk;
|
|
11
|
+
return chunk !== undefined && isTokenDelta(chunk);
|
|
12
|
+
}
|
|
3
13
|
/** Persisted and wire shape of the Codex activity value. */
|
|
4
14
|
export const codexActivitySchema = z.union([
|
|
5
15
|
z.object({
|
|
6
16
|
activity: z.literal('compaction'),
|
|
7
17
|
startedAt: z.number().int().nonnegative(),
|
|
8
18
|
}),
|
|
19
|
+
z.object({
|
|
20
|
+
activity: z.literal('requesting-model'),
|
|
21
|
+
startedAt: z.number().int().nonnegative(),
|
|
22
|
+
}),
|
|
23
|
+
z.object({
|
|
24
|
+
activity: z.literal('model-reply'),
|
|
25
|
+
startedAt: z.number().int().nonnegative(),
|
|
26
|
+
}),
|
|
27
|
+
// Accepted for rolling upgrades: an older Codex host may still send this
|
|
28
|
+
// ambiguous state until its projection definition is refreshed.
|
|
9
29
|
z.object({
|
|
10
30
|
activity: z.literal('awaiting-model'),
|
|
11
31
|
startedAt: z.number().int().nonnegative(),
|
|
@@ -17,14 +37,20 @@ export function applyCodexActivity(state, event) {
|
|
|
17
37
|
if (event.type === 'compaction/start')
|
|
18
38
|
return { activity: 'compaction', startedAt: event.time };
|
|
19
39
|
if (event.type === 'step/start' || event.type === 'llm/retry-started') {
|
|
20
|
-
return { activity: '
|
|
40
|
+
return { activity: 'requesting-model', startedAt: event.time };
|
|
41
|
+
}
|
|
42
|
+
if (startsModelReply(event)
|
|
43
|
+
&& (state?.activity === 'requesting-model' || state?.activity === 'awaiting-model')) {
|
|
44
|
+
return { activity: 'model-reply', startedAt: event.time };
|
|
21
45
|
}
|
|
22
46
|
if (event.type === 'turn/start' || event.type === 'turn/end' || event.type === 'compaction/end')
|
|
23
47
|
return null;
|
|
24
48
|
// Keep the line through reasoning and streamed output. It is the only
|
|
25
49
|
// visible indication that the model is still progressing; tool cards have
|
|
26
50
|
// their own status, so a tool dispatch retires this ambient line.
|
|
27
|
-
if (state?.activity === '
|
|
51
|
+
if ((state?.activity === 'requesting-model'
|
|
52
|
+
|| state?.activity === 'model-reply'
|
|
53
|
+
|| state?.activity === 'awaiting-model')
|
|
28
54
|
&& (event.type === 'llm/retry'
|
|
29
55
|
|| event.type === 'tool/call'
|
|
30
56
|
|| event.type === 'step/end'))
|
|
@@ -44,7 +70,7 @@ export const codexActivityProjection = {
|
|
|
44
70
|
// the `stateSchema`/`wire` split.
|
|
45
71
|
schema: codexActivitySchema,
|
|
46
72
|
view: (state) => state,
|
|
47
|
-
stateVersion:
|
|
73
|
+
stateVersion: 2,
|
|
48
74
|
};
|
|
49
75
|
/** Register the optional activity unit without requiring the projection seam in every assembly. */
|
|
50
76
|
export function registerCodexActivityProjection(ctx) {
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
/** Client-only inference used while the host activity projection frame is in flight. */
|
|
2
2
|
import type { ConversationSnapshot } from '@deepseek-ai/dsh-client-runtime/client';
|
|
3
|
-
export type ActivitySessionSnapshot = Pick<ConversationSnapshot, 'running' | 'partial' | 'runningCalls' | 'turnTimings'
|
|
4
|
-
/**
|
|
3
|
+
export type ActivitySessionSnapshot = Pick<ConversationSnapshot, 'running' | 'partial' | 'runningCalls' | 'turnTimings'> & {
|
|
4
|
+
/** Optional for hosts that predate the assembled Chat snapshot. */
|
|
5
|
+
readonly chat?: ConversationSnapshot['chat'];
|
|
6
|
+
};
|
|
7
|
+
export type CodexModelActivity = {
|
|
8
|
+
activity: 'requesting-model' | 'model-reply';
|
|
9
|
+
startedAt: number;
|
|
10
|
+
};
|
|
11
|
+
/** Equality for selector hooks, whose default is reference identity. */
|
|
12
|
+
export declare function sameModelActivity(left: CodexModelActivity | undefined, right: CodexModelActivity | undefined): boolean;
|
|
13
|
+
/** Infer the request-phase clock from the existing conversation snapshot. */
|
|
5
14
|
export declare function awaitingModelStartedAt(snapshot: ActivitySessionSnapshot): number | undefined;
|
|
15
|
+
/** Infer the first non-empty model token timestamp from the current snapshot. */
|
|
16
|
+
export declare function modelReplyStartedAt(snapshot: ActivitySessionSnapshot): number | undefined;
|
|
17
|
+
/** Infer the two-phase model activity from the current client snapshot. */
|
|
18
|
+
export declare function modelActivity(snapshot: ActivitySessionSnapshot): CodexModelActivity | undefined;
|
|
6
19
|
//# sourceMappingURL=activity.d.ts.map
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/** Client-only inference used while the host activity projection frame is in flight. */
|
|
2
|
-
/**
|
|
2
|
+
/** Equality for selector hooks, whose default is reference identity. */
|
|
3
|
+
export function sameModelActivity(left, right) {
|
|
4
|
+
return left?.activity === right?.activity && left?.startedAt === right?.startedAt;
|
|
5
|
+
}
|
|
6
|
+
/** Infer the request-phase clock from the existing conversation snapshot. */
|
|
3
7
|
export function awaitingModelStartedAt(snapshot) {
|
|
4
8
|
if (!snapshot.running || snapshot.runningCalls.length > 0)
|
|
5
9
|
return undefined;
|
|
@@ -10,4 +14,48 @@ export function awaitingModelStartedAt(snapshot) {
|
|
|
10
14
|
}
|
|
11
15
|
return latest;
|
|
12
16
|
}
|
|
17
|
+
/** Infer the first non-empty model token timestamp from the current snapshot. */
|
|
18
|
+
export function modelReplyStartedAt(snapshot) {
|
|
19
|
+
if (!snapshot.running || snapshot.runningCalls.length > 0)
|
|
20
|
+
return undefined;
|
|
21
|
+
let openTurn;
|
|
22
|
+
for (const [turn, timing] of snapshot.turnTimings) {
|
|
23
|
+
if (timing.endTime === undefined)
|
|
24
|
+
openTurn = { turn, startTime: timing.startTime };
|
|
25
|
+
}
|
|
26
|
+
if (openTurn === undefined)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (snapshot.partial !== null && snapshot.partial.turn === openTurn.turn) {
|
|
29
|
+
const partialReplyStartedAt = snapshot.partial.replyStartedAt;
|
|
30
|
+
if (partialReplyStartedAt !== undefined)
|
|
31
|
+
return partialReplyStartedAt;
|
|
32
|
+
}
|
|
33
|
+
// A non-streaming adapter has no partial row. The assembled Chat view still
|
|
34
|
+
// carries the reply boundary, but only accept it for the currently open step
|
|
35
|
+
// so an earlier tool step in the same turn cannot mask a new request.
|
|
36
|
+
const chat = snapshot.chat;
|
|
37
|
+
const turn = chat?.timeline.turns.get(openTurn.turn);
|
|
38
|
+
const step = turn?.steps.findLast(candidate => candidate.end === undefined);
|
|
39
|
+
if (step === undefined)
|
|
40
|
+
return undefined;
|
|
41
|
+
for (const node of [...(chat?.nodes.values() ?? [])].reverse()) {
|
|
42
|
+
if (node.kind !== 'assistant-step')
|
|
43
|
+
continue;
|
|
44
|
+
const data = node.data;
|
|
45
|
+
if (data.turn === openTurn.turn && data.step === step.step && typeof data.replyStartedAt === 'number') {
|
|
46
|
+
return data.replyStartedAt;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
/** Infer the two-phase model activity from the current client snapshot. */
|
|
52
|
+
export function modelActivity(snapshot) {
|
|
53
|
+
const startedAt = awaitingModelStartedAt(snapshot);
|
|
54
|
+
if (startedAt === undefined)
|
|
55
|
+
return undefined;
|
|
56
|
+
const replyStartedAt = modelReplyStartedAt(snapshot);
|
|
57
|
+
return replyStartedAt === undefined
|
|
58
|
+
? { activity: 'requesting-model', startedAt }
|
|
59
|
+
: { activity: 'model-reply', startedAt: replyStartedAt };
|
|
60
|
+
}
|
|
13
61
|
//# sourceMappingURL=activity.js.map
|
|
@@ -11,7 +11,8 @@ declare const en: {
|
|
|
11
11
|
readonly contextSizeDescription: "Next request capacity in K tokens. The meter above is current.";
|
|
12
12
|
readonly contextRestore: "Restore model default";
|
|
13
13
|
readonly activityCompacting: "Compacting context...";
|
|
14
|
-
readonly
|
|
14
|
+
readonly activityRequestingModel: "Requesting model...";
|
|
15
|
+
readonly activityModelReply: "Model replying...";
|
|
15
16
|
};
|
|
16
17
|
type CodexKey = keyof typeof en;
|
|
17
18
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
/** Browser controls for the Codex request settings mounted by the Host plugin. */
|
|
3
3
|
import { useEffect, useState } from 'react';
|
|
4
4
|
import { CODEX_CONTEXT_MAX, CODEX_CONTEXT_UNIT, isCodexPresetId } from "../context.js";
|
|
5
|
-
import {
|
|
5
|
+
import { modelActivity, sameModelActivity } from "./activity.js";
|
|
6
6
|
const NS = 'codex';
|
|
7
7
|
const SETTINGS_NAMESPACE = 'codex';
|
|
8
8
|
const MODEL_SETTINGS_SLOT = 'conversation.input.model.settings';
|
|
@@ -24,7 +24,8 @@ const en = {
|
|
|
24
24
|
contextSizeDescription: 'Next request capacity in K tokens. The meter above is current.',
|
|
25
25
|
contextRestore: 'Restore model default',
|
|
26
26
|
activityCompacting: 'Compacting context...',
|
|
27
|
-
|
|
27
|
+
activityRequestingModel: 'Requesting model...',
|
|
28
|
+
activityModelReply: 'Model replying...',
|
|
28
29
|
};
|
|
29
30
|
const zh = {
|
|
30
31
|
fast: 'Fast',
|
|
@@ -36,7 +37,8 @@ const zh = {
|
|
|
36
37
|
contextSizeDescription: '设置下次请求的上下文容量,单位为 K tokens;上方是当前请求。',
|
|
37
38
|
contextRestore: '恢复模型默认值',
|
|
38
39
|
activityCompacting: '正在压缩上下文...',
|
|
39
|
-
|
|
40
|
+
activityRequestingModel: '请求模型...',
|
|
41
|
+
activityModelReply: '模型回复...',
|
|
40
42
|
};
|
|
41
43
|
function FastModeButton({ sessionId, useSessions, useSettings, setSetting, t }) {
|
|
42
44
|
const agentPreset = useSessions(state => state.byId[sessionId]?.agentPreset);
|
|
@@ -143,14 +145,20 @@ export function ActivityLine({ sessionId, useSession, useSessions, useProjection
|
|
|
143
145
|
// Keep the projection seam optional: this package must still load when the
|
|
144
146
|
// host has no session-projection registry or has not carried this key.
|
|
145
147
|
const projectedActivity = useProjection('codexActivity');
|
|
146
|
-
// The projection is the authoritative clock. The session snapshot
|
|
147
|
-
// only covers the short wire gap before the next projection frame
|
|
148
|
-
//
|
|
149
|
-
const
|
|
148
|
+
// The projection is the authoritative phase and clock. The session snapshot
|
|
149
|
+
// fallback only covers the short wire gap before the next projection frame;
|
|
150
|
+
// tool calls intentionally remain silent because their cards own the status.
|
|
151
|
+
const fallbackActivity = useSession(modelActivity, sameModelActivity);
|
|
150
152
|
// `undefined` means the key has not arrived yet; `null` is an authoritative
|
|
151
153
|
// clear and must not be resurrected by the local snapshot fallback.
|
|
152
|
-
const
|
|
153
|
-
? {
|
|
154
|
+
const normalizedProjectedActivity = projectedActivity?.activity === 'awaiting-model'
|
|
155
|
+
? {
|
|
156
|
+
activity: fallbackActivity?.activity ?? 'requesting-model',
|
|
157
|
+
startedAt: fallbackActivity?.startedAt ?? projectedActivity.startedAt,
|
|
158
|
+
}
|
|
159
|
+
: projectedActivity;
|
|
160
|
+
const activity = projectedActivity !== undefined ? normalizedProjectedActivity : (isCodexPresetId(agentPreset) && fallbackActivity !== undefined
|
|
161
|
+
? fallbackActivity
|
|
154
162
|
: null);
|
|
155
163
|
const [now, setNow] = useState(() => Date.now());
|
|
156
164
|
useEffect(() => {
|
|
@@ -159,12 +167,14 @@ export function ActivityLine({ sessionId, useSession, useSessions, useProjection
|
|
|
159
167
|
setNow(Date.now());
|
|
160
168
|
const timer = setInterval(() => { setNow(Date.now()); }, 1_000);
|
|
161
169
|
return () => clearInterval(timer);
|
|
162
|
-
}, [agentPreset, activity?.startedAt]);
|
|
170
|
+
}, [agentPreset, activity?.activity, activity?.startedAt]);
|
|
163
171
|
if (!isCodexPresetId(agentPreset) || activity === undefined || activity === null)
|
|
164
172
|
return null;
|
|
165
|
-
const label = activity.activity === '
|
|
166
|
-
? t('
|
|
167
|
-
:
|
|
173
|
+
const label = activity.activity === 'compaction'
|
|
174
|
+
? t('activityCompacting')
|
|
175
|
+
: activity.activity === 'model-reply'
|
|
176
|
+
? t('activityModelReply')
|
|
177
|
+
: t('activityRequestingModel');
|
|
168
178
|
return (_jsxs("span", { id: "codex-activity", role: "status", "aria-live": "polite", style: {
|
|
169
179
|
display: 'inline-flex',
|
|
170
180
|
alignItems: 'center',
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Codex compaction backend that honors the latest durable request capacity. */
|
|
2
|
+
import { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
import BasicCompactionEngine from '@deepseek-ai/dsh-compaction-basic';
|
|
4
|
+
import type { CompactionResult, CompactionTrigger } from '@deepseek-ai/dsh-compaction';
|
|
5
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
6
|
+
/**
|
|
7
|
+
* Keep the upstream compaction policy, retention, overflow recovery, and
|
|
8
|
+
* transaction implementation intact. The scoped LLM seam changes only the
|
|
9
|
+
* context metadata returned during a pressure check.
|
|
10
|
+
*/
|
|
11
|
+
export default class CodexCompactionEngine extends BasicCompactionEngine {
|
|
12
|
+
static inject: string[];
|
|
13
|
+
static Config: import("@deepseek-ai/schemastery").default<import("@deepseek-ai/dsh-compaction-basic").BasicCompactionConfig>;
|
|
14
|
+
private readonly activeSession;
|
|
15
|
+
constructor(ctx: Context, config?: ConstructorParameters<typeof BasicCompactionEngine>[1]);
|
|
16
|
+
compactIfNeeded(agent: Agent, trigger: CompactionTrigger, signal: AbortSignal): Promise<CompactionResult | null>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=compaction.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** Codex compaction backend that honors the latest durable request capacity. */
|
|
2
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
3
|
+
import BasicCompactionEngine from '@deepseek-ai/dsh-compaction-basic';
|
|
4
|
+
/** Overlay only the capacity lookup used by pressure compaction. */
|
|
5
|
+
function withDurableContextCapacity(llm, activeSession) {
|
|
6
|
+
return new Proxy(llm, {
|
|
7
|
+
get(target, property) {
|
|
8
|
+
if (property === 'resolveModelInfo') {
|
|
9
|
+
return async (provider, model, signal) => {
|
|
10
|
+
const info = await target.resolveModelInfo(provider, model, signal);
|
|
11
|
+
const requestContext = activeSession.getStore()?.requestContext();
|
|
12
|
+
if (requestContext?.provider !== provider
|
|
13
|
+
|| requestContext.model !== model
|
|
14
|
+
|| requestContext.contextWindow === undefined)
|
|
15
|
+
return info;
|
|
16
|
+
return {
|
|
17
|
+
...info,
|
|
18
|
+
context: { ...info.context, contextWindow: requestContext.contextWindow },
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const value = Reflect.get(target, property, target);
|
|
23
|
+
return typeof value === 'function' ? value.bind(target) : value;
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Keep the upstream compaction policy, retention, overflow recovery, and
|
|
29
|
+
* transaction implementation intact. The scoped LLM seam changes only the
|
|
30
|
+
* context metadata returned during a pressure check.
|
|
31
|
+
*/
|
|
32
|
+
export default class CodexCompactionEngine extends BasicCompactionEngine {
|
|
33
|
+
static inject = BasicCompactionEngine.inject;
|
|
34
|
+
static Config = BasicCompactionEngine.Config;
|
|
35
|
+
activeSession;
|
|
36
|
+
constructor(ctx, config = {}) {
|
|
37
|
+
const activeSession = new AsyncLocalStorage();
|
|
38
|
+
const llm = ctx.get('llm');
|
|
39
|
+
if (llm === undefined)
|
|
40
|
+
throw new Error('codex compaction requires ctx.llm');
|
|
41
|
+
super(ctx.extend({ llm: withDurableContextCapacity(llm, activeSession) }), config);
|
|
42
|
+
this.activeSession = activeSession;
|
|
43
|
+
}
|
|
44
|
+
compactIfNeeded(agent, trigger, signal) {
|
|
45
|
+
return this.activeSession.run(agent.session, () => super.compactIfNeeded(agent, trigger, signal));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=compaction.js.map
|
package/lib/types/exec.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export interface ExecResult {
|
|
|
29
29
|
exit_code?: number;
|
|
30
30
|
original_token_count?: number;
|
|
31
31
|
}
|
|
32
|
-
export declare function normalizeWaitMs(value: number | undefined, fallback: number, empty?: boolean): number;
|
|
32
|
+
export declare function normalizeWaitMs(value: number | undefined, fallback: number, empty?: boolean, initialExec?: boolean): number;
|
|
33
33
|
/** Render the ordinary Responses tool result text used by Codex's unified exec tools. */
|
|
34
34
|
export declare function renderExecResult(result: ExecResult): string;
|
|
35
35
|
/** Execute one Codex command through the configured pipe or PTY capability. */
|
package/lib/types/exec.js
CHANGED
|
@@ -3,6 +3,7 @@ import { randomBytes } from 'node:crypto';
|
|
|
3
3
|
import { resolve as resolvePath } from 'node:path';
|
|
4
4
|
const STATES = new WeakMap();
|
|
5
5
|
const MIN_YIELD_TIME_MS = 250;
|
|
6
|
+
const WINDOWS_INITIAL_EXEC_YIELD_TIME_MS = 10_000;
|
|
6
7
|
const MIN_EMPTY_YIELD_TIME_MS = 5_000;
|
|
7
8
|
const MAX_YIELD_TIME_MS = 30_000;
|
|
8
9
|
const MAX_EMPTY_YIELD_TIME_MS = 300_000;
|
|
@@ -21,8 +22,12 @@ function positiveFinite(name, value) {
|
|
|
21
22
|
throw new Error(`${name} must be a non-negative finite number`);
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
|
-
export function normalizeWaitMs(value, fallback, empty = false) {
|
|
25
|
-
const lower = empty
|
|
25
|
+
export function normalizeWaitMs(value, fallback, empty = false, initialExec = false) {
|
|
26
|
+
const lower = empty
|
|
27
|
+
? MIN_EMPTY_YIELD_TIME_MS
|
|
28
|
+
: initialExec && process.platform === 'win32'
|
|
29
|
+
? WINDOWS_INITIAL_EXEC_YIELD_TIME_MS
|
|
30
|
+
: MIN_YIELD_TIME_MS;
|
|
26
31
|
const upper = empty ? MAX_EMPTY_YIELD_TIME_MS : MAX_YIELD_TIME_MS;
|
|
27
32
|
return Math.max(lower, Math.min(upper, Math.trunc(value ?? fallback)));
|
|
28
33
|
}
|
|
@@ -178,7 +183,7 @@ export async function runExecCommand(ctx, args, exec, config) {
|
|
|
178
183
|
const sendRequest = {
|
|
179
184
|
text: commandFor(args),
|
|
180
185
|
submit: true,
|
|
181
|
-
waitMs: normalizeWaitMs(args.yield_time_ms, config.defaultYieldTimeMs),
|
|
186
|
+
waitMs: normalizeWaitMs(args.yield_time_ms, config.defaultYieldTimeMs, false, true),
|
|
182
187
|
signal: exec.signal,
|
|
183
188
|
};
|
|
184
189
|
const operation = terminals.startSend(agent, spawned.sessionId, sendRequest);
|
|
@@ -250,7 +255,7 @@ export async function runExecCommand(ctx, args, exec, config) {
|
|
|
250
255
|
signal: exec.signal,
|
|
251
256
|
}));
|
|
252
257
|
try {
|
|
253
|
-
await waitForShell(process, normalizeWaitMs(args.yield_time_ms, config.defaultYieldTimeMs), exec.signal);
|
|
258
|
+
await waitForShell(process, normalizeWaitMs(args.yield_time_ms, config.defaultYieldTimeMs, false, true), exec.signal);
|
|
254
259
|
const output = readShellOutput(process.readOutput(), maxBytes);
|
|
255
260
|
if (process.status === 'running') {
|
|
256
261
|
if (exec.agent === undefined) {
|
package/lib/types/index.js
CHANGED
|
@@ -9,12 +9,13 @@ import { hostedWebSearchStream, installHostedWebSearch, remoteCompactStream } fr
|
|
|
9
9
|
import { registerCodexActivityProjection } from "./activity.js";
|
|
10
10
|
export const name = 'codex';
|
|
11
11
|
export const inject = ['tools', 'systemPrompt', 'shell', 'fs', 'llm', 'credentials', 'settings'];
|
|
12
|
+
const DEFAULT_MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
12
13
|
/** Runtime configuration schema for the Codex tool bridge. */
|
|
13
14
|
export const Config = z.object({
|
|
14
15
|
defaultYieldTimeMs: z.number().step(1).min(0).default(10_000),
|
|
15
16
|
pollYieldTimeMs: z.number().step(1).min(0).default(5_000),
|
|
16
17
|
writeYieldTimeMs: z.number().step(1).min(0).default(250),
|
|
17
|
-
maxOutputBytes: z.number().step(1).min(1).default(
|
|
18
|
+
maxOutputBytes: z.number().step(1).min(1).default(DEFAULT_MAX_OUTPUT_BYTES),
|
|
18
19
|
hostedWebSearch: z.boolean().default(true),
|
|
19
20
|
remoteCompact: z.boolean().default(true),
|
|
20
21
|
collaborationPrompt: z.boolean().default(false),
|
|
@@ -451,7 +452,7 @@ export function apply(ctx, config = {}) {
|
|
|
451
452
|
defaultYieldTimeMs: config.defaultYieldTimeMs ?? 10_000,
|
|
452
453
|
pollYieldTimeMs: config.pollYieldTimeMs ?? 5_000,
|
|
453
454
|
writeYieldTimeMs: config.writeYieldTimeMs ?? 250,
|
|
454
|
-
maxOutputBytes: config.maxOutputBytes ??
|
|
455
|
+
maxOutputBytes: config.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
455
456
|
hostedWebSearch: config.hostedWebSearch ?? true,
|
|
456
457
|
remoteCompact: config.remoteCompact ?? true,
|
|
457
458
|
collaborationPrompt: config.collaborationPrompt ?? false,
|
package/lib/types/patch.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/** Parser and line-oriented applicator for Codex's `apply_patch` language. */
|
|
2
2
|
export const APPLY_PATCH_DESCRIPTION = 'Edits files using Codex patch syntax with Begin/End Patch markers and file update directives. In hunk lines, the first character is the operation marker; repeat a source-leading marker when the source line itself starts with one.';
|
|
3
3
|
/** The grammar sent to providers that support OpenAI custom grammar tools. */
|
|
4
|
-
export const APPLY_PATCH_GRAMMAR = String.raw `start: begin_patch
|
|
4
|
+
export const APPLY_PATCH_GRAMMAR = String.raw `start: begin_patch hunk+ end_patch
|
|
5
5
|
begin_patch: "*** Begin Patch" LF
|
|
6
|
-
environment_id: "*** Environment ID: " filename LF
|
|
7
6
|
end_patch: "*** End Patch" LF?
|
|
8
7
|
hunk: add_hunk | delete_hunk | update_hunk
|
|
9
8
|
add_hunk: "*** Add File: " filename LF add_line+
|
|
@@ -27,7 +26,6 @@ function isFileHeader(line) {
|
|
|
27
26
|
|| trimmed.startsWith('*** Delete File: ')
|
|
28
27
|
|| trimmed.startsWith('*** Update File: ');
|
|
29
28
|
}
|
|
30
|
-
const ENVIRONMENT_ID_MARKER = '*** Environment ID:';
|
|
31
29
|
function unwrapHeredoc(input) {
|
|
32
30
|
const normalized = input.replaceAll('\r\n', '\n').trim();
|
|
33
31
|
const lines = normalized.split('\n');
|
|
@@ -63,14 +61,8 @@ export function parsePatch(input) {
|
|
|
63
61
|
const files = [];
|
|
64
62
|
let index = 1;
|
|
65
63
|
const end = lines.length - 1;
|
|
66
|
-
if (lines[index]?.trim().startsWith(
|
|
67
|
-
|
|
68
|
-
if (environmentId.length === 0)
|
|
69
|
-
invalid('environment id cannot be empty');
|
|
70
|
-
index++;
|
|
71
|
-
if (lines[index]?.trim().startsWith(ENVIRONMENT_ID_MARKER) === true) {
|
|
72
|
-
invalid('environment id cannot be specified more than once');
|
|
73
|
-
}
|
|
64
|
+
if (lines[index]?.trim().startsWith('*** Environment ID:') === true) {
|
|
65
|
+
invalid('environment selection is unavailable in this single-environment DSH plugin');
|
|
74
66
|
}
|
|
75
67
|
while (index < end) {
|
|
76
68
|
const header = lines[index++]?.trim();
|
package/lib/types/remote.js
CHANGED
|
@@ -437,6 +437,36 @@ function compactText(body) {
|
|
|
437
437
|
const encrypted = text.join('\n\n').trim();
|
|
438
438
|
return encrypted.length === 0 ? '' : `${REMOTE_COMPACTION_OPEN}${encrypted}${REMOTE_COMPACTION_CLOSE}`;
|
|
439
439
|
}
|
|
440
|
+
function nonNegativeInteger(value) {
|
|
441
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
442
|
+
}
|
|
443
|
+
/** Map the Responses compact usage object without inventing missing counts. */
|
|
444
|
+
function compactUsage(body) {
|
|
445
|
+
if (typeof body.usage !== 'object' || body.usage === null)
|
|
446
|
+
return undefined;
|
|
447
|
+
const raw = body.usage;
|
|
448
|
+
const inputTokens = nonNegativeInteger(raw.input_tokens);
|
|
449
|
+
const outputTokens = nonNegativeInteger(raw.output_tokens);
|
|
450
|
+
if (inputTokens === undefined || outputTokens === undefined)
|
|
451
|
+
return undefined;
|
|
452
|
+
const details = typeof raw.input_tokens_details === 'object' && raw.input_tokens_details !== null
|
|
453
|
+
? raw.input_tokens_details
|
|
454
|
+
: undefined;
|
|
455
|
+
const cacheReadTokens = nonNegativeInteger(details?.cached_tokens);
|
|
456
|
+
const cacheWriteTokens = nonNegativeInteger(details?.cache_write_tokens);
|
|
457
|
+
const cached = cacheReadTokens ?? 0;
|
|
458
|
+
const writes = cacheWriteTokens ?? 0;
|
|
459
|
+
// Responses input_tokens includes the cache buckets. Reject an inconsistent
|
|
460
|
+
// response instead of clamping it and reporting numbers that no longer sum.
|
|
461
|
+
if (cached + writes > inputTokens)
|
|
462
|
+
return undefined;
|
|
463
|
+
return {
|
|
464
|
+
inputTokens: inputTokens - cached - writes,
|
|
465
|
+
outputTokens,
|
|
466
|
+
...cacheReadTokens !== undefined && cacheReadTokens > 0 ? { cacheReadTokens } : {},
|
|
467
|
+
...cacheWriteTokens !== undefined && cacheWriteTokens > 0 ? { cacheWriteTokens } : {},
|
|
468
|
+
};
|
|
469
|
+
}
|
|
440
470
|
async function remoteCompact(ctx, options) {
|
|
441
471
|
const profile = profileOf(ctx, options.provider);
|
|
442
472
|
if (!supportsResponses(profile, options.provider) || profile?.baseURL === undefined) {
|
|
@@ -457,17 +487,19 @@ async function remoteCompact(ctx, options) {
|
|
|
457
487
|
const text = compactText(body);
|
|
458
488
|
if (text.length === 0)
|
|
459
489
|
throw new Error('remote compaction returned no compaction text');
|
|
460
|
-
|
|
490
|
+
const usage = compactUsage(body);
|
|
491
|
+
return { text, ...usage === undefined ? {} : { usage } };
|
|
461
492
|
}
|
|
462
493
|
/** Remote-first compaction waterfall with the existing DSH path as fallback. */
|
|
463
494
|
export function remoteCompactStream(ctx, options, next) {
|
|
464
495
|
return (async function* () {
|
|
465
496
|
try {
|
|
466
|
-
const
|
|
497
|
+
const result = await remoteCompact(ctx, options);
|
|
467
498
|
yield { type: 'block-start', index: 0, blockType: 'text' };
|
|
468
|
-
yield { type: 'text-delta', index: 0, text };
|
|
469
|
-
yield { type: 'block-end', index: 0, block: { type: 'text', text } };
|
|
470
|
-
|
|
499
|
+
yield { type: 'text-delta', index: 0, text: result.text };
|
|
500
|
+
yield { type: 'block-end', index: 0, block: { type: 'text', text: result.text } };
|
|
501
|
+
if (result.usage !== undefined)
|
|
502
|
+
yield { type: 'usage', usage: result.usage };
|
|
471
503
|
yield { type: 'finish', reason: { kind: 'stop' } };
|
|
472
504
|
}
|
|
473
505
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shuind/dsh-codex-harness",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"description": "A Codex harness with a streamlined system prompt for GPT models that do not fit DSH's native interface, while remaining compatible with the DSH plugin ecosystem.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
"types": "./lib/types/installer.d.ts",
|
|
19
19
|
"default": "./lib/installer.js"
|
|
20
20
|
},
|
|
21
|
+
"./compaction": {
|
|
22
|
+
"types": "./lib/types/compaction.d.ts",
|
|
23
|
+
"default": "./lib/compaction.js"
|
|
24
|
+
},
|
|
21
25
|
"./client": {
|
|
22
26
|
"types": "./lib/types/client/index.d.ts",
|
|
23
27
|
"default": "./lib/client.js"
|
|
@@ -30,6 +34,7 @@
|
|
|
30
34
|
"lib/index.js",
|
|
31
35
|
"lib/invariant.js",
|
|
32
36
|
"lib/installer.js",
|
|
37
|
+
"lib/compaction.js",
|
|
33
38
|
"lib/types/**/*.js",
|
|
34
39
|
"lib/types/**/*.d.ts",
|
|
35
40
|
"lib/client.js",
|
|
@@ -87,6 +92,9 @@
|
|
|
87
92
|
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.0-rc.8",
|
|
88
93
|
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.0-rc.8",
|
|
89
94
|
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.0-rc.8",
|
|
95
|
+
"@deepseek-ai/dsh-compaction": ">=0.1.1-rc.2",
|
|
96
|
+
"@deepseek-ai/dsh-compaction-basic": ">=0.1.1-rc.2",
|
|
97
|
+
"@deepseek-ai/dsh-compaction-tool-result-pruner": ">=0.1.1-rc.2",
|
|
90
98
|
"@deepseek-ai/dsh-credentials": ">=0.1.0-rc.8",
|
|
91
99
|
"@deepseek-ai/dsh-fs": ">=0.0.1-rc.1",
|
|
92
100
|
"@deepseek-ai/dsh-invariants": ">=0.0.1-rc.1",
|
|
@@ -95,6 +103,7 @@
|
|
|
95
103
|
"@deepseek-ai/dsh-settings": ">=0.1.0-rc.8",
|
|
96
104
|
"@deepseek-ai/dsh-sandbox": ">=0.0.1-rc.1",
|
|
97
105
|
"@deepseek-ai/dsh-sandbox-policy": ">=0.0.1-rc.1",
|
|
106
|
+
"@deepseek-ai/dsh-session": ">=0.1.1-rc.2",
|
|
98
107
|
"@deepseek-ai/dsh-shell": ">=0.0.1-rc.5",
|
|
99
108
|
"@deepseek-ai/dsh-shell-env": ">=0.0.1-rc.3",
|
|
100
109
|
"@deepseek-ai/dsh-system-prompt": ">=0.0.1-rc.1",
|
|
@@ -102,6 +111,7 @@
|
|
|
102
111
|
"@deepseek-ai/dsh-tool-todo": ">=0.0.1-rc.1",
|
|
103
112
|
"@deepseek-ai/dsh-terminal": ">=0.0.1-rc.3",
|
|
104
113
|
"@deepseek-ai/dsh-tool-jobs": ">=0.1.0-rc.8",
|
|
114
|
+
"@deepseek-ai/dsh-token-meter": ">=0.1.1-rc.2",
|
|
105
115
|
"@deepseek-ai/dsh-tools": ">=0.0.1-rc.1"
|
|
106
116
|
},
|
|
107
117
|
"peerDependenciesMeta": {
|
|
@@ -126,6 +136,15 @@
|
|
|
126
136
|
"@deepseek-ai/dsh-client-ui-slots": {
|
|
127
137
|
"optional": true
|
|
128
138
|
},
|
|
139
|
+
"@deepseek-ai/dsh-compaction": {
|
|
140
|
+
"optional": true
|
|
141
|
+
},
|
|
142
|
+
"@deepseek-ai/dsh-compaction-basic": {
|
|
143
|
+
"optional": true
|
|
144
|
+
},
|
|
145
|
+
"@deepseek-ai/dsh-compaction-tool-result-pruner": {
|
|
146
|
+
"optional": true
|
|
147
|
+
},
|
|
129
148
|
"@deepseek-ai/dsh-credentials": {
|
|
130
149
|
"optional": true
|
|
131
150
|
},
|
|
@@ -150,6 +169,9 @@
|
|
|
150
169
|
"@deepseek-ai/dsh-sandbox-policy": {
|
|
151
170
|
"optional": true
|
|
152
171
|
},
|
|
172
|
+
"@deepseek-ai/dsh-session": {
|
|
173
|
+
"optional": true
|
|
174
|
+
},
|
|
153
175
|
"@deepseek-ai/dsh-shell": {
|
|
154
176
|
"optional": true
|
|
155
177
|
},
|
|
@@ -171,6 +193,9 @@
|
|
|
171
193
|
"@deepseek-ai/dsh-tool-jobs": {
|
|
172
194
|
"optional": true
|
|
173
195
|
},
|
|
196
|
+
"@deepseek-ai/dsh-token-meter": {
|
|
197
|
+
"optional": true
|
|
198
|
+
},
|
|
174
199
|
"@deepseek-ai/dsh-tools": {
|
|
175
200
|
"optional": true
|
|
176
201
|
}
|
|
@@ -183,6 +208,9 @@
|
|
|
183
208
|
"@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.8",
|
|
184
209
|
"@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.8",
|
|
185
210
|
"@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.8",
|
|
211
|
+
"@deepseek-ai/dsh-compaction": "0.1.1-rc.2",
|
|
212
|
+
"@deepseek-ai/dsh-compaction-basic": "0.1.1-rc.2",
|
|
213
|
+
"@deepseek-ai/dsh-compaction-tool-result-pruner": "0.1.1-rc.2",
|
|
186
214
|
"@deepseek-ai/dsh-credentials": "0.1.0-rc.8",
|
|
187
215
|
"@deepseek-ai/dsh-fs": "0.1.0-rc.6",
|
|
188
216
|
"@deepseek-ai/dsh-invariants": "0.1.0-rc.6",
|
|
@@ -191,6 +219,7 @@
|
|
|
191
219
|
"@deepseek-ai/dsh-settings": "0.1.0-rc.8",
|
|
192
220
|
"@deepseek-ai/dsh-sandbox": "0.1.0-rc.6",
|
|
193
221
|
"@deepseek-ai/dsh-sandbox-policy": "0.1.0-rc.6",
|
|
222
|
+
"@deepseek-ai/dsh-session": "0.1.1-rc.2",
|
|
194
223
|
"@deepseek-ai/dsh-shell": "0.1.0-rc.6",
|
|
195
224
|
"@deepseek-ai/dsh-shell-env": "0.1.0-rc.6",
|
|
196
225
|
"@deepseek-ai/dsh-system-prompt": "0.1.0-rc.6",
|
|
@@ -198,6 +227,7 @@
|
|
|
198
227
|
"@deepseek-ai/dsh-tool-todo": "0.1.0-rc.6",
|
|
199
228
|
"@deepseek-ai/dsh-terminal": "0.1.0-rc.6",
|
|
200
229
|
"@deepseek-ai/dsh-tool-jobs": "0.1.0-rc.8",
|
|
230
|
+
"@deepseek-ai/dsh-token-meter": "0.1.1-rc.2",
|
|
201
231
|
"@deepseek-ai/dsh-tools": "0.1.0-rc.6",
|
|
202
232
|
"@types/node": "^22.20.0",
|
|
203
233
|
"@types/react": "~18.3.1",
|