@jingyi0605/codingns4dsh 0.2.1-beta.10 → 0.2.1-beta.12
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 +7 -5
- package/README.md +12 -6
- package/data/build/dist/bootstrap/dsh-connection-adapter.d.ts +1 -1
- package/data/build/dist/bootstrap/index.d.ts +1 -1
- package/data/build/dist/client/bundle.js +9713 -7350
- package/data/build/dist/client/bundle.js.map +1 -1
- package/data/build/dist/client/cli-slots.d.ts +13 -3
- package/data/build/dist/client/cli-slots.d.ts.map +1 -1
- package/data/build/dist/client/cli-slots.js +93 -18
- package/data/build/dist/client/cli-slots.js.map +1 -1
- package/data/build/dist/client/client.assistant-configuration-view.js +4 -3
- package/data/build/dist/client/client.assistant-configuration-view.js.map +1 -1
- package/data/build/dist/client/client.moss-voice-output.js +415 -0
- package/data/build/dist/client/client.moss-voice-output.js.map +1 -0
- package/data/build/dist/client/client.native-workspace-store.js +4 -4
- package/data/build/dist/client/client.native-workspace-store.js.map +1 -1
- package/data/build/dist/client/client.primitives-adapter.js.map +1 -1
- package/data/build/dist/client/client.react-dom.js +0 -404
- package/data/build/dist/client/client.react-dom.js.map +1 -1
- package/data/build/dist/client/client.session-translation.js +105 -2
- package/data/build/dist/client/client.session-translation.js.map +1 -1
- package/data/build/dist/client/client.transport.js +103 -11
- package/data/build/dist/client/client.transport.js.map +1 -1
- package/data/build/dist/client/conversation-translation-settings.d.ts +10 -0
- package/data/build/dist/client/conversation-translation-settings.d.ts.map +1 -0
- package/data/build/dist/client/conversation-translation-settings.js +52 -0
- package/data/build/dist/client/conversation-translation-settings.js.map +1 -0
- package/data/build/dist/client/desktop-assistant.js +569 -450
- package/data/build/dist/client/features/cli-adapters.d.ts.map +1 -1
- package/data/build/dist/client/features/cli-adapters.js +3 -1
- package/data/build/dist/client/features/cli-adapters.js.map +1 -1
- package/data/build/dist/client/features/session-translation.d.ts.map +1 -1
- package/data/build/dist/client/features/session-translation.js +49 -48
- package/data/build/dist/client/features/session-translation.js.map +1 -1
- package/data/build/dist/client/locales/panels.d.ts.map +1 -1
- package/data/build/dist/client/locales/panels.js +103 -11
- package/data/build/dist/client/locales/panels.js.map +1 -1
- package/data/build/dist/client/native-model-translation-menu.d.ts +6 -0
- package/data/build/dist/client/native-model-translation-menu.d.ts.map +1 -0
- package/data/build/dist/client/native-model-translation-menu.js +57 -0
- package/data/build/dist/client/native-model-translation-menu.js.map +1 -0
- package/data/build/dist/client/native-translation-default.d.ts +6 -0
- package/data/build/dist/client/native-translation-default.d.ts.map +1 -0
- package/data/build/dist/client/native-translation-default.js +30 -0
- package/data/build/dist/client/native-translation-default.js.map +1 -0
- package/data/build/dist/client/session-translation-chat.d.ts +23 -2
- package/data/build/dist/client/session-translation-chat.d.ts.map +1 -1
- package/data/build/dist/client/session-translation-chat.js +238 -72
- package/data/build/dist/client/session-translation-chat.js.map +1 -1
- package/data/build/dist/client/session-translation-interactions.d.ts +31 -0
- package/data/build/dist/client/session-translation-interactions.d.ts.map +1 -0
- package/data/build/dist/client/session-translation-interactions.js +158 -0
- package/data/build/dist/client/session-translation-interactions.js.map +1 -0
- package/data/build/dist/client/session-translation-model-pool.d.ts +16 -0
- package/data/build/dist/client/session-translation-model-pool.d.ts.map +1 -0
- package/data/build/dist/client/session-translation-model-pool.js +246 -0
- package/data/build/dist/client/session-translation-model-pool.js.map +1 -0
- package/data/build/dist/client/session-translation-pending-dom.d.ts +8 -0
- package/data/build/dist/client/session-translation-pending-dom.d.ts.map +1 -0
- package/data/build/dist/client/session-translation-pending-dom.js +58 -0
- package/data/build/dist/client/session-translation-pending-dom.js.map +1 -0
- package/data/build/dist/client/session-translation-retry.d.ts +16 -0
- package/data/build/dist/client/session-translation-retry.d.ts.map +1 -0
- package/data/build/dist/client/session-translation-retry.js +66 -0
- package/data/build/dist/client/session-translation-retry.js.map +1 -0
- package/data/build/dist/client/session-translation-rules.d.ts +13 -0
- package/data/build/dist/client/session-translation-rules.d.ts.map +1 -0
- package/data/build/dist/client/session-translation-rules.js +58 -0
- package/data/build/dist/client/session-translation-rules.js.map +1 -0
- package/data/build/dist/client/style.css +276 -276
- package/data/build/dist/dsh-capabilities/client/interaction-presentation-adapter.d.ts +30 -0
- package/data/build/dist/dsh-capabilities/client/interaction-presentation-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/client/interaction-presentation-adapter.js +93 -0
- package/data/build/dist/dsh-capabilities/client/interaction-presentation-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/client/interaction-text-dom.d.ts +12 -0
- package/data/build/dist/dsh-capabilities/client/interaction-text-dom.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/client/interaction-text-dom.js +181 -0
- package/data/build/dist/dsh-capabilities/client/interaction-text-dom.js.map +1 -0
- package/data/build/dist/dsh-capabilities/client/message-presentation-adapter.d.ts +19 -0
- package/data/build/dist/dsh-capabilities/client/message-presentation-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/client/message-presentation-adapter.js +39 -0
- package/data/build/dist/dsh-capabilities/client/message-presentation-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts +1 -0
- package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/client/primitives-adapter.js +1 -0
- package/data/build/dist/dsh-capabilities/client/primitives-adapter.js.map +1 -1
- package/data/build/dist/dsh-capabilities/client/question-history-adapter.d.ts +20 -0
- package/data/build/dist/dsh-capabilities/client/question-history-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/client/question-history-adapter.js +65 -0
- package/data/build/dist/dsh-capabilities/client/question-history-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/client/slot-presentation-mirror.d.ts +32 -0
- package/data/build/dist/dsh-capabilities/client/slot-presentation-mirror.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/client/slot-presentation-mirror.js +90 -0
- package/data/build/dist/dsh-capabilities/client/slot-presentation-mirror.js.map +1 -0
- package/data/build/dist/dsh-capabilities/host/connection-peer-adapter.d.ts +10 -0
- package/data/build/dist/dsh-capabilities/host/connection-peer-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/host/connection-peer-adapter.js +34 -0
- package/data/build/dist/dsh-capabilities/host/connection-peer-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/host/native-dispatch-adapter.d.ts +21 -0
- package/data/build/dist/dsh-capabilities/host/native-dispatch-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/host/native-dispatch-adapter.js +11 -0
- package/data/build/dist/dsh-capabilities/host/native-dispatch-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/host/session-activation-adapter.d.ts +17 -0
- package/data/build/dist/dsh-capabilities/host/session-activation-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/host/session-activation-adapter.js +37 -0
- package/data/build/dist/dsh-capabilities/host/session-activation-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.d.ts +17 -0
- package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.js +45 -0
- package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/host/session-prompt-adapter.d.ts +28 -0
- package/data/build/dist/dsh-capabilities/host/session-prompt-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/host/session-prompt-adapter.js +31 -0
- package/data/build/dist/dsh-capabilities/host/session-prompt-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/matrix.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/matrix.js +12 -3
- package/data/build/dist/dsh-capabilities/matrix.js.map +1 -1
- package/data/build/dist/dsh-capabilities/routes.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/routes.js +26 -3
- package/data/build/dist/dsh-capabilities/routes.js.map +1 -1
- package/data/build/dist/dsh-capabilities/types.d.ts +1 -1
- package/data/build/dist/dsh-capabilities/types.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/types.js.map +1 -1
- package/data/build/dist/host/cli-adapters/antigravity-driver.js +1 -1
- package/data/build/dist/host/cli-adapters/antigravity-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/attachment-utils.d.ts +4 -3
- package/data/build/dist/host/cli-adapters/attachment-utils.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/attachment-utils.js +9 -8
- package/data/build/dist/host/cli-adapters/attachment-utils.js.map +1 -1
- package/data/build/dist/host/cli-adapters/claude-driver.js +1 -1
- package/data/build/dist/host/cli-adapters/claude-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/command-code-driver.js +1 -1
- package/data/build/dist/host/cli-adapters/command-code-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/driver.d.ts +2 -0
- package/data/build/dist/host/cli-adapters/driver.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +2 -0
- package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/dsh-message-projector.js +28 -11
- package/data/build/dist/host/cli-adapters/dsh-message-projector.js.map +1 -1
- package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/feature.js +369 -70
- package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
- package/data/build/dist/host/cli-adapters/gemini-driver.js +1 -1
- package/data/build/dist/host/cli-adapters/gemini-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/grok-driver.d.ts +1 -0
- package/data/build/dist/host/cli-adapters/grok-driver.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/grok-driver.js +128 -40
- package/data/build/dist/host/cli-adapters/grok-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/kimi-driver.js +2 -2
- package/data/build/dist/host/cli-adapters/kimi-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/mcode-driver.js +1 -1
- package/data/build/dist/host/cli-adapters/mcode-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/native-subagent-dispatch.js +2 -2
- package/data/build/dist/host/cli-adapters/native-subagent-dispatch.js.map +1 -1
- package/data/build/dist/host/cli-adapters/native-team-subagent.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/native-team-subagent.js +2 -1
- package/data/build/dist/host/cli-adapters/native-team-subagent.js.map +1 -1
- package/data/build/dist/host/cli-adapters/pi-driver.js +1 -1
- package/data/build/dist/host/cli-adapters/pi-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/registry.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/registry.js +25 -16
- package/data/build/dist/host/cli-adapters/registry.js.map +1 -1
- package/data/build/dist/host/cli-adapters/zcode-driver.js +1 -1
- package/data/build/dist/host/cli-adapters/zcode-driver.js.map +1 -1
- package/data/build/dist/host/features/global-voice-rpc.d.ts.map +1 -1
- package/data/build/dist/host/features/global-voice-rpc.js +2 -3
- package/data/build/dist/host/features/global-voice-rpc.js.map +1 -1
- package/data/build/dist/host/features/interaction-translation.d.ts +9 -0
- package/data/build/dist/host/features/interaction-translation.d.ts.map +1 -0
- package/data/build/dist/host/features/interaction-translation.js +168 -0
- package/data/build/dist/host/features/interaction-translation.js.map +1 -0
- package/data/build/dist/host/features/peer-host.js +6 -6
- package/data/build/dist/host/features/peer-host.js.map +1 -1
- package/data/build/dist/host/features/session-prompt-translation.d.ts +10 -0
- package/data/build/dist/host/features/session-prompt-translation.d.ts.map +1 -0
- package/data/build/dist/host/features/session-prompt-translation.js +197 -0
- package/data/build/dist/host/features/session-prompt-translation.js.map +1 -0
- package/data/build/dist/host/features/session-translation-protection.d.ts +16 -0
- package/data/build/dist/host/features/session-translation-protection.d.ts.map +1 -0
- package/data/build/dist/host/features/session-translation-protection.js +183 -0
- package/data/build/dist/host/features/session-translation-protection.js.map +1 -0
- package/data/build/dist/host/features/session-translation-recovery.d.ts +20 -0
- package/data/build/dist/host/features/session-translation-recovery.d.ts.map +1 -0
- package/data/build/dist/host/features/session-translation-recovery.js +122 -0
- package/data/build/dist/host/features/session-translation-recovery.js.map +1 -0
- package/data/build/dist/host/features/session-translation-runtime.d.ts +16 -0
- package/data/build/dist/host/features/session-translation-runtime.d.ts.map +1 -0
- package/data/build/dist/host/features/session-translation-runtime.js +85 -0
- package/data/build/dist/host/features/session-translation-runtime.js.map +1 -0
- package/data/build/dist/host/features/session-translation-service.d.ts +14 -4
- package/data/build/dist/host/features/session-translation-service.d.ts.map +1 -1
- package/data/build/dist/host/features/session-translation-service.js +217 -211
- package/data/build/dist/host/features/session-translation-service.js.map +1 -1
- package/data/build/dist/host/features/session-translation.d.ts.map +1 -1
- package/data/build/dist/host/features/session-translation.js +5 -2
- package/data/build/dist/host/features/session-translation.js.map +1 -1
- package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.d.ts +2 -2
- package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.d.ts.map +1 -1
- package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.js +10 -9
- package/data/build/dist/host/modules/peer-host/peer-host-native-dispatch.js.map +1 -1
- package/data/build/dist/host/modules/peer-host/peer-host-native-streams.d.ts +3 -3
- package/data/build/dist/host/modules/peer-host/peer-host-native-streams.d.ts.map +1 -1
- package/data/build/dist/host/modules/peer-host/peer-host-native-streams.js +26 -14
- package/data/build/dist/host/modules/peer-host/peer-host-native-streams.js.map +1 -1
- package/data/build/dist/host/native-session-bridge.d.ts +2 -1
- package/data/build/dist/host/native-session-bridge.d.ts.map +1 -1
- package/data/build/dist/host/native-session-bridge.js +7 -15
- package/data/build/dist/host/native-session-bridge.js.map +1 -1
- package/data/build/dist/host/rpc.d.ts.map +1 -1
- package/data/build/dist/host/rpc.js +14 -8
- package/data/build/dist/host/rpc.js.map +1 -1
- package/data/build/dist/host/settings.d.ts.map +1 -1
- package/data/build/dist/host/settings.js +10 -2
- package/data/build/dist/host/settings.js.map +1 -1
- package/data/build/dist/shared/attachment-prompts.d.ts +11 -0
- package/data/build/dist/shared/attachment-prompts.d.ts.map +1 -0
- package/data/build/dist/shared/attachment-prompts.js +17 -0
- package/data/build/dist/shared/attachment-prompts.js.map +1 -0
- package/data/build/dist/shared/contracts/cli-adapter.d.ts +8 -1
- package/data/build/dist/shared/contracts/cli-adapter.d.ts.map +1 -1
- package/data/build/dist/shared/contracts/errors.d.ts +2 -2
- package/data/build/dist/shared/contracts/interaction-presentation.d.ts +32 -0
- package/data/build/dist/shared/contracts/interaction-presentation.d.ts.map +1 -0
- package/data/build/dist/shared/contracts/interaction-presentation.js +2 -0
- package/data/build/dist/shared/contracts/interaction-presentation.js.map +1 -0
- package/data/build/dist/shared/contracts/interaction-translation.d.ts +53 -0
- package/data/build/dist/shared/contracts/interaction-translation.d.ts.map +1 -0
- package/data/build/dist/shared/contracts/interaction-translation.js +44 -0
- package/data/build/dist/shared/contracts/interaction-translation.js.map +1 -0
- package/data/build/dist/shared/contracts/session-translation.d.ts +75 -7
- package/data/build/dist/shared/contracts/session-translation.d.ts.map +1 -1
- package/data/build/dist/shared/contracts/session-translation.js +132 -2
- package/data/build/dist/shared/contracts/session-translation.js.map +1 -1
- package/data/build/dist/shared/contracts/version.d.ts +4 -4
- package/data/build/dist/shared/contracts/version.js +3 -3
- package/data/build/dist/shared/index.d.ts +1 -1
- package/data/build/dist/shared/index.d.ts.map +1 -1
- package/data/build/dist/shared/index.js +1 -1
- package/data/build/dist/shared/index.js.map +1 -1
- package/data/build/dist/shared/translation-indicator.d.ts +26 -0
- package/data/build/dist/shared/translation-indicator.d.ts.map +1 -0
- package/data/build/dist/shared/translation-indicator.js +29 -0
- package/data/build/dist/shared/translation-indicator.js.map +1 -0
- package/package.json +35 -34
- package/profile/README.md +2 -2
- package/profile/package.json +3 -3
- package/profile/version.json +3 -3
- package/version.json +3 -3
|
@@ -31,7 +31,14 @@ import { containsDelegationCarrier, delegationAdapterIds, rewriteDelegationMessa
|
|
|
31
31
|
import { clearDelegationAuthorization, setDelegationAuthorization } from './delegation-authorization.js';
|
|
32
32
|
import { debugInfo } from '../../shared/debug.js';
|
|
33
33
|
import { hasLegacySessionAdapterHint } from './legacy-session-adapter.js';
|
|
34
|
-
import {} from '../../shared/contracts/session-translation.js';
|
|
34
|
+
import { DSH_NATIVE_SESSION_ADAPTER_ID, formatSessionTranslationOutput, readSessionTranslationMetrics, } from '../../shared/contracts/session-translation.js';
|
|
35
|
+
import { createInteractionTranslation } from '../features/interaction-translation.js';
|
|
36
|
+
import { createSessionTranslationRecovery, SessionTranslationCancelled } from '../features/session-translation-recovery.js';
|
|
37
|
+
import { ASSISTANT_AGENT_PREFIX } from '../../dsh-capabilities/host/assistant-agent-adapter.js';
|
|
38
|
+
import { createDshCapabilityRegistry } from '../../dsh-capabilities/routes.js';
|
|
39
|
+
import { attachmentFileNotice } from '../../shared/attachment-prompts.js';
|
|
40
|
+
import { sessionPromptScope } from '../../dsh-capabilities/host/session-prompt-adapter.js';
|
|
41
|
+
import { createSessionPromptTranslation } from '../features/session-prompt-translation.js';
|
|
35
42
|
export function createCliAdaptersFeature(options = {}) {
|
|
36
43
|
return {
|
|
37
44
|
descriptor: {
|
|
@@ -40,8 +47,10 @@ export function createCliAdaptersFeature(options = {}) {
|
|
|
40
47
|
enabledByDefault: true,
|
|
41
48
|
dependencies: [],
|
|
42
49
|
runtime: 'host',
|
|
50
|
+
requires: [{ capability: 'session.external-model-selection', required: false, fallback: 'degrade' }],
|
|
43
51
|
},
|
|
44
52
|
async start(context) {
|
|
53
|
+
const lifetime = new AbortController();
|
|
45
54
|
// 用量查询超时对所有适配器统一生效:同一个 timeoutMs 下发给全部网络读取器,
|
|
46
55
|
// 设置变更时整体重建,避免旧超时继续生效。
|
|
47
56
|
const buildSubscriptions = (settings) => {
|
|
@@ -91,6 +100,18 @@ export function createCliAdaptersFeature(options = {}) {
|
|
|
91
100
|
virtualProviders?.setProviders(registry.enabledAdapterIds());
|
|
92
101
|
if (virtualProviders !== undefined)
|
|
93
102
|
context.resources.add(() => virtualProviders.dispose());
|
|
103
|
+
if (context.services.dshContext !== undefined && context.services.dshVersion !== undefined) {
|
|
104
|
+
const selection = createDshCapabilityRegistry(context.services.dshVersion, 'host', context.services.dshContext)
|
|
105
|
+
.getProfile(context.services.dshContext).capabilities.get('session.external-model-selection')
|
|
106
|
+
?.value;
|
|
107
|
+
if (selection !== undefined)
|
|
108
|
+
context.resources.add(selection.install((sessionId) => {
|
|
109
|
+
const config = registry.getSession(sessionId);
|
|
110
|
+
if (config.adapterId === 'dsh' || !registry.isEnabled(config.adapterId))
|
|
111
|
+
return undefined;
|
|
112
|
+
return { provider: config.adapterId, model: config.modelId?.trim() || 'provider-default' };
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
94
115
|
registry.warmCatalog();
|
|
95
116
|
// 外部适配器没有经过 DSH 原生 Agent Loop,必须把同一套运行状态投影给
|
|
96
117
|
// subagentCatalog。这里集中去重,避免 llm/stream、原生 session/event 和
|
|
@@ -130,8 +151,27 @@ export function createCliAdaptersFeature(options = {}) {
|
|
|
130
151
|
});
|
|
131
152
|
context.resources.add(disposeNativeEvents);
|
|
132
153
|
}
|
|
133
|
-
|
|
134
|
-
context.resources.add(
|
|
154
|
+
const translationRecovery = createSessionTranslationRecovery(translation, sessionId => registry.getSession(sessionId));
|
|
155
|
+
context.resources.add(() => translationRecovery.dispose());
|
|
156
|
+
const promptTranslation = createSessionPromptTranslation(translation, sessionId => {
|
|
157
|
+
if (!sessionId || isAssistantSession(sessionId) || readNativeSessionHeader(nativeSessions, sessionId)?.origin === 'subagent')
|
|
158
|
+
return undefined;
|
|
159
|
+
const config = registry.getSession(sessionId);
|
|
160
|
+
return (config.translationEnabled ?? (config.adapterId === 'dsh' && translation?.nativeEnabled === true)) ? config.adapterId : undefined;
|
|
161
|
+
});
|
|
162
|
+
context.resources.add(() => promptTranslation.dispose());
|
|
163
|
+
if (context.services.dshContext !== undefined && context.services.dshVersion !== undefined) {
|
|
164
|
+
const adapter = createDshCapabilityRegistry(context.services.dshVersion, 'host', context.services.dshContext)
|
|
165
|
+
.getProfile(context.services.dshContext).capabilities.get('session.prompt-assembly')?.value;
|
|
166
|
+
if (adapter !== undefined)
|
|
167
|
+
context.resources.add(adapter.install((assembly, scope) => promptTranslation.translateAssembly(assembly, scope)));
|
|
168
|
+
}
|
|
169
|
+
registerDelegationAgentHooks(context.services.dshContext, registry, context.resources, publishExternalStatus, translation, translationRecovery, promptTranslation, nativeSessions);
|
|
170
|
+
const interactionTranslation = createInteractionTranslation(translation, sessionId => registry.getSession(sessionId));
|
|
171
|
+
context.resources.add(() => interactionTranslation.dispose());
|
|
172
|
+
context.resources.add(context.services.rpc.register('cli', (action, payload, rpcContext) => {
|
|
173
|
+
const rpcSignal = asRecord(rpcContext)?.signal;
|
|
174
|
+
const signal = isAbortSignal(rpcSignal) ? rpcSignal : undefined;
|
|
135
175
|
switch (action) {
|
|
136
176
|
case 'catalog': return registry.catalog();
|
|
137
177
|
case 'catalog/refresh': return registry.refreshCatalog(asRecord(payload)?.adapterId === undefined ? undefined : readAdapterId(payload)).then((catalog) => {
|
|
@@ -143,6 +183,10 @@ export function createCliAdaptersFeature(options = {}) {
|
|
|
143
183
|
return adapterId === 'dsh' ? readDshModelCatalog(context.services.dshContext) : registry.models(adapterId);
|
|
144
184
|
}
|
|
145
185
|
case 'translation/models': return context.services.sessionTranslation?.catalog() ?? { models: [], default: null, errors: ['翻译模型目录不可用'] };
|
|
186
|
+
case 'translation/pending': return translationRecovery.pending(payload);
|
|
187
|
+
case 'translation/resolve': return translationRecovery.resolve(payload);
|
|
188
|
+
case 'translation/retry-output': return translationRecovery.retryOutput(payload, signal);
|
|
189
|
+
case 'translation/fields': return interactionTranslation.translate(payload, signal);
|
|
146
190
|
case 'skills': {
|
|
147
191
|
const request = readSkillsRequest(payload);
|
|
148
192
|
const cwd = resolveSessionCwd(context.services.nativeSessions, request.sessionId, null);
|
|
@@ -160,15 +204,26 @@ export function createCliAdaptersFeature(options = {}) {
|
|
|
160
204
|
}
|
|
161
205
|
return registry.getSession(sessionId);
|
|
162
206
|
}
|
|
163
|
-
case 'session/set':
|
|
207
|
+
case 'session/set': {
|
|
208
|
+
const sessionId = readSessionId(payload);
|
|
209
|
+
const previous = registry.getSession(sessionId);
|
|
210
|
+
const config = registry.setSession(sessionId, readSessionConfig(payload));
|
|
211
|
+
if (config.translationEnabled === false || previous.adapterId !== config.adapterId)
|
|
212
|
+
translationRecovery.cancelSession(sessionId);
|
|
213
|
+
return config;
|
|
214
|
+
}
|
|
164
215
|
case 'session/list': return registry.listSessions(readSessionListOptions(payload));
|
|
165
216
|
case 'session/adapter-map':
|
|
166
217
|
// 列表查询只返回持久化索引,不能触发会话加载或历史解析。
|
|
167
218
|
return sessionStore.adapterBindings();
|
|
168
219
|
case 'session/archive': return registry.archiveSession(readSessionId(payload));
|
|
169
|
-
case 'session/steer': return translateSteerPrompt(
|
|
170
|
-
case 'session/follow-up': return translateSteerPrompt(
|
|
171
|
-
case 'session/interrupt':
|
|
220
|
+
case 'session/steer': return translateSteerPrompt(translationRecovery, registry, readSessionId(payload), readPrompt(payload), false, signal);
|
|
221
|
+
case 'session/follow-up': return translateSteerPrompt(translationRecovery, registry, readSessionId(payload), readPrompt(payload), true, signal);
|
|
222
|
+
case 'session/interrupt': {
|
|
223
|
+
const sessionId = readSessionId(payload);
|
|
224
|
+
translationRecovery.cancelSession(sessionId);
|
|
225
|
+
return registry.interrupt(sessionId);
|
|
226
|
+
}
|
|
172
227
|
case 'team/status': return context.services.nativeTeam?.diagnostic() ?? registry.teamDiagnostic();
|
|
173
228
|
case 'team/members': return requireTeam(context).invoke('members', payload);
|
|
174
229
|
case 'team/tasks': return requireTeam(context).invoke('tasks', payload);
|
|
@@ -259,6 +314,7 @@ export function createCliAdaptersFeature(options = {}) {
|
|
|
259
314
|
virtualProviders?.setProviders(registry.enabledAdapterIds());
|
|
260
315
|
registry.syncPreferences(next.agentAdapterPreferences);
|
|
261
316
|
sessionStore.sync(next.cliSessions);
|
|
317
|
+
translationRecovery.cancelDisabled(next.sessionTranslation?.nativeEnabled === true, next.sessionTranslation?.inputEnabled !== false);
|
|
262
318
|
const nextSubscriptionSettings = JSON.stringify(next.subscriptionUsage ?? null);
|
|
263
319
|
if (nextSubscriptionSettings !== subscriptionSettings) {
|
|
264
320
|
subscriptionSettings = nextSubscriptionSettings;
|
|
@@ -344,6 +400,18 @@ export function createCliAdaptersFeature(options = {}) {
|
|
|
344
400
|
if (sessionId !== '' && (selection.modelId !== undefined || selection.effortId !== undefined)) {
|
|
345
401
|
registry.setSession(sessionId, { adapterId: 'dsh', ...selection });
|
|
346
402
|
}
|
|
403
|
+
// Native-session output translation wraps only DSH's own Provider stream:
|
|
404
|
+
// preserve text/reasoning and attach the translation record; the client renders it.
|
|
405
|
+
if (!isSessionTranslationLlmRequest(value)
|
|
406
|
+
&& translation !== undefined
|
|
407
|
+
&& translation.enabled
|
|
408
|
+
&& (config.translationEnabled ?? translation.nativeEnabled === true)
|
|
409
|
+
&& sessionId !== ''
|
|
410
|
+
&& !isAssistantSession(sessionId)
|
|
411
|
+
&& readNativeSessionHeader(nativeSessions, sessionId)?.origin !== 'subagent') {
|
|
412
|
+
yield* guardDshNativeStream(() => translateNativeStream(next(), translation, translation.bilingual === true, isAbortSignal(value?.signal) ? value.signal : undefined));
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
347
415
|
yield* guardDshNativeStream(next);
|
|
348
416
|
return;
|
|
349
417
|
}
|
|
@@ -351,19 +419,24 @@ export function createCliAdaptersFeature(options = {}) {
|
|
|
351
419
|
const turnInput = extractTurnInput(messages, context.services.dshContext);
|
|
352
420
|
const turnOptions = readCliTurnOptions(value);
|
|
353
421
|
const runtimeEnv = readCliRuntimeEnv(value);
|
|
354
|
-
const requestSignal = isAbortSignal(value?.signal)
|
|
422
|
+
const requestSignal = isAbortSignal(value?.signal)
|
|
423
|
+
? AbortSignal.any([value.signal, lifetime.signal])
|
|
424
|
+
: lifetime.signal;
|
|
425
|
+
const translationLanguage = translation?.enabled && translation.inputEnabled !== false && config.translationEnabled === true ? readInputTargetLanguage(translation) : undefined;
|
|
355
426
|
let translatedPrompt = turnInput.translationPrompt;
|
|
356
|
-
if (turnInput.translatePrompt &&
|
|
427
|
+
if (turnInput.translatePrompt && turnInput.translationPrompt.trim() !== '' && translationLanguage !== undefined) {
|
|
357
428
|
try {
|
|
358
|
-
translatedPrompt = await
|
|
429
|
+
translatedPrompt = (await translationRecovery.translateInput(sessionId, config.adapterId, turnInput.translationPrompt, requestSignal)).translated;
|
|
359
430
|
}
|
|
360
|
-
catch {
|
|
361
|
-
|
|
362
|
-
|
|
431
|
+
catch (error) {
|
|
432
|
+
if (!(error instanceof SessionTranslationCancelled) && !requestSignal?.aborted)
|
|
433
|
+
throw error;
|
|
434
|
+
yield { type: 'finish', reason: { kind: 'stop' } };
|
|
435
|
+
return;
|
|
363
436
|
}
|
|
364
437
|
}
|
|
365
438
|
const prompt = turnInput.translatePrompt
|
|
366
|
-
? [translatedPrompt, turnInput.untranslatedPrompt].filter((part) => part.trim() !== '').join('\n\n')
|
|
439
|
+
? [translatedPrompt, translationLanguage === undefined ? turnInput.untranslatedPrompt : attachmentNotices(turnInput.attachments, translationLanguage)].filter((part) => part.trim() !== '').join('\n\n')
|
|
367
440
|
: turnInput.prompt;
|
|
368
441
|
// 权限状态必须与 DSH 会话当前生效值同源。驱动不能自行假设“完全权限”,
|
|
369
442
|
// 也不能把缺省当成“已确认无限制”:解析失败时留空,由驱动沿用保守默认。
|
|
@@ -376,6 +449,7 @@ export function createCliAdaptersFeature(options = {}) {
|
|
|
376
449
|
sessionId,
|
|
377
450
|
messages: turnInput.messages,
|
|
378
451
|
prompt,
|
|
452
|
+
...(translationLanguage === undefined ? {} : { translationLanguage }),
|
|
379
453
|
...(turnInput.attachments.length === 0 ? {} : { attachments: turnInput.attachments }),
|
|
380
454
|
...(permission === undefined ? {} : { permission }),
|
|
381
455
|
...(turnOptions.plan === true ? { plan: true } : {}),
|
|
@@ -472,6 +546,8 @@ export function createCliAdaptersFeature(options = {}) {
|
|
|
472
546
|
// DSH 先停用设置上下文再执行异步资源清理时,旧的写队列不能继续调用
|
|
473
547
|
// configEditor,否则会出现 inactive context 并污染退出日志。
|
|
474
548
|
sessionStore.dispose();
|
|
549
|
+
// Close native interaction cards before unloading their provider transports.
|
|
550
|
+
lifetime.abort();
|
|
475
551
|
await registry.dispose();
|
|
476
552
|
await sessionStore.flush();
|
|
477
553
|
setAdapterRegistry(undefined);
|
|
@@ -526,12 +602,13 @@ function createExternalSessionStatusPublisher(events, registry, sessionStore) {
|
|
|
526
602
|
* `messages`,会直接抛出只读属性异常。`agent/pre-step` 返回的新消息保留用户原文,并把
|
|
527
603
|
* 译文写入 source 元数据;外部适配器再据此构造发给 Agent 的译文。
|
|
528
604
|
*/
|
|
529
|
-
function registerDelegationAgentHooks(dshContext, registry, resources, publishExternalStatus, translation) {
|
|
605
|
+
function registerDelegationAgentHooks(dshContext, registry, resources, publishExternalStatus, translation, translationRecovery, promptTranslation, nativeSessions) {
|
|
530
606
|
if (dshContext === undefined || typeof dshContext.on !== 'function')
|
|
531
607
|
return;
|
|
532
608
|
const disposers = [];
|
|
533
609
|
const register = (name, listener) => {
|
|
534
|
-
|
|
610
|
+
// Wrap existing pre-step producers so their after-next catalogs are visible.
|
|
611
|
+
const disposer = dshContext.on(name, listener, { global: true, prepend: name === 'agent/pre-step' });
|
|
535
612
|
if (typeof disposer === 'function')
|
|
536
613
|
disposers.push(disposer);
|
|
537
614
|
};
|
|
@@ -588,20 +665,44 @@ function registerDelegationAgentHooks(dshContext, registry, resources, publishEx
|
|
|
588
665
|
messages = [...delegation.value.messages];
|
|
589
666
|
}
|
|
590
667
|
}
|
|
591
|
-
|
|
668
|
+
let translatedInput;
|
|
669
|
+
try {
|
|
670
|
+
translatedInput = await translatePreStepInput(translation, translationRecovery, registry, sessionId, messages, dshContext, isAbortSignal(record?.signal) ? record.signal : undefined, nativePreStepContext(translation, registry, sessionId, nativeSessions));
|
|
671
|
+
}
|
|
672
|
+
catch (error) {
|
|
673
|
+
if (error instanceof SessionTranslationCancelled || record?.signal?.aborted === true)
|
|
674
|
+
return { kind: 'reject' };
|
|
675
|
+
throw error;
|
|
676
|
+
}
|
|
592
677
|
if (translatedInput !== undefined)
|
|
593
678
|
messages = [...translatedInput];
|
|
594
679
|
const decision = await next();
|
|
595
680
|
if (!isEnterPreStepDecision(decision))
|
|
596
681
|
return decision;
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
682
|
+
// Match producer-owned messages by identity. Downstream middleware may insert
|
|
683
|
+
// instructions before the human message, so a positional prefix loses data.
|
|
684
|
+
const incoming = Array.isArray(record?.messages) ? record.messages.filter(isMessage) : [];
|
|
685
|
+
const replaced = new Set();
|
|
686
|
+
const accepted = delegation?.kind === 'rewritten' || translatedInput !== undefined
|
|
687
|
+
? decision.messages.map(message => {
|
|
688
|
+
const index = incoming.findIndex((original, position) => !replaced.has(position) && (original === message || typeof original.id === 'string' && original.id === message.id
|
|
689
|
+
// Legacy callers can return detached messages without durable IDs.
|
|
690
|
+
|| original.id === undefined && message.id === undefined && original.role === message.role
|
|
691
|
+
&& original.source?.kind === message.source?.kind && original.source?.form === message.source?.form
|
|
692
|
+
&& JSON.stringify(original.content) === JSON.stringify(message.content)));
|
|
693
|
+
if (index >= 0)
|
|
694
|
+
replaced.add(index);
|
|
695
|
+
return index < 0 ? message : messages[index] ?? message;
|
|
696
|
+
}) : decision.messages;
|
|
697
|
+
try {
|
|
698
|
+
const scope = sessionPromptScope(record?.agent, isAbortSignal(record?.signal) ? record.signal : undefined);
|
|
699
|
+
return { ...decision, messages: await promptTranslation.translateMessages(accepted, scope) };
|
|
700
|
+
}
|
|
701
|
+
catch (error) {
|
|
702
|
+
if (error instanceof SessionTranslationCancelled || record?.signal?.aborted === true)
|
|
703
|
+
return { kind: 'reject' };
|
|
704
|
+
throw error;
|
|
705
|
+
}
|
|
605
706
|
});
|
|
606
707
|
// 正常结束、异常结束和中断最终都会进入 idle;在此清理本轮授权,避免下一轮
|
|
607
708
|
// 没有 carrier 时继承上一轮的目标白名单。
|
|
@@ -611,12 +712,14 @@ function registerDelegationAgentHooks(dshContext, registry, resources, publishEx
|
|
|
611
712
|
if (record?.status === 'running')
|
|
612
713
|
publishExternalStatus(sessionId, true);
|
|
613
714
|
else if (record?.status === 'idle') {
|
|
715
|
+
translationRecovery.cancelSession(sessionId);
|
|
614
716
|
publishExternalStatus(sessionId, false);
|
|
615
717
|
clearDelegationAuthorization(sessionId);
|
|
616
718
|
}
|
|
617
719
|
});
|
|
618
720
|
register('agent/disposed', (payload) => {
|
|
619
721
|
const sessionId = readAgentSessionId(asRecord(payload)?.agent);
|
|
722
|
+
translationRecovery.cancelSession(sessionId);
|
|
620
723
|
// disposed 只代表运行时释放;subagentCatalog 没有删除语义,保留目录项并
|
|
621
724
|
// 把它标成 idle,后续若 DSH 重新激活会再次收到 running。
|
|
622
725
|
publishExternalStatus(sessionId, false);
|
|
@@ -979,18 +1082,20 @@ async function setAdapterEnabled(settings, registry, value) {
|
|
|
979
1082
|
return { adapterId, enabled };
|
|
980
1083
|
}
|
|
981
1084
|
/** 运行中的外部 Agent 插话也必须经过同一条输入翻译路径。 */
|
|
982
|
-
async function translateSteerPrompt(
|
|
1085
|
+
async function translateSteerPrompt(translationRecovery, registry, sessionId, prompt, followUp, signal) {
|
|
983
1086
|
const session = registry.getSession(sessionId);
|
|
984
1087
|
let translated = prompt;
|
|
985
|
-
if (
|
|
1088
|
+
if (session.translationEnabled === true) {
|
|
986
1089
|
try {
|
|
987
|
-
translated = await
|
|
1090
|
+
translated = (await translationRecovery.translateInput(sessionId, session.adapterId, prompt, signal)).translated;
|
|
988
1091
|
}
|
|
989
|
-
catch {
|
|
990
|
-
|
|
991
|
-
|
|
1092
|
+
catch (error) {
|
|
1093
|
+
if (error instanceof SessionTranslationCancelled)
|
|
1094
|
+
return;
|
|
1095
|
+
throw error;
|
|
992
1096
|
}
|
|
993
1097
|
}
|
|
1098
|
+
signal?.throwIfAborted();
|
|
994
1099
|
await registry.steer(sessionId, translated, followUp);
|
|
995
1100
|
}
|
|
996
1101
|
/**
|
|
@@ -999,9 +1104,42 @@ async function translateSteerPrompt(translation, registry, sessionId, prompt, fo
|
|
|
999
1104
|
* DSH 随后会把返回的消息写入 `user/message`。正文只放实际发送的译文;原文和模型
|
|
1000
1105
|
* 记录在 source 元数据中供 Client 详情按钮读取。外部 CLI 边界也会移除该元数据。
|
|
1001
1106
|
*/
|
|
1002
|
-
async function translatePreStepInput(translation, registry, sessionId, messages, dshContext, signal) {
|
|
1003
|
-
if (translation === undefined || !translation.enabled || sessionId.trim() === '')
|
|
1107
|
+
async function translatePreStepInput(translation, translationRecovery, registry, sessionId, messages, dshContext, signal, nativeSession) {
|
|
1108
|
+
if (translation === undefined || !translation.enabled || translation.inputEnabled === false || sessionId.trim() === '')
|
|
1109
|
+
return undefined;
|
|
1110
|
+
const messageIndex = findLatestHumanMessage(messages);
|
|
1111
|
+
const current = messageIndex < 0 ? undefined : messages[messageIndex];
|
|
1112
|
+
if (current === undefined || readInputTranslation(current.source) !== undefined)
|
|
1004
1113
|
return undefined;
|
|
1114
|
+
if (nativeSession !== undefined) {
|
|
1115
|
+
// DSH 原生会话:消息本身就是发给 Provider 的正文,直接替换为译文并把原文留在元数据。
|
|
1116
|
+
if (nativeSession.translationEnabled !== true)
|
|
1117
|
+
return undefined;
|
|
1118
|
+
const input = extractTurnInput(messages, dshContext);
|
|
1119
|
+
if (input.prompt.trim() === '')
|
|
1120
|
+
return undefined;
|
|
1121
|
+
const result = await translationRecovery.translateInput(sessionId, nativeSession.adapterId, input.translationPrompt, signal);
|
|
1122
|
+
const translated = [result.translated, attachmentNotices(input.attachments, readInputTargetLanguage(translation))].filter((part) => part.trim() !== '').join('\n\n').trim();
|
|
1123
|
+
if (translated === '')
|
|
1124
|
+
return undefined;
|
|
1125
|
+
const record = {
|
|
1126
|
+
original: input.prompt,
|
|
1127
|
+
translated,
|
|
1128
|
+
...(result.sourceLanguage === undefined ? {} : { sourceLanguage: result.sourceLanguage }),
|
|
1129
|
+
targetLanguage: readInputTargetLanguage(translation),
|
|
1130
|
+
...(result.alreadyTargetLanguage === true ? { alreadyTargetLanguage: true } : {}),
|
|
1131
|
+
...(result.model === undefined ? {} : { model: result.model }),
|
|
1132
|
+
...readSessionTranslationMetrics(result),
|
|
1133
|
+
...(result.failed === true ? { failed: true } : {}),
|
|
1134
|
+
};
|
|
1135
|
+
const next = [...messages];
|
|
1136
|
+
next[messageIndex] = {
|
|
1137
|
+
...current,
|
|
1138
|
+
content: result.failed ? current.content : replaceInputTranslationContent(nativeTranslationContent(current.content, dshContext), translated),
|
|
1139
|
+
source: { ...(current.source ?? {}), kind: 'user', codingnsTranslationInput: record },
|
|
1140
|
+
};
|
|
1141
|
+
return next;
|
|
1142
|
+
}
|
|
1005
1143
|
let session;
|
|
1006
1144
|
try {
|
|
1007
1145
|
session = registry.getSession(sessionId);
|
|
@@ -1011,37 +1149,11 @@ async function translatePreStepInput(translation, registry, sessionId, messages,
|
|
|
1011
1149
|
}
|
|
1012
1150
|
if (session.adapterId === 'dsh' || session.translationEnabled !== true)
|
|
1013
1151
|
return undefined;
|
|
1014
|
-
const messageIndex = findLatestHumanMessage(messages);
|
|
1015
|
-
const current = messageIndex < 0 ? undefined : messages[messageIndex];
|
|
1016
|
-
if (current === undefined || readInputTranslation(current.source) !== undefined)
|
|
1017
|
-
return undefined;
|
|
1018
1152
|
const input = extractTurnInput(messages, dshContext);
|
|
1019
|
-
if (input.
|
|
1153
|
+
if (input.prompt.trim() === '')
|
|
1020
1154
|
return undefined;
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
let alreadyTargetLanguage = false;
|
|
1024
|
-
let translationModel;
|
|
1025
|
-
let translationFailed = false;
|
|
1026
|
-
try {
|
|
1027
|
-
if (translation.translateInputDetailed !== undefined) {
|
|
1028
|
-
const detailed = await translation.translateInputDetailed(session.adapterId, input.translationPrompt, signal, true);
|
|
1029
|
-
translatedNatural = detailed.translated;
|
|
1030
|
-
translationSourceLanguage = detailed.sourceLanguage;
|
|
1031
|
-
alreadyTargetLanguage = detailed.alreadyTargetLanguage === true;
|
|
1032
|
-
translationModel = detailed.model;
|
|
1033
|
-
translationFailed = detailed.failed === true;
|
|
1034
|
-
}
|
|
1035
|
-
else {
|
|
1036
|
-
translatedNatural = await translation.translateInput(session.adapterId, input.translationPrompt, signal, true);
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
catch {
|
|
1040
|
-
// 翻译只是增强能力;异常时保持现有外部 Agent 回合继续使用原文。
|
|
1041
|
-
translatedNatural = input.translationPrompt;
|
|
1042
|
-
translationFailed = true;
|
|
1043
|
-
}
|
|
1044
|
-
const translated = [translatedNatural, input.untranslatedPrompt]
|
|
1155
|
+
const result = await translationRecovery.translateInput(sessionId, session.adapterId, input.translationPrompt, signal);
|
|
1156
|
+
const translated = [result.translated, attachmentNotices(input.attachments, readInputTargetLanguage(translation))]
|
|
1045
1157
|
.filter((part) => part.trim() !== '')
|
|
1046
1158
|
.join('\n\n')
|
|
1047
1159
|
.trim();
|
|
@@ -1050,11 +1162,12 @@ async function translatePreStepInput(translation, registry, sessionId, messages,
|
|
|
1050
1162
|
const record = {
|
|
1051
1163
|
original: input.prompt,
|
|
1052
1164
|
translated,
|
|
1053
|
-
...(
|
|
1054
|
-
targetLanguage: translation
|
|
1055
|
-
...(alreadyTargetLanguage ? { alreadyTargetLanguage: true } : {}),
|
|
1056
|
-
...(
|
|
1057
|
-
...(
|
|
1165
|
+
...(result.sourceLanguage === undefined ? {} : { sourceLanguage: result.sourceLanguage }),
|
|
1166
|
+
targetLanguage: readInputTargetLanguage(translation),
|
|
1167
|
+
...(result.alreadyTargetLanguage === true ? { alreadyTargetLanguage: true } : {}),
|
|
1168
|
+
...(result.model === undefined ? {} : { model: result.model }),
|
|
1169
|
+
...readSessionTranslationMetrics(result),
|
|
1170
|
+
...(result.failed === true ? { failed: true } : {}),
|
|
1058
1171
|
};
|
|
1059
1172
|
const next = [...messages];
|
|
1060
1173
|
next[messageIndex] = {
|
|
@@ -1067,6 +1180,177 @@ async function translatePreStepInput(translation, registry, sessionId, messages,
|
|
|
1067
1180
|
};
|
|
1068
1181
|
return next;
|
|
1069
1182
|
}
|
|
1183
|
+
/** 旧测试替身没有 inputLanguage 时沿用历史默认值英语。 */
|
|
1184
|
+
function readInputTargetLanguage(translation) {
|
|
1185
|
+
const language = translation.inputLanguage;
|
|
1186
|
+
return language === undefined ? 'en' : language;
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* 判断本次 pre-step 是否按 DSH 原生会话翻译。
|
|
1190
|
+
*
|
|
1191
|
+
* 原生会话的翻译记录来自全局 `nativeEnabled` 与适配器偏好(会话索引对 `dsh` 不落盘),
|
|
1192
|
+
* 子代理与插件自己的助理会话必须排除,避免把内部执行流水线翻译掉。
|
|
1193
|
+
*/
|
|
1194
|
+
function nativePreStepContext(translation, registry, sessionId, nativeSessions) {
|
|
1195
|
+
if (translation === undefined || !translation.enabled || sessionId.trim() === '')
|
|
1196
|
+
return undefined;
|
|
1197
|
+
if (isAssistantSession(sessionId))
|
|
1198
|
+
return undefined;
|
|
1199
|
+
if (readNativeSessionHeader(nativeSessions, sessionId)?.origin === 'subagent')
|
|
1200
|
+
return undefined;
|
|
1201
|
+
let session;
|
|
1202
|
+
try {
|
|
1203
|
+
session = registry.getSession(sessionId);
|
|
1204
|
+
}
|
|
1205
|
+
catch {
|
|
1206
|
+
return undefined;
|
|
1207
|
+
}
|
|
1208
|
+
if (session.adapterId !== DSH_NATIVE_SESSION_ADAPTER_ID)
|
|
1209
|
+
return undefined;
|
|
1210
|
+
return {
|
|
1211
|
+
adapterId: DSH_NATIVE_SESSION_ADAPTER_ID,
|
|
1212
|
+
// 会话级开关优先;用户没有单独设置过该会话时跟随「DSH 原生会话」总开关。
|
|
1213
|
+
translationEnabled: session.translationEnabled ?? translation.nativeEnabled === true,
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
/** 读取原生会话 header;测试替身或会话尚未装载时返回 undefined。 */
|
|
1217
|
+
function readNativeSessionHeader(nativeSessions, sessionId) {
|
|
1218
|
+
if (nativeSessions === undefined)
|
|
1219
|
+
return undefined;
|
|
1220
|
+
try {
|
|
1221
|
+
return asRecord(asRecord(nativeSessions.get(sessionId))?.header) ?? undefined;
|
|
1222
|
+
}
|
|
1223
|
+
catch {
|
|
1224
|
+
return undefined;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
/** 插件自己的全局助理会话不属于用户对话,不能被翻译改写。 */
|
|
1228
|
+
function isAssistantSession(sessionId) {
|
|
1229
|
+
// 复用助理适配器导出的会话前缀常量:会话身份的唯一定义在那里,重复字面量会漂移。
|
|
1230
|
+
return sessionId.startsWith(ASSISTANT_AGENT_PREFIX);
|
|
1231
|
+
}
|
|
1232
|
+
/**
|
|
1233
|
+
* DSH 原生会话的输出翻译。
|
|
1234
|
+
*
|
|
1235
|
+
* 原生回复由 DSH 自己组装成 `assistant/message`,插件只能在 Provider 流边界改写:
|
|
1236
|
+
* 文本与思考增量先缓存,块结束时一次性发出原文,并把译文放进记录供客户端显示;
|
|
1237
|
+
* 工具调用、usage 与 finish 原样透传。翻译失败、流中断或异常都会补发原文块,保证回复不丢失。
|
|
1238
|
+
*/
|
|
1239
|
+
async function* translateNativeStream(stream, translation, bilingual, signal) {
|
|
1240
|
+
const blocks = new Map();
|
|
1241
|
+
const bufferOf = (index, kind) => {
|
|
1242
|
+
const existing = blocks.get(index);
|
|
1243
|
+
if (existing !== undefined)
|
|
1244
|
+
return existing.kind === kind && !existing.closed ? existing : undefined;
|
|
1245
|
+
const created = {
|
|
1246
|
+
index, kind, text: '', closed: false,
|
|
1247
|
+
translate: translation.shouldTranslate(DSH_NATIVE_SESSION_ADAPTER_ID, kind === 'reasoning' ? 'reasoning' : 'assistant', true),
|
|
1248
|
+
};
|
|
1249
|
+
blocks.set(index, created);
|
|
1250
|
+
return created;
|
|
1251
|
+
};
|
|
1252
|
+
const translateBlock = async (block) => {
|
|
1253
|
+
const original = block.text;
|
|
1254
|
+
if (original.trim() === '')
|
|
1255
|
+
return [];
|
|
1256
|
+
const kind = block.kind === 'reasoning' ? 'reasoning' : 'assistant';
|
|
1257
|
+
let record;
|
|
1258
|
+
try {
|
|
1259
|
+
const result = await translation.translateOutput(DSH_NATIVE_SESSION_ADAPTER_ID, kind, original, signal, true);
|
|
1260
|
+
if (result !== null && result !== undefined) {
|
|
1261
|
+
record = {
|
|
1262
|
+
original: result.original,
|
|
1263
|
+
translated: result.translated,
|
|
1264
|
+
...(result.sourceLanguage === undefined ? {} : { sourceLanguage: result.sourceLanguage }),
|
|
1265
|
+
targetLanguage: result.targetLanguage,
|
|
1266
|
+
outputKind: kind,
|
|
1267
|
+
bilingual: result.bilingual,
|
|
1268
|
+
...(result.alreadyTargetLanguage === true ? { alreadyTargetLanguage: true } : {}),
|
|
1269
|
+
...(result.model === undefined ? {} : { model: result.model }),
|
|
1270
|
+
...readSessionTranslationMetrics(result),
|
|
1271
|
+
...(result.failed === true ? { failed: true } : {}),
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
catch {
|
|
1276
|
+
record = { original, translated: original, targetLanguage: translation.outputLanguage ?? 'zh', outputKind: kind, bilingual, failed: true };
|
|
1277
|
+
}
|
|
1278
|
+
if (record === undefined)
|
|
1279
|
+
return [];
|
|
1280
|
+
const visible = formatSessionTranslationOutput(record);
|
|
1281
|
+
if (visible.trim() === '' || visible === original && record.failed !== true)
|
|
1282
|
+
return [];
|
|
1283
|
+
return [
|
|
1284
|
+
// Keep the provider text in the native history. The client chooses the translated
|
|
1285
|
+
// text for display from codingnsTranslation.translated.
|
|
1286
|
+
{ type: `${block.kind}-delta`, index: block.index, text: original, codingnsTranslation: record },
|
|
1287
|
+
{ type: 'block-end', index: block.index, block: { type: block.kind, text: original, codingnsTranslation: record }, codingnsTranslation: record },
|
|
1288
|
+
];
|
|
1289
|
+
};
|
|
1290
|
+
try {
|
|
1291
|
+
for await (const chunk of stream) {
|
|
1292
|
+
const record = asRecord(chunk);
|
|
1293
|
+
const type = typeof record?.type === 'string' ? record.type : '';
|
|
1294
|
+
const index = typeof record?.index === 'number' ? record.index : undefined;
|
|
1295
|
+
if (type === 'text-delta' || type === 'reasoning-delta') {
|
|
1296
|
+
if (index === undefined || typeof record?.text !== 'string') {
|
|
1297
|
+
yield chunk;
|
|
1298
|
+
continue;
|
|
1299
|
+
}
|
|
1300
|
+
const kind = type === 'text-delta' ? 'text' : 'reasoning';
|
|
1301
|
+
const block = bufferOf(index, kind);
|
|
1302
|
+
// Decide once per block: changing settings must not translate only a suffix
|
|
1303
|
+
// or drop a prefix that was already buffered.
|
|
1304
|
+
if (block === undefined || !block.translate) {
|
|
1305
|
+
yield chunk;
|
|
1306
|
+
continue;
|
|
1307
|
+
}
|
|
1308
|
+
block.text += record.text;
|
|
1309
|
+
continue;
|
|
1310
|
+
}
|
|
1311
|
+
if (type === 'block-end' && index !== undefined) {
|
|
1312
|
+
const block = blocks.get(index);
|
|
1313
|
+
if (block !== undefined && !block.closed) {
|
|
1314
|
+
block.closed = true;
|
|
1315
|
+
if (block.text.trim() !== '') {
|
|
1316
|
+
const emitted = await translateBlock(block);
|
|
1317
|
+
for (const item of emitted)
|
|
1318
|
+
yield item;
|
|
1319
|
+
if (emitted.length > 0)
|
|
1320
|
+
continue;
|
|
1321
|
+
yield { type: `${block.kind}-delta`, index: block.index, text: block.text };
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
yield chunk;
|
|
1325
|
+
continue;
|
|
1326
|
+
}
|
|
1327
|
+
yield chunk;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
catch (error) {
|
|
1331
|
+
// 流异常时先把缓存正文按原文补发,再把原始错误交给 DSH,保证回复不丢失。
|
|
1332
|
+
for (const item of flushBuffered())
|
|
1333
|
+
yield item;
|
|
1334
|
+
throw error;
|
|
1335
|
+
}
|
|
1336
|
+
for (const item of flushBuffered())
|
|
1337
|
+
yield item;
|
|
1338
|
+
/**
|
|
1339
|
+
* Provider 未发送 block-end(中断或异常)时,把缓存正文按原文补发。
|
|
1340
|
+
*
|
|
1341
|
+
* 不能用 `finally` 里的 `yield`:异常正在传播时生成器已经结束,后续 yield 会被
|
|
1342
|
+
* 直接丢弃,用户会看不到已经生成的半截回复。
|
|
1343
|
+
*/
|
|
1344
|
+
function* flushBuffered() {
|
|
1345
|
+
for (const block of [...blocks.values()]) {
|
|
1346
|
+
if (block.closed || block.text.trim() === '')
|
|
1347
|
+
continue;
|
|
1348
|
+
block.closed = true;
|
|
1349
|
+
yield { type: `${block.kind}-delta`, index: block.index, text: block.text };
|
|
1350
|
+
yield { type: 'block-end', index: block.index, block: { type: block.kind, text: block.text } };
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1070
1354
|
function extractTurnInput(messages, dshContext) {
|
|
1071
1355
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
1072
1356
|
const message = messages[index];
|
|
@@ -1125,7 +1409,7 @@ function readInputTranslation(value) {
|
|
|
1125
1409
|
return undefined;
|
|
1126
1410
|
if (candidate.original.trim() === '' || candidate.translated.trim() === '')
|
|
1127
1411
|
return undefined;
|
|
1128
|
-
const targetLanguage = candidate.targetLanguage === 'fr' || candidate.targetLanguage === 'de' || candidate.targetLanguage === 'ja'
|
|
1412
|
+
const targetLanguage = candidate.targetLanguage === 'fr' || candidate.targetLanguage === 'de' || candidate.targetLanguage === 'ja' || candidate.targetLanguage === 'zh'
|
|
1129
1413
|
? candidate.targetLanguage
|
|
1130
1414
|
: 'en';
|
|
1131
1415
|
const sourceLanguage = candidate.sourceLanguage === 'zh' || candidate.sourceLanguage === 'en' || candidate.sourceLanguage === 'fr' || candidate.sourceLanguage === 'de' || candidate.sourceLanguage === 'ja'
|
|
@@ -1175,6 +1459,19 @@ function replaceInputTranslationContent(content, text) {
|
|
|
1175
1459
|
});
|
|
1176
1460
|
return replaced ? blocks : [{ type: 'text', text }, ...content];
|
|
1177
1461
|
}
|
|
1462
|
+
/** Resolved files already have localized path notices. Leaving their file blocks
|
|
1463
|
+
* would make DSH append another, English-only file notice at adapter dispatch.
|
|
1464
|
+
* Preserve images and unresolved files so DSH retains modality/error handling.
|
|
1465
|
+
*/
|
|
1466
|
+
function nativeTranslationContent(content, dshContext) {
|
|
1467
|
+
if (!Array.isArray(content))
|
|
1468
|
+
return content;
|
|
1469
|
+
return content.filter(part => {
|
|
1470
|
+
if (!isRecord(part) || part.type !== 'file')
|
|
1471
|
+
return true;
|
|
1472
|
+
return resolveDshAttachmentPath(dshContext, 'file', isRecord(part.attachment) ? part.attachment : part) === undefined;
|
|
1473
|
+
});
|
|
1474
|
+
}
|
|
1178
1475
|
/** DSH 为工具分段注入的继续提示必须成为下一次 Provider 请求的 prompt。 */
|
|
1179
1476
|
function isInjectedStepNotice(message) {
|
|
1180
1477
|
if (message.role !== 'user' || !isRecord(message.source))
|
|
@@ -1230,11 +1527,13 @@ function extractMessageInput(content, dshContext) {
|
|
|
1230
1527
|
const mimeType = typeof reference.mediaType === 'string' && reference.mediaType.trim() !== '' ? reference.mediaType.trim() : undefined;
|
|
1231
1528
|
attachments.push({ kind, path, ...(name === undefined ? {} : { name }), ...(mimeType === undefined ? {} : { mimeType }) });
|
|
1232
1529
|
}
|
|
1233
|
-
const fileNotes = attachments.filter((attachment) => attachment.kind === 'file').map((attachment) => `附件文件${attachment.name === undefined ? '' : `「${attachment.name}」`}位于:${attachment.path}\n请使用工具读取该文件的内容。`);
|
|
1234
1530
|
const translationPrompt = text.join('\n\n').trim();
|
|
1235
|
-
const untranslatedPrompt =
|
|
1531
|
+
const untranslatedPrompt = attachmentNotices(attachments);
|
|
1236
1532
|
return { prompt: [translationPrompt, untranslatedPrompt].filter(value => value !== '').join('\n\n'), translationPrompt, untranslatedPrompt, attachments };
|
|
1237
1533
|
}
|
|
1534
|
+
function attachmentNotices(attachments, language) {
|
|
1535
|
+
return attachments.filter(attachment => attachment.kind === 'file').map(attachment => attachmentFileNotice(attachment, language)).join('\n\n');
|
|
1536
|
+
}
|
|
1238
1537
|
function resolveDshAttachmentPath(dshContext, kind, reference) {
|
|
1239
1538
|
if (dshContext === undefined || typeof reference.attachmentId !== 'string')
|
|
1240
1539
|
return undefined;
|