@jingyi0605/codingns4dsh 0.1.0 → 0.1.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/README.en.md +306 -0
- package/README.md +190 -993
- package/data/build/dist/client/account-bar.d.ts +2 -2
- package/data/build/dist/client/account-bar.js +96 -39
- package/data/build/dist/client/bundle.js +13722 -3611
- package/data/build/dist/client/cli-catalog.js +20 -3
- package/data/build/dist/client/cli-slots.d.ts +5 -0
- package/data/build/dist/client/cli-slots.js +57 -7
- package/data/build/dist/client/debug/ui.d.ts +1 -1
- package/data/build/dist/client/debug/ui.js +62 -32
- package/data/build/dist/client/dsh-runtime-version.d.ts +9 -2
- package/data/build/dist/client/dsh-runtime-version.js +24 -2
- package/data/build/dist/client/features/cli-adapters.d.ts +1 -1
- package/data/build/dist/client/features/cli-adapters.js +19 -16
- package/data/build/dist/client/features/debug.js +2 -2
- package/data/build/dist/client/features/index.d.ts +2 -1
- package/data/build/dist/client/features/index.js +3 -1
- package/data/build/dist/client/features/lan-access-panel.d.ts +1 -1
- package/data/build/dist/client/features/lan-access-panel.js +8 -10
- package/data/build/dist/client/features/lan-access.js +1 -1
- package/data/build/dist/client/features/login-protection-panel.d.ts +1 -1
- package/data/build/dist/client/features/login-protection-panel.js +7 -9
- package/data/build/dist/client/features/reverse-proxy-panel.d.ts +1 -1
- package/data/build/dist/client/features/reverse-proxy-panel.js +99 -11
- package/data/build/dist/client/features/reverse-proxy.d.ts +1 -1
- package/data/build/dist/client/features/reverse-proxy.js +19 -18
- package/data/build/dist/client/features/terminal-enhancement-panel.d.ts +1 -1
- package/data/build/dist/client/features/terminal-enhancement-panel.js +62 -55
- package/data/build/dist/client/features/terminal-enhancement.d.ts +1 -1
- package/data/build/dist/client/features/terminal-enhancement.js +3 -3
- package/data/build/dist/client/features/types.d.ts +14 -3
- package/data/build/dist/client/features/workspace-session-enhancement-panel.d.ts +1 -1
- package/data/build/dist/client/features/workspace-session-enhancement-panel.js +31 -9
- package/data/build/dist/client/features/workspace-session-enhancement.js +72 -11
- package/data/build/dist/client/git-management.d.ts +16 -0
- package/data/build/dist/client/git-management.js +757 -0
- package/data/build/dist/client/index.d.ts +3 -2
- package/data/build/dist/client/index.js +152 -27
- package/data/build/dist/client/locale.js +91 -29
- package/data/build/dist/client/quick-phrase-layout.d.ts +49 -0
- package/data/build/dist/client/quick-phrase-layout.js +95 -0
- package/data/build/dist/client/quick-phrase-slot.d.ts +7 -0
- package/data/build/dist/client/quick-phrase-slot.js +370 -0
- package/data/build/dist/client/remote-web-context.js +1 -1
- package/data/build/dist/client/settings-bridge.d.ts +9 -6
- package/data/build/dist/client/settings-bridge.js +51 -27
- package/data/build/dist/client/settings-section.d.ts +3 -2
- package/data/build/dist/client/settings-section.js +33 -19
- package/data/build/dist/client/subscription-slot.d.ts +3 -0
- package/data/build/dist/client/subscription-slot.js +108 -16
- package/data/build/dist/client/terminal/model.d.ts +14 -2
- package/data/build/dist/client/terminal/model.js +109 -21
- package/data/build/dist/client/terminal/recovery.d.ts +50 -0
- package/data/build/dist/client/terminal/recovery.js +101 -0
- package/data/build/dist/client/terminal/ui.d.ts +2 -2
- package/data/build/dist/client/terminal/ui.js +49 -11
- package/data/build/dist/client/terminal/xterm-view.d.ts +2 -2
- package/data/build/dist/client/terminal/xterm-view.js +2 -1
- package/data/build/dist/client/theme.d.ts +6 -1
- package/data/build/dist/client/theme.js +32 -1
- package/data/build/dist/client/workspace-session-archive-dom.d.ts +12 -0
- package/data/build/dist/client/workspace-session-archive-dom.js +27 -5
- package/data/build/dist/client/workspace-session-visibility-dom.d.ts +30 -0
- package/data/build/dist/client/workspace-session-visibility-dom.js +604 -0
- package/data/build/dist/dsh-capabilities/client/config-forms-adapter.d.ts +50 -0
- package/data/build/dist/dsh-capabilities/client/config-forms-adapter.js +139 -0
- package/data/build/dist/dsh-capabilities/client/conversation-adapter.d.ts +7 -0
- package/data/build/dist/dsh-capabilities/client/conversation-adapter.js +6 -0
- package/data/build/dist/dsh-capabilities/client/locale-adapter.d.ts +9 -0
- package/data/build/dist/dsh-capabilities/client/locale-adapter.js +4 -0
- package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts +10 -0
- package/data/build/dist/dsh-capabilities/client/primitives-adapter.js +14 -0
- package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.d.ts +8 -0
- package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.js +16 -0
- package/data/build/dist/dsh-capabilities/client/sidebar-adapter.d.ts +7 -0
- package/data/build/dist/dsh-capabilities/client/sidebar-adapter.js +5 -0
- package/data/build/dist/dsh-capabilities/client/theme-adapter.d.ts +6 -0
- package/data/build/dist/dsh-capabilities/client/theme-adapter.js +4 -0
- package/data/build/dist/dsh-capabilities/client/typert-adapter.d.ts +5 -0
- package/data/build/dist/dsh-capabilities/client/typert-adapter.js +4 -0
- package/data/build/dist/dsh-capabilities/host/config-forms-adapter.d.ts +19 -0
- package/data/build/dist/dsh-capabilities/host/config-forms-adapter.js +45 -0
- package/data/build/dist/dsh-capabilities/host/connection-rpc-adapter.d.ts +19 -0
- package/data/build/dist/dsh-capabilities/host/connection-rpc-adapter.js +13 -0
- package/data/build/dist/dsh-capabilities/host/settings-scope-adapter.d.ts +8 -0
- package/data/build/dist/dsh-capabilities/host/settings-scope-adapter.js +47 -0
- package/data/build/dist/dsh-capabilities/host/typert-adapter.d.ts +6 -0
- package/data/build/dist/dsh-capabilities/host/typert-adapter.js +4 -0
- package/data/build/dist/dsh-capabilities/index.d.ts +6 -0
- package/data/build/dist/dsh-capabilities/index.js +6 -0
- package/data/build/dist/dsh-capabilities/matrix.d.ts +15 -0
- package/data/build/dist/dsh-capabilities/matrix.js +32 -0
- package/data/build/dist/dsh-capabilities/registry.d.ts +22 -0
- package/data/build/dist/dsh-capabilities/registry.js +196 -0
- package/data/build/dist/dsh-capabilities/routes.d.ts +10 -0
- package/data/build/dist/dsh-capabilities/routes.js +34 -0
- package/data/build/dist/dsh-capabilities/settings-store.d.ts +29 -0
- package/data/build/dist/dsh-capabilities/settings-store.js +5 -0
- package/data/build/dist/dsh-capabilities/types.d.ts +50 -0
- package/data/build/dist/dsh-capabilities/types.js +23 -0
- package/data/build/dist/features/registry.d.ts +8 -2
- package/data/build/dist/features/registry.js +104 -1
- package/data/build/dist/host/auth-session.d.ts +8 -1
- package/data/build/dist/host/auth-session.js +28 -6
- package/data/build/dist/host/cli-adapters/claude-driver.d.ts +2 -0
- package/data/build/dist/host/cli-adapters/claude-driver.js +19 -4
- package/data/build/dist/host/cli-adapters/claude-model-options.d.ts +14 -0
- package/data/build/dist/host/cli-adapters/claude-model-options.js +157 -0
- package/data/build/dist/host/cli-adapters/codex-driver.d.ts +11 -0
- package/data/build/dist/host/cli-adapters/codex-driver.js +166 -14
- package/data/build/dist/host/cli-adapters/driver.d.ts +2 -0
- package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +15 -0
- package/data/build/dist/host/cli-adapters/dsh-message-projector.js +120 -29
- package/data/build/dist/host/cli-adapters/dsh-tool-history.d.ts +4 -1
- package/data/build/dist/host/cli-adapters/dsh-tool-history.js +25 -7
- package/data/build/dist/host/cli-adapters/feature.js +74 -8
- package/data/build/dist/host/cli-adapters/gemini-driver.js +2 -2
- package/data/build/dist/host/cli-adapters/grok-driver.js +2 -2
- package/data/build/dist/host/cli-adapters/json-rpc-process.d.ts +4 -2
- package/data/build/dist/host/cli-adapters/json-rpc-process.js +8 -9
- package/data/build/dist/host/cli-adapters/kimi-driver.js +1 -1
- package/data/build/dist/host/cli-adapters/legacy-session-adapter.d.ts +17 -0
- package/data/build/dist/host/cli-adapters/legacy-session-adapter.js +88 -0
- package/data/build/dist/host/cli-adapters/legacy-session-settings.d.ts +24 -0
- package/data/build/dist/host/cli-adapters/legacy-session-settings.js +162 -0
- package/data/build/dist/host/cli-adapters/official-provider-subscription.d.ts +29 -0
- package/data/build/dist/host/cli-adapters/official-provider-subscription.js +361 -0
- package/data/build/dist/host/cli-adapters/opencode-driver.d.ts +2 -0
- package/data/build/dist/host/cli-adapters/opencode-driver.js +97 -12
- package/data/build/dist/host/cli-adapters/pi-driver.js +69 -23
- package/data/build/dist/host/cli-adapters/provider-registry.d.ts +33 -0
- package/data/build/dist/host/cli-adapters/provider-registry.js +83 -0
- package/data/build/dist/host/cli-adapters/provider-subscription.d.ts +25 -3
- package/data/build/dist/host/cli-adapters/provider-subscription.js +346 -30
- package/data/build/dist/host/cli-adapters/registry.d.ts +6 -0
- package/data/build/dist/host/cli-adapters/registry.js +170 -13
- package/data/build/dist/host/cli-adapters/rpc-driver-utils.js +10 -0
- package/data/build/dist/host/cli-adapters/session-store.d.ts +7 -0
- package/data/build/dist/host/cli-adapters/session-store.js +39 -1
- package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts +3 -0
- package/data/build/dist/host/cli-adapters/stream-normalizer.d.ts +3 -0
- package/data/build/dist/host/cli-adapters/stream-normalizer.js +22 -2
- package/data/build/dist/host/control-api-client.d.ts +3 -3
- package/data/build/dist/host/control-api-client.js +2 -1
- package/data/build/dist/host/credential-store.js +11 -1
- package/data/build/dist/host/dsh-device-runtime.d.ts +4 -0
- package/data/build/dist/host/dsh-device-runtime.js +20 -9
- package/data/build/dist/host/features/auth.js +8 -5
- package/data/build/dist/host/features/debug.js +1 -1
- package/data/build/dist/host/features/git-management.d.ts +5 -0
- package/data/build/dist/host/features/git-management.js +290 -0
- package/data/build/dist/host/features/host-status.js +1 -1
- package/data/build/dist/host/features/index.d.ts +1 -0
- package/data/build/dist/host/features/index.js +3 -0
- package/data/build/dist/host/features/terminal-process.js +1 -1
- package/data/build/dist/host/features/terminal-status.d.ts +3 -1
- package/data/build/dist/host/features/terminal-status.js +3 -1
- package/data/build/dist/host/index.d.ts +7 -3
- package/data/build/dist/host/index.js +76 -11
- package/data/build/dist/host/lan-access-dsh.js +18 -5
- package/data/build/dist/host/native-session-bridge.d.ts +23 -1
- package/data/build/dist/host/native-session-bridge.js +157 -10
- package/data/build/dist/host/rpc-table.d.ts +1 -1
- package/data/build/dist/host/rpc.js +60 -10
- package/data/build/dist/host/session-migration-repair.d.ts +19 -0
- package/data/build/dist/host/session-migration-repair.js +395 -0
- package/data/build/dist/host/settings.d.ts +8 -1
- package/data/build/dist/host/settings.js +94 -3
- package/data/build/dist/host/terminal/backends/tmux-backend.d.ts +1 -0
- package/data/build/dist/host/terminal/backends/tmux-backend.js +4 -2
- package/data/build/dist/host/terminal/controller-factory.d.ts +4 -0
- package/data/build/dist/host/terminal/controller-factory.js +26 -7
- package/data/build/dist/host/terminal/runtime-manager.d.ts +2 -1
- package/data/build/dist/host/terminal/runtime-manager.js +3 -0
- package/data/build/dist/host/terminal/startup.d.ts +2 -0
- package/data/build/dist/host/terminal/startup.js +2 -1
- package/data/build/dist/host/terminal/terminal-controller.d.ts +10 -3
- package/data/build/dist/host/terminal/terminal-controller.js +101 -15
- package/data/build/dist/host/terminal/terminal-process-service.js +3 -1
- package/data/build/dist/host/terminal/terminal-service.d.ts +2 -0
- package/data/build/dist/host/terminal/terminal-service.js +10 -0
- package/data/build/dist/index.d.ts +6 -2
- package/data/build/dist/index.js +8 -2
- package/data/build/dist/shared/contracts/cli-adapter.d.ts +14 -0
- package/data/build/dist/shared/contracts/config.d.ts +31 -1
- package/data/build/dist/shared/contracts/config.js +25 -0
- package/data/build/dist/shared/contracts/dsh-device.d.ts +13 -1
- package/data/build/dist/shared/contracts/errors.d.ts +1 -1
- package/data/build/dist/shared/contracts/feature.d.ts +6 -0
- package/data/build/dist/shared/contracts/git.d.ts +82 -0
- package/data/build/dist/shared/contracts/git.js +3 -0
- package/data/build/dist/shared/contracts/subscription.d.ts +46 -0
- package/data/build/dist/shared/contracts/terminal.d.ts +4 -1
- package/data/build/dist/shared/contracts/version.d.ts +2 -2
- package/data/build/dist/shared/contracts/version.js +4 -6
- package/data/build/dist/shared/debug.d.ts +14 -0
- package/data/build/dist/shared/debug.js +53 -0
- package/data/build/dist/shared/index.d.ts +7 -4
- package/data/build/dist/shared/index.js +2 -1
- package/data/build/dist/transport/debug.d.ts +1 -1
- package/data/build/dist/transport/debug.js +3 -30
- package/data/build/dist/transport/dsh-session.js +3 -3
- package/data/build/dist/typert.host.js +4 -2
- package/data/build/dist/typert.remote-client.d.ts +11 -0
- package/data/build/dist/typert.remote-client.js +7 -0
- package/dsh.bundle.patch +1 -1
- package/package.json +17 -5
- package/profile/README.md +4 -4
- package/profile/package.json +6 -4
- package/profile/scripts/check-dsh-install.mjs +2 -2
- package/profile/version.json +2 -2
- package/scripts/check-dsh-install.mjs +2 -2
- package/version.json +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CodingNsRpcError } from '../rpc-table.js';
|
|
2
2
|
import { CodingNsCliSessionStore } from './session-store.js';
|
|
3
|
+
import { readLegacyImportedAdapterPreferences } from './legacy-session-settings.js';
|
|
3
4
|
const DEFAULT_INSTALLED_CACHE_TTL_MS = 5 * 60_000;
|
|
4
5
|
const DEFAULT_UNINSTALLED_CACHE_TTL_MS = 30_000;
|
|
5
6
|
const DEFAULT_MODEL_CACHE_TTL_MS = 10 * 60_000;
|
|
@@ -28,6 +29,8 @@ export class CodingNsCliAdapterRegistry {
|
|
|
28
29
|
modelTimers = new Map();
|
|
29
30
|
modelGenerations = new Map();
|
|
30
31
|
requestedModelCatalogs = new Set();
|
|
32
|
+
/** 已切到下一个 DSH step、但仍在继续产出 Provider 流的驱动迭代器。 */
|
|
33
|
+
segmentedTurns = new Map();
|
|
31
34
|
cacheGeneration = 0;
|
|
32
35
|
disposed = false;
|
|
33
36
|
constructor(drivers, enabled = {}, options = {}) {
|
|
@@ -42,7 +45,15 @@ export class CodingNsCliAdapterRegistry {
|
|
|
42
45
|
this.uninstalledCacheTtlMs = positiveTtl(options.uninstalledCacheTtlMs, DEFAULT_UNINSTALLED_CACHE_TTL_MS);
|
|
43
46
|
this.modelCacheTtlMs = positiveTtl(options.modelCacheTtlMs, DEFAULT_MODEL_CACHE_TTL_MS);
|
|
44
47
|
this.modelRetryTtlMs = positiveTtl(options.modelRetryTtlMs, DEFAULT_MODEL_RETRY_TTL_MS);
|
|
45
|
-
|
|
48
|
+
const configuredPreferences = options.settings?.get().agentAdapterPreferences;
|
|
49
|
+
const legacyPreferences = options.settings === undefined ? {} : readLegacyImportedAdapterPreferences();
|
|
50
|
+
const mergedPreferences = mergePreferenceRecords(legacyPreferences, configuredPreferences);
|
|
51
|
+
this.syncPreferences(mergedPreferences);
|
|
52
|
+
// DSH 0.1.7 不会把旧 `codingns` 设置段自动映射到 scoped Config entry。
|
|
53
|
+
// 先用旧值恢复当前进程,再把缺失值写入新配置,后续重启即可走正常路径。
|
|
54
|
+
if (options.settings !== undefined && hasMissingPreferences(configuredPreferences, legacyPreferences)) {
|
|
55
|
+
void options.settings.update({ agentAdapterPreferences: preferenceSnapshot(this.preferences) }).catch(() => undefined);
|
|
56
|
+
}
|
|
46
57
|
for (const driver of drivers) {
|
|
47
58
|
if (this.drivers.has(driver.descriptor.id))
|
|
48
59
|
throw new Error(`重复 Agent: ${driver.descriptor.id}`);
|
|
@@ -137,6 +148,11 @@ export class CodingNsCliAdapterRegistry {
|
|
|
137
148
|
: remembered?.effortId
|
|
138
149
|
? { effortId: remembered.effortId }
|
|
139
150
|
: {}),
|
|
151
|
+
...(config.providerId?.trim()
|
|
152
|
+
? { providerId: config.providerId.trim() }
|
|
153
|
+
: sameAdapter && previous?.providerId
|
|
154
|
+
? { providerId: previous.providerId }
|
|
155
|
+
: {}),
|
|
140
156
|
...(providerSessionId ? { providerSessionId } : sameAdapter && previous?.providerSessionId ? { providerSessionId: previous.providerSessionId } : {}),
|
|
141
157
|
...(config.rawStoreRef?.trim()
|
|
142
158
|
? { rawStoreRef: config.rawStoreRef.trim() }
|
|
@@ -153,6 +169,10 @@ export class CodingNsCliAdapterRegistry {
|
|
|
153
169
|
syncPreferences(value) {
|
|
154
170
|
if (value === undefined)
|
|
155
171
|
return;
|
|
172
|
+
// 0.1.7 ConfigForms 在 entry 重新描述的瞬间可能只返回默认空字典;
|
|
173
|
+
// 不能让这次短暂快照抹掉当前进程已经恢复的选择。
|
|
174
|
+
if (Object.keys(value).length === 0 && this.preferences.size > 0)
|
|
175
|
+
return;
|
|
156
176
|
this.preferences.clear();
|
|
157
177
|
for (const [adapterId, preference] of Object.entries(value)) {
|
|
158
178
|
const modelId = preference?.modelId?.trim();
|
|
@@ -194,19 +214,24 @@ export class CodingNsCliAdapterRegistry {
|
|
|
194
214
|
this.preferences.set(adapterId, preference);
|
|
195
215
|
if (this.settings === undefined)
|
|
196
216
|
return;
|
|
197
|
-
const snapshot =
|
|
217
|
+
const snapshot = preferenceSnapshot(this.preferences);
|
|
198
218
|
void this.settings.update({ agentAdapterPreferences: snapshot }).catch(() => undefined);
|
|
199
219
|
}
|
|
200
220
|
getSession(sessionId) {
|
|
201
221
|
const session = this.sessions.get(sessionId);
|
|
202
|
-
if (session !== undefined && (session.adapterId === 'dsh' || this.isEnabled(session.adapterId)))
|
|
203
|
-
return session;
|
|
222
|
+
if (session !== undefined && (session.adapterId === 'dsh' || this.isEnabled(session.adapterId))) {
|
|
223
|
+
return session.adapterId === 'dsh' ? mergeDshNativeSelection(session, this.nativeSessions?.get(sessionId)) : session;
|
|
224
|
+
}
|
|
204
225
|
const remembered = this.preferences.get('dsh') ?? this.findRememberedPreference('dsh');
|
|
205
|
-
return {
|
|
226
|
+
return mergeDshNativeSelection({
|
|
206
227
|
adapterId: 'dsh',
|
|
207
228
|
...(remembered?.modelId ? { modelId: remembered.modelId } : {}),
|
|
208
229
|
...(remembered?.effortId ? { effortId: remembered.effortId } : {}),
|
|
209
|
-
};
|
|
230
|
+
}, this.nativeSessions?.get(sessionId));
|
|
231
|
+
}
|
|
232
|
+
/** 只有驱动自己维护 Provider turn 边界时,Host 才能把它映射到 DSH step。 */
|
|
233
|
+
supportsSegmentedTurns(adapterId) {
|
|
234
|
+
return this.drivers.get(adapterId)?.supportsSegmentedTurns === true;
|
|
210
235
|
}
|
|
211
236
|
async *execute(input) {
|
|
212
237
|
const driver = this.requireEnabledDriver(input.adapterId);
|
|
@@ -237,13 +262,15 @@ export class CodingNsCliAdapterRegistry {
|
|
|
237
262
|
throw new CodingNsRpcError('CODINGNS_CLI_SESSION_MISSING', '外部 Agent 原始会话已删除,无法继续恢复');
|
|
238
263
|
}
|
|
239
264
|
}
|
|
265
|
+
const suspended = this.segmentedTurns.get(input.sessionId);
|
|
266
|
+
const resumingSegmentedTurn = suspended?.adapterId === input.adapterId;
|
|
240
267
|
this.sessions.set(input.sessionId, current);
|
|
241
268
|
this.sessionStore?.upsert(input.sessionId, {
|
|
242
269
|
...current,
|
|
243
270
|
adapterId: input.adapterId,
|
|
244
271
|
...(input.cwd ? { cwd: input.cwd } : {}),
|
|
245
272
|
status: 'active',
|
|
246
|
-
title: input.prompt,
|
|
273
|
+
...(resumingSegmentedTurn ? {} : { title: input.prompt }),
|
|
247
274
|
});
|
|
248
275
|
// Agent Loop 通常已经创建了同名 DSH 原生会话;直接调用 Registry 时才按需补建。
|
|
249
276
|
// 原生服务失败不能阻断外部 Agent,消息仍由现有 llm/stream 链路处理。
|
|
@@ -251,11 +278,31 @@ export class CodingNsCliAdapterRegistry {
|
|
|
251
278
|
await this.nativeSessions?.ensure(input.sessionId, input.cwd);
|
|
252
279
|
}
|
|
253
280
|
catch { /* 可选服务降级 */ }
|
|
254
|
-
|
|
281
|
+
// 每轮都写入稳定的适配器身份。旧日志只有通用 codingns-external 标记,
|
|
282
|
+
// 这条 request/context 是升级后自动迁移时唯一可靠的回填依据。
|
|
283
|
+
try {
|
|
284
|
+
this.nativeSessions?.appendRequestContext?.(input.sessionId, {
|
|
285
|
+
provider: input.adapterId,
|
|
286
|
+
model: input.modelId ?? input.adapterId,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
catch { /* 原生历史写入失败不应阻断外部 Agent */ }
|
|
290
|
+
if (suspended !== undefined && suspended.adapterId !== input.adapterId) {
|
|
291
|
+
this.segmentedTurns.delete(input.sessionId);
|
|
292
|
+
await closeAgentIterator(suspended.iterator);
|
|
293
|
+
}
|
|
294
|
+
const iterator = suspended?.adapterId === input.adapterId
|
|
295
|
+
? (this.segmentedTurns.delete(input.sessionId), suspended.iterator)
|
|
296
|
+
: driver.executeTurn(input)[Symbol.asyncIterator]();
|
|
297
|
+
while (true) {
|
|
298
|
+
const next = await iterator.next();
|
|
299
|
+
if (next.done)
|
|
300
|
+
break;
|
|
301
|
+
const event = next.value;
|
|
255
302
|
if (event.type === 'session-binding') {
|
|
256
303
|
const providerIdentityChanged = event.providerSessionId !== current.providerSessionId;
|
|
257
304
|
const { rawStoreRef: previousRawStoreRef, ...currentWithoutRawStoreRef } = current;
|
|
258
|
-
const
|
|
305
|
+
const nextConfig = {
|
|
259
306
|
...currentWithoutRawStoreRef,
|
|
260
307
|
providerSessionId: event.providerSessionId,
|
|
261
308
|
...(event.rawStoreRef
|
|
@@ -264,19 +311,40 @@ export class CodingNsCliAdapterRegistry {
|
|
|
264
311
|
? { rawStoreRef: previousRawStoreRef }
|
|
265
312
|
: {}),
|
|
266
313
|
};
|
|
267
|
-
this.sessions.set(input.sessionId,
|
|
268
|
-
current =
|
|
314
|
+
this.sessions.set(input.sessionId, nextConfig);
|
|
315
|
+
current = nextConfig;
|
|
269
316
|
this.sessionStore?.upsert(input.sessionId, {
|
|
270
|
-
...
|
|
317
|
+
...nextConfig,
|
|
271
318
|
status: 'active',
|
|
272
319
|
providerState: 'available',
|
|
273
320
|
providerCheckedAt: new Date().toISOString(),
|
|
274
321
|
});
|
|
275
322
|
}
|
|
276
|
-
if (event.type === 'finish')
|
|
323
|
+
if (event.type === 'finish') {
|
|
324
|
+
this.segmentedTurns.delete(input.sessionId);
|
|
277
325
|
this.sessionStore?.upsert(input.sessionId, { ...this.sessions.get(input.sessionId) ?? current, status: event.reason === 'error' ? 'error' : 'idle' });
|
|
326
|
+
}
|
|
327
|
+
// Codex 等驱动已经把同一个 Provider turn 切成了多个段。边界本身
|
|
328
|
+
// 直接交给 Feature,不能再次按工具完成事件切一遍。
|
|
329
|
+
if (event.type === 'step-boundary') {
|
|
330
|
+
await closeAgentIterator(iterator);
|
|
331
|
+
yield event;
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (input.splitToolSteps
|
|
335
|
+
&& driver.supportsSegmentedTurns !== true
|
|
336
|
+
&& event.type === 'tool-event'
|
|
337
|
+
&& (event.status === 'completed' || event.status === 'failed')) {
|
|
338
|
+
// 先保存迭代器再 yield。即使调用方在工具事件后提前关闭流,
|
|
339
|
+
// 下一次 DSH step 仍能从同一个 Provider 进程继续读取正文。
|
|
340
|
+
this.segmentedTurns.set(input.sessionId, { adapterId: input.adapterId, iterator });
|
|
341
|
+
yield event;
|
|
342
|
+
yield { type: 'step-boundary' };
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
278
345
|
yield event;
|
|
279
346
|
}
|
|
347
|
+
this.segmentedTurns.delete(input.sessionId);
|
|
280
348
|
}
|
|
281
349
|
catch (error) {
|
|
282
350
|
this.sessionStore?.upsert(input.sessionId, {
|
|
@@ -359,6 +427,14 @@ export class CodingNsCliAdapterRegistry {
|
|
|
359
427
|
throw new CodingNsRpcError('CODINGNS_CLI_UNSUPPORTED', '当前 Agent 不支持中断');
|
|
360
428
|
await driver.interrupt(sessionId);
|
|
361
429
|
}
|
|
430
|
+
/** 丢弃等待下一步的 Provider 流,避免取消后的旧正文进入新回合。 */
|
|
431
|
+
discardSegmentedTurn(sessionId) {
|
|
432
|
+
const suspended = this.segmentedTurns.get(sessionId);
|
|
433
|
+
if (suspended === undefined)
|
|
434
|
+
return;
|
|
435
|
+
this.segmentedTurns.delete(sessionId);
|
|
436
|
+
void closeAgentIterator(suspended.iterator);
|
|
437
|
+
}
|
|
362
438
|
async dispose() {
|
|
363
439
|
if (this.disposed)
|
|
364
440
|
return;
|
|
@@ -371,6 +447,8 @@ export class CodingNsCliAdapterRegistry {
|
|
|
371
447
|
this.modelFailures.clear();
|
|
372
448
|
this.modelGenerations.clear();
|
|
373
449
|
this.requestedModelCatalogs.clear();
|
|
450
|
+
await Promise.all([...this.segmentedTurns.values()].map(({ iterator }) => closeAgentIterator(iterator)));
|
|
451
|
+
this.segmentedTurns.clear();
|
|
374
452
|
await Promise.all([...this.drivers.values()].map((driver) => driver.dispose?.()));
|
|
375
453
|
}
|
|
376
454
|
async readDetection(driver) {
|
|
@@ -631,6 +709,12 @@ function providerProbeKey(record) {
|
|
|
631
709
|
function delay(milliseconds) {
|
|
632
710
|
return milliseconds <= 0 ? Promise.resolve() : new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
633
711
|
}
|
|
712
|
+
async function closeAgentIterator(iterator) {
|
|
713
|
+
try {
|
|
714
|
+
await iterator.return?.();
|
|
715
|
+
}
|
|
716
|
+
catch { /* 驱动清理失败不能阻断 Registry 释放 */ }
|
|
717
|
+
}
|
|
634
718
|
async function forEachConcurrent(values, concurrency, task) {
|
|
635
719
|
let nextIndex = 0;
|
|
636
720
|
const workerCount = Math.min(concurrency, values.length);
|
|
@@ -652,6 +736,79 @@ function detectionFingerprint(detection) {
|
|
|
652
736
|
function catalogHasModels(catalog) {
|
|
653
737
|
return catalog.groups.some((group) => group.models.length > 0);
|
|
654
738
|
}
|
|
739
|
+
function mergePreferenceRecords(legacy, configured) {
|
|
740
|
+
const merged = {};
|
|
741
|
+
for (const [adapterId, preference] of Object.entries(legacy)) {
|
|
742
|
+
const normalized = normalizePreference(preference);
|
|
743
|
+
if (normalized !== undefined)
|
|
744
|
+
merged[adapterId] = normalized;
|
|
745
|
+
}
|
|
746
|
+
for (const [adapterId, preference] of Object.entries(configured ?? {})) {
|
|
747
|
+
const normalized = normalizePreference(preference);
|
|
748
|
+
if (normalized === undefined)
|
|
749
|
+
continue;
|
|
750
|
+
merged[adapterId] = { ...merged[adapterId], ...normalized };
|
|
751
|
+
}
|
|
752
|
+
return merged;
|
|
753
|
+
}
|
|
754
|
+
function normalizePreference(value) {
|
|
755
|
+
if (value === undefined)
|
|
756
|
+
return undefined;
|
|
757
|
+
const modelId = value.modelId?.trim();
|
|
758
|
+
const effortId = value.effortId?.trim();
|
|
759
|
+
if (modelId === undefined && effortId === undefined)
|
|
760
|
+
return undefined;
|
|
761
|
+
return {
|
|
762
|
+
...(modelId ? { modelId } : {}),
|
|
763
|
+
...(effortId ? { effortId } : {}),
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
function hasMissingPreferences(configured, legacy) {
|
|
767
|
+
for (const [adapterId, legacyPreference] of Object.entries(legacy)) {
|
|
768
|
+
const current = configured?.[adapterId];
|
|
769
|
+
if (legacyPreference.modelId !== undefined && !hasText(current?.modelId))
|
|
770
|
+
return true;
|
|
771
|
+
if (legacyPreference.effortId !== undefined && !hasText(current?.effortId))
|
|
772
|
+
return true;
|
|
773
|
+
}
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
function hasText(value) {
|
|
777
|
+
return value?.trim() !== '' && value !== undefined;
|
|
778
|
+
}
|
|
779
|
+
function preferenceSnapshot(preferences) {
|
|
780
|
+
return Object.fromEntries([...preferences.entries()].map(([adapterId, preference]) => [adapterId, { ...preference }]));
|
|
781
|
+
}
|
|
782
|
+
/** 从 DSH 原生会话快照补齐当前模型提供商,供订阅分流使用。 */
|
|
783
|
+
function mergeDshNativeSelection(config, session) {
|
|
784
|
+
if (config.adapterId !== 'dsh' || config.providerId !== undefined && config.modelId !== undefined)
|
|
785
|
+
return config;
|
|
786
|
+
const root = asRecord(session);
|
|
787
|
+
const rows = asRecord(root?.record)?.rows;
|
|
788
|
+
const selectionRow = asRecord(asRecord(rows)?.modelSelection);
|
|
789
|
+
const selection = asRecord(root?.modelSelection) ?? selectionRow;
|
|
790
|
+
const value = asRecord(selection?.val) ?? selection;
|
|
791
|
+
const lastUsed = asRecord(value?.lastUsed);
|
|
792
|
+
const next = asRecord(value?.next);
|
|
793
|
+
const candidate = lastUsed ?? next;
|
|
794
|
+
if (candidate === null)
|
|
795
|
+
return config;
|
|
796
|
+
const providerId = stringValue(candidate.provider);
|
|
797
|
+
const modelId = stringValue(candidate.model);
|
|
798
|
+
const effortId = stringValue(candidate.reasoningEffort);
|
|
799
|
+
return {
|
|
800
|
+
...config,
|
|
801
|
+
...(config.providerId === undefined && providerId !== undefined ? { providerId } : {}),
|
|
802
|
+
...(config.modelId === undefined && modelId !== undefined ? { modelId } : {}),
|
|
803
|
+
...(config.effortId === undefined && effortId !== undefined ? { effortId } : {}),
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
function asRecord(value) {
|
|
807
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value) ? value : null;
|
|
808
|
+
}
|
|
809
|
+
function stringValue(value) {
|
|
810
|
+
return typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined;
|
|
811
|
+
}
|
|
655
812
|
function unrefTimer(timer) {
|
|
656
813
|
const nodeTimer = timer;
|
|
657
814
|
nodeTimer.unref?.();
|
|
@@ -92,6 +92,13 @@ export function usageChunk(value) {
|
|
|
92
92
|
if (inputTokens === 0 && outputTokens === 0 && cacheReadTokens === undefined && cacheWriteTokens === undefined)
|
|
93
93
|
return null;
|
|
94
94
|
const totalTokens = optionalNumberValue(usage.totalTokens ?? usage.total_tokens ?? usage.totalTokenCount);
|
|
95
|
+
const contextWindow = optionalNumberValue(usage.contextWindow ?? usage.context_window ?? usage.contextLimit ?? usage.context_limit);
|
|
96
|
+
const contextTokens = optionalNumberValue(usage.contextTokens ?? usage.context_tokens);
|
|
97
|
+
const explicitContextUsageRatio = optionalNumberValue(usage.contextUsageRatio ?? usage.context_usage_ratio);
|
|
98
|
+
const contextUsageRatio = explicitContextUsageRatio
|
|
99
|
+
?? (contextWindow !== undefined && contextTokens !== undefined && contextWindow > 0
|
|
100
|
+
? Number(Math.min(1, contextTokens / contextWindow).toFixed(6))
|
|
101
|
+
: undefined);
|
|
95
102
|
const hasCacheBreakdown = explicitUncachedInputTokens !== undefined || cacheReadTokens !== undefined || cacheWriteTokens !== undefined;
|
|
96
103
|
const cachedInputTokens = (cacheReadTokens ?? 0) + (cacheWriteTokens ?? 0);
|
|
97
104
|
const inputExcludesCache = explicitUncachedInputTokens !== undefined || cacheReadInputTokens !== undefined || cacheWriteInputTokens !== undefined;
|
|
@@ -104,6 +111,9 @@ export function usageChunk(value) {
|
|
|
104
111
|
...(cacheWriteTokens === undefined ? {} : { cacheWriteTokens }),
|
|
105
112
|
...(hasCacheBreakdown ? { uncachedInputTokens: inputExcludesCache ? inputTokens : Math.max(0, inputTokens - cachedInputTokens) } : {}),
|
|
106
113
|
...(totalTokens === undefined && !hasCacheBreakdown ? {} : { totalTokens: totalTokens ?? fullInputTokens + outputTokens }),
|
|
114
|
+
...(contextWindow === undefined ? {} : { contextWindow }),
|
|
115
|
+
...(contextTokens === undefined ? {} : { contextTokens }),
|
|
116
|
+
...(contextUsageRatio === undefined ? {} : { contextUsageRatio }),
|
|
107
117
|
...(cacheReadTokens === undefined || fullInputTokens <= 0
|
|
108
118
|
? {}
|
|
109
119
|
: { cacheHitRate: Number((cacheReadTokens / fullInputTokens * 100).toFixed(4)) }),
|
|
@@ -18,6 +18,7 @@ export interface CodingNsCliSessionPatch {
|
|
|
18
18
|
readonly adapterId?: CodingNsCliAdapterId;
|
|
19
19
|
readonly modelId?: string;
|
|
20
20
|
readonly effortId?: string;
|
|
21
|
+
readonly providerId?: string;
|
|
21
22
|
readonly providerSessionId?: string;
|
|
22
23
|
readonly rawStoreRef?: string;
|
|
23
24
|
readonly title?: string;
|
|
@@ -45,6 +46,7 @@ export declare class CodingNsCliSessionStore {
|
|
|
45
46
|
private readonly records;
|
|
46
47
|
private readonly settings;
|
|
47
48
|
private readonly persistence;
|
|
49
|
+
private readonly legacyImportedRecords;
|
|
48
50
|
private writeTail;
|
|
49
51
|
constructor(options?: CodingNsCliSessionStoreOptions);
|
|
50
52
|
/** 将设置变更重新载入内存;非法或不完整记录会被忽略。 */
|
|
@@ -56,6 +58,11 @@ export declare class CodingNsCliSessionStore {
|
|
|
56
58
|
}): CodingNsCliSessionRecord[];
|
|
57
59
|
/** 浏览器会话行只需要这两个字段,Host-only 恢复信息不得跨过 RPC 边界。 */
|
|
58
60
|
adapterBindings(): CodingNsSessionAdapterBinding[];
|
|
61
|
+
/** 启动时把旧 DSH 原生会话中有明确证据的适配器回填到 Host 索引。 */
|
|
62
|
+
migrateLegacySessions(sessions: readonly unknown[]): {
|
|
63
|
+
migrated: number;
|
|
64
|
+
unresolved: number;
|
|
65
|
+
};
|
|
59
66
|
/** 创建或更新记录;返回值是内存中的规范化记录,持久化在后台串行完成。 */
|
|
60
67
|
upsert(sessionId: string, patch: CodingNsCliSessionPatch & CodingNsCliSessionConfig): CodingNsCliSessionRecord;
|
|
61
68
|
archive(sessionId: string): CodingNsCliSessionRecord | undefined;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { inspectLegacySessionAdapter } from './legacy-session-adapter.js';
|
|
2
|
+
import { readLegacyImportedSessionRecords } from './legacy-session-settings.js';
|
|
1
3
|
/**
|
|
2
4
|
* Host-only 的外部 Agent 会话索引。
|
|
3
5
|
*
|
|
@@ -9,10 +11,16 @@ export class CodingNsCliSessionStore {
|
|
|
9
11
|
records = new Map();
|
|
10
12
|
settings;
|
|
11
13
|
persistence;
|
|
14
|
+
legacyImportedRecords;
|
|
12
15
|
writeTail = Promise.resolve();
|
|
13
16
|
constructor(options = {}) {
|
|
14
17
|
this.settings = options.settings;
|
|
15
18
|
this.persistence = options.persistence;
|
|
19
|
+
// DSH 升级时会把旧设置保存为 settings.yaml.imported;先恢复其中的
|
|
20
|
+
// 外部会话索引,再用当前设置覆盖同 ID 记录,保证用户后续修改优先。
|
|
21
|
+
this.legacyImportedRecords = options.settings === undefined ? [] : readLegacyImportedSessionRecords();
|
|
22
|
+
for (const record of this.legacyImportedRecords)
|
|
23
|
+
this.hydrateRecord(record, true);
|
|
16
24
|
for (const record of options.settings?.get().cliSessions ?? [])
|
|
17
25
|
this.hydrateRecord(record, true);
|
|
18
26
|
}
|
|
@@ -21,6 +29,8 @@ export class CodingNsCliSessionStore {
|
|
|
21
29
|
if (records === undefined)
|
|
22
30
|
return;
|
|
23
31
|
this.records.clear();
|
|
32
|
+
for (const record of this.legacyImportedRecords)
|
|
33
|
+
this.hydrateRecord(record, false);
|
|
24
34
|
for (const record of records)
|
|
25
35
|
this.hydrateRecord(record, false);
|
|
26
36
|
}
|
|
@@ -36,11 +46,33 @@ export class CodingNsCliSessionStore {
|
|
|
36
46
|
}
|
|
37
47
|
/** 浏览器会话行只需要这两个字段,Host-only 恢复信息不得跨过 RPC 边界。 */
|
|
38
48
|
adapterBindings() {
|
|
39
|
-
return this.list().map((record) => ({
|
|
49
|
+
return this.list({ includeArchived: true }).map((record) => ({
|
|
40
50
|
sessionId: record.dshSessionId,
|
|
41
51
|
adapterId: record.adapterId,
|
|
42
52
|
}));
|
|
43
53
|
}
|
|
54
|
+
/** 启动时把旧 DSH 原生会话中有明确证据的适配器回填到 Host 索引。 */
|
|
55
|
+
migrateLegacySessions(sessions) {
|
|
56
|
+
let migrated = 0;
|
|
57
|
+
let unresolved = 0;
|
|
58
|
+
for (const session of sessions) {
|
|
59
|
+
const evidence = inspectLegacySessionAdapter(session);
|
|
60
|
+
const existing = evidence === undefined ? undefined : this.records.get(evidence.sessionId);
|
|
61
|
+
if (evidence === undefined || existing !== undefined && existing.adapterId !== 'dsh')
|
|
62
|
+
continue;
|
|
63
|
+
if (evidence.adapterId === undefined) {
|
|
64
|
+
unresolved += 1;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
this.upsert(evidence.sessionId, {
|
|
68
|
+
adapterId: evidence.adapterId,
|
|
69
|
+
...(evidence.cwd === undefined ? {} : { cwd: evidence.cwd }),
|
|
70
|
+
status: existing?.status ?? 'idle',
|
|
71
|
+
});
|
|
72
|
+
migrated += 1;
|
|
73
|
+
}
|
|
74
|
+
return { migrated, unresolved };
|
|
75
|
+
}
|
|
44
76
|
/** 创建或更新记录;返回值是内存中的规范化记录,持久化在后台串行完成。 */
|
|
45
77
|
upsert(sessionId, patch) {
|
|
46
78
|
const now = new Date().toISOString();
|
|
@@ -59,6 +91,7 @@ export class CodingNsCliSessionStore {
|
|
|
59
91
|
adapterId,
|
|
60
92
|
...(patch.modelId?.trim() ? { modelId: patch.modelId.trim() } : base?.modelId ? { modelId: base.modelId } : {}),
|
|
61
93
|
...(patch.effortId?.trim() ? { effortId: patch.effortId.trim() } : base?.effortId ? { effortId: base.effortId } : {}),
|
|
94
|
+
...(patch.providerId?.trim() ? { providerId: patch.providerId.trim() } : base?.providerId ? { providerId: base.providerId } : {}),
|
|
62
95
|
...(providerSessionId ? { providerSessionId } : base?.providerSessionId ? { providerSessionId: base.providerSessionId } : {}),
|
|
63
96
|
...(patch.rawStoreRef?.trim() ? { rawStoreRef: patch.rawStoreRef.trim() } : providerBase?.rawStoreRef ? { rawStoreRef: providerBase.rawStoreRef } : {}),
|
|
64
97
|
...(patch.title?.trim() ? { title: patch.title.trim() } : base?.title ? { title: base.title } : {}),
|
|
@@ -132,6 +165,7 @@ export class CodingNsCliSessionStore {
|
|
|
132
165
|
adapterId: value.adapterId,
|
|
133
166
|
...(stringValue(value.modelId) ? { modelId: stringValue(value.modelId) } : {}),
|
|
134
167
|
...(stringValue(value.effortId) ? { effortId: stringValue(value.effortId) } : {}),
|
|
168
|
+
...(stringValue(value.providerId) ? { providerId: stringValue(value.providerId) } : {}),
|
|
135
169
|
...(stringValue(value.providerSessionId) ? { providerSessionId: stringValue(value.providerSessionId) } : {}),
|
|
136
170
|
...(stringValue(value.rawStoreRef) ? { rawStoreRef: stringValue(value.rawStoreRef) } : {}),
|
|
137
171
|
...(stringValue(value.title) ? { title: stringValue(value.title) } : {}),
|
|
@@ -156,6 +190,10 @@ export class CodingNsCliSessionStore {
|
|
|
156
190
|
await this.persistence.write(snapshot);
|
|
157
191
|
if (this.settings !== undefined)
|
|
158
192
|
await this.settings.update({ cliSessions: snapshot });
|
|
193
|
+
})
|
|
194
|
+
.catch((error) => {
|
|
195
|
+
// 会话索引是辅助缓存;设置服务短暂不可用不能杀死 Host 或模型探测任务。
|
|
196
|
+
console.warn('codingns4dsh: 外部会话索引持久化失败', error);
|
|
159
197
|
});
|
|
160
198
|
}
|
|
161
199
|
}
|
|
@@ -9,6 +9,9 @@ export interface StandardStreamDriverOptions {
|
|
|
9
9
|
readonly spawn?: typeof spawn;
|
|
10
10
|
readonly versionArgs?: readonly string[];
|
|
11
11
|
readonly modelArgs?: readonly string[];
|
|
12
|
+
/** Claude 模型发现的配置目录和网络请求注入点。 */
|
|
13
|
+
readonly claudeConfigDir?: string;
|
|
14
|
+
readonly fetch?: typeof fetch;
|
|
12
15
|
}
|
|
13
16
|
/**
|
|
14
17
|
* 把采用 JSONL/stream-json 的 CLI 统一成 Codingns4DSH 的最小驱动契约。
|
|
@@ -14,12 +14,15 @@ export declare class CodingNsAgentEventNormalizer {
|
|
|
14
14
|
private text;
|
|
15
15
|
private reasoningBoundary;
|
|
16
16
|
private textBoundary;
|
|
17
|
+
private reasoningMessageId;
|
|
18
|
+
private textMessageId;
|
|
17
19
|
private usage;
|
|
18
20
|
push(chunk: CodingNsAgentEvent): readonly CodingNsNormalizedAgentEvent[];
|
|
19
21
|
/** 流未携带 finish 时仍返回最后一次统计,避免正常结束路径丢失 usage。 */
|
|
20
22
|
flush(): readonly CodingNsNormalizedAgentEvent[];
|
|
21
23
|
private appendSnapshot;
|
|
22
24
|
private takeUsage;
|
|
25
|
+
private messageBoundary;
|
|
23
26
|
}
|
|
24
27
|
export {};
|
|
25
28
|
//# sourceMappingURL=stream-normalizer.d.ts.map
|
|
@@ -9,17 +9,21 @@ export class CodingNsAgentEventNormalizer {
|
|
|
9
9
|
text = '';
|
|
10
10
|
reasoningBoundary = false;
|
|
11
11
|
textBoundary = false;
|
|
12
|
+
reasoningMessageId;
|
|
13
|
+
textMessageId;
|
|
12
14
|
usage = null;
|
|
13
15
|
push(chunk) {
|
|
14
16
|
if (chunk.type === 'reasoning-delta') {
|
|
17
|
+
const boundary = this.messageBoundary('reasoning', chunk.messageId);
|
|
15
18
|
this.reasoning = this.reasoningBoundary ? chunk.text : this.reasoning + chunk.text;
|
|
16
19
|
this.reasoningBoundary = false;
|
|
17
|
-
return chunk.text === '' ?
|
|
20
|
+
return chunk.text === '' ? boundary : [...boundary, chunk];
|
|
18
21
|
}
|
|
19
22
|
if (chunk.type === 'text-delta') {
|
|
23
|
+
const boundary = this.messageBoundary('text', chunk.messageId);
|
|
20
24
|
this.text = this.textBoundary ? chunk.text : this.text + chunk.text;
|
|
21
25
|
this.textBoundary = false;
|
|
22
|
-
return chunk.text === '' ?
|
|
26
|
+
return chunk.text === '' ? boundary : [...boundary, chunk];
|
|
23
27
|
}
|
|
24
28
|
if (chunk.type === 'reasoning-snapshot')
|
|
25
29
|
return this.appendSnapshot('reasoning', chunk.text);
|
|
@@ -79,5 +83,21 @@ export class CodingNsAgentEventNormalizer {
|
|
|
79
83
|
this.usage = null;
|
|
80
84
|
return usage;
|
|
81
85
|
}
|
|
86
|
+
messageBoundary(channel, messageId) {
|
|
87
|
+
if (messageId === undefined)
|
|
88
|
+
return [];
|
|
89
|
+
const previous = channel === 'reasoning' ? this.reasoningMessageId : this.textMessageId;
|
|
90
|
+
if (channel === 'reasoning')
|
|
91
|
+
this.reasoningMessageId = messageId;
|
|
92
|
+
else
|
|
93
|
+
this.textMessageId = messageId;
|
|
94
|
+
if (previous === undefined || previous === messageId)
|
|
95
|
+
return [];
|
|
96
|
+
if (channel === 'reasoning')
|
|
97
|
+
this.reasoning = '';
|
|
98
|
+
else
|
|
99
|
+
this.text = '';
|
|
100
|
+
return [{ type: 'message-boundary', channel, messageId }];
|
|
101
|
+
}
|
|
82
102
|
}
|
|
83
103
|
//# sourceMappingURL=stream-normalizer.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AuthDeviceManagementSnapshotDto, HostBindRequest, HostBindResponse, HostBindingsResponse, HostLabelAvailabilityResponse, HostUnbindResponse, LoginByEmailRequest } from '../shared/contracts/auth.js';
|
|
2
|
-
import type { DshDeviceHeartbeatResponse, DshDeviceListResponse, DshDeviceRegistrationRequest, DshDeviceRegistrationResponse, DshRelayTicketRequest, DshRelayTicketResponse } from '../shared/contracts/dsh-device.js';
|
|
2
|
+
import type { DshDeviceHeartbeatResponse, DshDeviceHeartbeatRequest, DshDeviceListResponse, DshDeviceRegistrationRequest, DshDeviceRegistrationResponse, DshRelayTicketRequest, DshRelayTicketResponse } from '../shared/contracts/dsh-device.js';
|
|
3
3
|
import type { RelaySignalingTicketRequest, RelaySignalingTicketResponse } from '../shared/contracts/signaling.js';
|
|
4
4
|
/** 仅 Host 使用的控制面会话响应;refresh token 不进入 shared/client 类型。 */
|
|
5
5
|
export interface LoginByEmailResponse {
|
|
@@ -45,7 +45,7 @@ export interface CodingNsControlApiClient {
|
|
|
45
45
|
createSignalingTicket(accessToken: string, request: RelaySignalingTicketRequest): Promise<RelaySignalingTicketResponse>;
|
|
46
46
|
registerDshDevice(accessToken: string, request: DshDeviceRegistrationRequest): Promise<DshDeviceRegistrationResponse>;
|
|
47
47
|
listDshDevices(accessToken: string): Promise<DshDeviceListResponse>;
|
|
48
|
-
heartbeatDshDevice(accessToken: string, deviceId: string, deviceCredential: string): Promise<DshDeviceHeartbeatResponse>;
|
|
48
|
+
heartbeatDshDevice(accessToken: string, deviceId: string, deviceCredential: string, details?: DshDeviceHeartbeatRequest): Promise<DshDeviceHeartbeatResponse>;
|
|
49
49
|
createDshRelayTicket(accessToken: string, request: DshRelayTicketRequest): Promise<DshRelayTicketResponse>;
|
|
50
50
|
}
|
|
51
51
|
/** 设计文档中的简写名称;保留长名称以明确其 Control API 边界。 */
|
|
@@ -77,7 +77,7 @@ export declare class HttpCodingNsControlApiClient implements CodingNsControlApiC
|
|
|
77
77
|
createSignalingTicket(accessToken: string, request: RelaySignalingTicketRequest): Promise<RelaySignalingTicketResponse>;
|
|
78
78
|
registerDshDevice(accessToken: string, request: DshDeviceRegistrationRequest): Promise<DshDeviceRegistrationResponse>;
|
|
79
79
|
listDshDevices(accessToken: string): Promise<DshDeviceListResponse>;
|
|
80
|
-
heartbeatDshDevice(accessToken: string, deviceId: string, deviceCredential: string): Promise<DshDeviceHeartbeatResponse>;
|
|
80
|
+
heartbeatDshDevice(accessToken: string, deviceId: string, deviceCredential: string, details?: DshDeviceHeartbeatRequest): Promise<DshDeviceHeartbeatResponse>;
|
|
81
81
|
createDshRelayTicket(accessToken: string, request: DshRelayTicketRequest): Promise<DshRelayTicketResponse>;
|
|
82
82
|
private request;
|
|
83
83
|
}
|
|
@@ -74,10 +74,11 @@ export class HttpCodingNsControlApiClient {
|
|
|
74
74
|
listDshDevices(accessToken) {
|
|
75
75
|
return this.request(this.controlBaseUrl, CODINGNS_CONTROL_API_PATHS.dshDevices, { token: accessToken });
|
|
76
76
|
}
|
|
77
|
-
heartbeatDshDevice(accessToken, deviceId, deviceCredential) {
|
|
77
|
+
heartbeatDshDevice(accessToken, deviceId, deviceCredential, details) {
|
|
78
78
|
return this.request(this.controlBaseUrl, `${CODINGNS_CONTROL_API_PATHS.dshDevices}/${encodeURIComponent(deviceId)}/heartbeat`, {
|
|
79
79
|
method: 'POST',
|
|
80
80
|
token: accessToken,
|
|
81
|
+
...(details === undefined ? {} : { body: details }),
|
|
81
82
|
headers: { 'x-dsh-device-credential': deviceCredential },
|
|
82
83
|
});
|
|
83
84
|
}
|
|
@@ -103,7 +103,17 @@ function parseDshCredential(value) {
|
|
|
103
103
|
if (!isRecord(value) || typeof value.deviceId !== 'string' || typeof value.deviceCredential !== 'string' || typeof value.credentialVersion !== 'number' || !Number.isInteger(value.credentialVersion) || value.credentialVersion < 1 || typeof value.dtlsFingerprint !== 'string' || (typeof value.tunnelDomain !== 'string' && value.tunnelDomain !== null) || typeof value.displayName !== 'string' || typeof value.savedAt !== 'string') {
|
|
104
104
|
throw new Error('DSH device credential 文件格式无效');
|
|
105
105
|
}
|
|
106
|
-
return {
|
|
106
|
+
return {
|
|
107
|
+
deviceId: value.deviceId,
|
|
108
|
+
deviceCredential: value.deviceCredential,
|
|
109
|
+
credentialVersion: value.credentialVersion,
|
|
110
|
+
dtlsFingerprint: value.dtlsFingerprint,
|
|
111
|
+
tunnelDomain: value.tunnelDomain,
|
|
112
|
+
displayName: value.displayName,
|
|
113
|
+
...(typeof value.dshVersion === 'string' && value.dshVersion.trim() ? { dshVersion: value.dshVersion } : {}),
|
|
114
|
+
...(typeof value.computerName === 'string' && value.computerName.trim() ? { computerName: value.computerName } : {}),
|
|
115
|
+
savedAt: value.savedAt,
|
|
116
|
+
};
|
|
107
117
|
}
|
|
108
118
|
function isRecord(value) {
|
|
109
119
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
@@ -10,12 +10,16 @@ export interface DshHostDeviceRuntimeOptions {
|
|
|
10
10
|
readonly accessToken: string;
|
|
11
11
|
/** 认证续期后动态读取最新 access token;未提供时沿用 accessToken。 */
|
|
12
12
|
readonly accessTokenProvider?: () => string | null;
|
|
13
|
+
/** 对控制面请求统一处理 401 续期;未提供时直接使用当前 token。 */
|
|
14
|
+
readonly withAccessToken?: <T>(operation: (accessToken: string) => Promise<T>) => Promise<T>;
|
|
13
15
|
readonly credentialStore?: DshDeviceCredentialStore;
|
|
14
16
|
readonly dtlsStore?: HostDtlsIdentityStore;
|
|
15
17
|
readonly displayName?: string;
|
|
16
18
|
readonly protocolVersion?: string;
|
|
17
19
|
/** 当前 DSH 宿主的真实版本,用于 Relay Transport 握手。 */
|
|
18
20
|
readonly dshVersion?: string;
|
|
21
|
+
/** 覆盖自动获取的计算机名,主要用于测试和受控运行环境。 */
|
|
22
|
+
readonly computerName?: string;
|
|
19
23
|
readonly capabilities?: readonly string[];
|
|
20
24
|
readonly resources?: Pick<FeatureResourceScope, 'add'>;
|
|
21
25
|
readonly signalingSocketFactory?: Parameters<typeof startHostRelayRuntime>[0]['signalingSocketFactory'];
|