@jsonstudio/llms 0.6.1739 → 0.6.1890
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/conversion/compat/actions/deepseek-web-request.d.ts +3 -0
- package/dist/conversion/compat/actions/deepseek-web-request.js +350 -0
- package/dist/conversion/compat/actions/deepseek-web-response.d.ts +3 -0
- package/dist/conversion/compat/actions/deepseek-web-response.js +886 -0
- package/dist/conversion/compat/actions/gemini-cli-request.js +3 -1
- package/dist/conversion/compat/profiles/chat-deepseek-web.json +18 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +166 -2
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +169 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +6 -0
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +12 -0
- package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.js +1 -0
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +4 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +365 -144
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +9 -0
- package/dist/conversion/hub/policy/policy-engine.d.ts +2 -0
- package/dist/conversion/hub/policy/policy-engine.js +8 -0
- package/dist/conversion/hub/process/chat-process.js +466 -16
- package/dist/conversion/hub/response/provider-response.js +0 -35
- package/dist/conversion/responses/responses-openai-bridge.d.ts +2 -0
- package/dist/conversion/responses/responses-openai-bridge.js +166 -8
- package/dist/conversion/shared/anthropic-message-utils.js +10 -1
- package/dist/conversion/shared/protocol-field-allowlists.d.ts +2 -2
- package/dist/conversion/shared/protocol-field-allowlists.js +4 -0
- package/dist/conversion/shared/tool-governor.js +102 -0
- package/dist/guidance/index.js +17 -0
- package/dist/router/virtual-router/bootstrap.js +46 -1
- package/dist/router/virtual-router/classifier.js +59 -4
- package/dist/router/virtual-router/engine/health/index.js +6 -6
- package/dist/router/virtual-router/engine/routing-state/store.js +16 -3
- package/dist/router/virtual-router/engine-logging.js +62 -24
- package/dist/router/virtual-router/engine-selection/route-utils.js +20 -20
- package/dist/router/virtual-router/engine-selection/tier-selection.js +2 -2
- package/dist/router/virtual-router/engine.d.ts +3 -1
- package/dist/router/virtual-router/engine.js +359 -39
- package/dist/router/virtual-router/features.js +2 -1
- package/dist/router/virtual-router/pre-command-file-resolver.d.ts +2 -0
- package/dist/router/virtual-router/pre-command-file-resolver.js +90 -0
- package/dist/router/virtual-router/provider-registry.js +3 -1
- package/dist/router/virtual-router/routing-instructions.d.ts +15 -1
- package/dist/router/virtual-router/routing-instructions.js +110 -151
- package/dist/router/virtual-router/routing-pre-command-actions.d.ts +3 -0
- package/dist/router/virtual-router/routing-pre-command-actions.js +26 -0
- package/dist/router/virtual-router/routing-pre-command-parser.d.ts +2 -0
- package/dist/router/virtual-router/routing-pre-command-parser.js +85 -0
- package/dist/router/virtual-router/routing-pre-command-state-codec.d.ts +3 -0
- package/dist/router/virtual-router/routing-pre-command-state-codec.js +24 -0
- package/dist/router/virtual-router/routing-stop-message-actions.d.ts +2 -0
- package/dist/router/virtual-router/routing-stop-message-actions.js +96 -0
- package/dist/router/virtual-router/routing-stop-message-parser.d.ts +3 -0
- package/dist/router/virtual-router/routing-stop-message-parser.js +142 -0
- package/dist/router/virtual-router/routing-stop-message-state-codec.d.ts +4 -0
- package/dist/router/virtual-router/routing-stop-message-state-codec.js +85 -0
- package/dist/router/virtual-router/sticky-session-store.js +206 -57
- package/dist/router/virtual-router/stop-message-stage-template-files.d.ts +12 -0
- package/dist/router/virtual-router/stop-message-stage-template-files.js +67 -0
- package/dist/router/virtual-router/stop-message-state-sync.d.ts +1 -1
- package/dist/router/virtual-router/stop-message-state-sync.js +5 -0
- package/dist/router/virtual-router/token-file-scanner.d.ts +9 -0
- package/dist/router/virtual-router/token-file-scanner.js +64 -3
- package/dist/router/virtual-router/tool-signals.d.ts +5 -0
- package/dist/router/virtual-router/tool-signals.js +42 -3
- package/dist/router/virtual-router/types.d.ts +19 -1
- package/dist/router/virtual-router/types.js +1 -0
- package/dist/servertool/clock/config.d.ts +1 -1
- package/dist/servertool/clock/config.js +27 -4
- package/dist/servertool/clock/state.js +41 -2
- package/dist/servertool/clock/task-store.d.ts +2 -2
- package/dist/servertool/clock/task-store.js +1 -1
- package/dist/servertool/clock/tasks.d.ts +3 -1
- package/dist/servertool/clock/tasks.js +209 -18
- package/dist/servertool/clock/types.d.ts +17 -0
- package/dist/servertool/continue-execution/log.d.ts +3 -0
- package/dist/servertool/continue-execution/log.js +13 -0
- package/dist/servertool/engine.js +414 -68
- package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.js +6 -6
- package/dist/servertool/handlers/clock-auto.js +54 -71
- package/dist/servertool/handlers/clock.js +121 -6
- package/dist/servertool/handlers/continue-execution.d.ts +1 -0
- package/dist/servertool/handlers/continue-execution.js +91 -0
- package/dist/servertool/handlers/followup-request-builder.js +13 -0
- package/dist/servertool/handlers/gemini-empty-reply-continue.js +1 -1
- package/dist/servertool/handlers/iflow-model-error-retry.js +1 -1
- package/dist/servertool/handlers/recursive-detection-guard.js +1 -1
- package/dist/servertool/handlers/stop-message-auto.js +386 -257
- package/dist/servertool/handlers/stop-message-stage-policy.d.ts +43 -0
- package/dist/servertool/handlers/stop-message-stage-policy.js +684 -0
- package/dist/servertool/handlers/vision.js +1 -1
- package/dist/servertool/log/progress-file.d.ts +14 -0
- package/dist/servertool/log/progress-file.js +88 -0
- package/dist/servertool/pre-command-hooks.d.ts +17 -0
- package/dist/servertool/pre-command-hooks.js +491 -0
- package/dist/servertool/registry.d.ts +23 -6
- package/dist/servertool/registry.js +66 -1
- package/dist/servertool/server-side-tools.d.ts +1 -0
- package/dist/servertool/server-side-tools.js +216 -14
- package/dist/servertool/stop-gateway-context.d.ts +14 -0
- package/dist/servertool/stop-gateway-context.js +167 -0
- package/dist/servertool/stop-message-compare-context.d.ts +24 -0
- package/dist/servertool/stop-message-compare-context.js +133 -0
- package/dist/servertool/types.d.ts +12 -0
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +1 -0
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +36 -1
- package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +3 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +3 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +118 -1
- package/dist/tools/apply-patch/args-normalizer/default-actions.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { ensureRuntimeMetadata, readRuntimeMetadata } from '../conversion/shared/runtime-metadata.js';
|
|
2
|
+
const STOP_MESSAGE_COMPARE_KEY = 'stopMessageCompareContext';
|
|
3
|
+
export function attachStopMessageCompareContext(adapterContext, context) {
|
|
4
|
+
if (!adapterContext || typeof adapterContext !== 'object' || Array.isArray(adapterContext)) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
try {
|
|
8
|
+
const runtime = ensureRuntimeMetadata(adapterContext);
|
|
9
|
+
runtime[STOP_MESSAGE_COMPARE_KEY] = {
|
|
10
|
+
armed: context.armed,
|
|
11
|
+
mode: context.mode,
|
|
12
|
+
allowModeOnly: context.allowModeOnly,
|
|
13
|
+
textLength: context.textLength,
|
|
14
|
+
maxRepeats: context.maxRepeats,
|
|
15
|
+
used: context.used,
|
|
16
|
+
remaining: context.remaining,
|
|
17
|
+
active: context.active,
|
|
18
|
+
stopEligible: context.stopEligible,
|
|
19
|
+
hasCapturedRequest: context.hasCapturedRequest,
|
|
20
|
+
compactionRequest: context.compactionRequest,
|
|
21
|
+
hasSeed: context.hasSeed,
|
|
22
|
+
decision: context.decision,
|
|
23
|
+
reason: context.reason,
|
|
24
|
+
...(typeof context.stage === 'string' && context.stage.trim() ? { stage: context.stage.trim() } : {}),
|
|
25
|
+
...(typeof context.bdWorkState === 'string' && context.bdWorkState.trim()
|
|
26
|
+
? { bdWorkState: context.bdWorkState.trim() }
|
|
27
|
+
: {}),
|
|
28
|
+
...(typeof context.observationHash === 'string' && context.observationHash.trim()
|
|
29
|
+
? { observationHash: context.observationHash.trim() }
|
|
30
|
+
: {}),
|
|
31
|
+
...(typeof context.observationStableCount === 'number' && Number.isFinite(context.observationStableCount)
|
|
32
|
+
? { observationStableCount: Math.max(0, Math.floor(context.observationStableCount)) }
|
|
33
|
+
: {}),
|
|
34
|
+
...(typeof context.toolSignatureHash === 'string' && context.toolSignatureHash.trim()
|
|
35
|
+
? { toolSignatureHash: context.toolSignatureHash.trim() }
|
|
36
|
+
: {})
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// ignore metadata write failures
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function readStopMessageCompareContext(adapterContext) {
|
|
44
|
+
if (!adapterContext || typeof adapterContext !== 'object' || Array.isArray(adapterContext)) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const runtime = readRuntimeMetadata(adapterContext);
|
|
48
|
+
const raw = runtime && typeof runtime === 'object' ? runtime[STOP_MESSAGE_COMPARE_KEY] : undefined;
|
|
49
|
+
return normalizeStopMessageCompareContext(raw);
|
|
50
|
+
}
|
|
51
|
+
export function formatStopMessageCompareContext(context) {
|
|
52
|
+
if (!context) {
|
|
53
|
+
return 'decision=unknown reason=no_context';
|
|
54
|
+
}
|
|
55
|
+
return [
|
|
56
|
+
`decision=${context.decision}`,
|
|
57
|
+
`reason=${context.reason}`,
|
|
58
|
+
`armed=${context.armed}`,
|
|
59
|
+
`mode=${context.mode}`,
|
|
60
|
+
`allowModeOnly=${context.allowModeOnly}`,
|
|
61
|
+
`max=${context.maxRepeats}`,
|
|
62
|
+
`used=${context.used}`,
|
|
63
|
+
`left=${context.remaining}`,
|
|
64
|
+
`active=${context.active}`,
|
|
65
|
+
`stopEligible=${context.stopEligible}`,
|
|
66
|
+
`captured=${context.hasCapturedRequest}`,
|
|
67
|
+
`compaction=${context.compactionRequest}`,
|
|
68
|
+
`seed=${context.hasSeed}`,
|
|
69
|
+
...(typeof context.stage === 'string' && context.stage ? [`stage=${context.stage}`] : []),
|
|
70
|
+
...(typeof context.bdWorkState === 'string' && context.bdWorkState ? [`bd=${context.bdWorkState}`] : []),
|
|
71
|
+
`obs=${typeof context.observationHash === 'string' && context.observationHash ? context.observationHash : 'none'}`,
|
|
72
|
+
`stable=${typeof context.observationStableCount === 'number' && Number.isFinite(context.observationStableCount)
|
|
73
|
+
? Math.max(0, Math.floor(context.observationStableCount))
|
|
74
|
+
: 'n/a'}`,
|
|
75
|
+
`toolSig=${typeof context.toolSignatureHash === 'string' && context.toolSignatureHash ? context.toolSignatureHash : 'none'}`
|
|
76
|
+
].join(' ');
|
|
77
|
+
}
|
|
78
|
+
function normalizeStopMessageCompareContext(raw) {
|
|
79
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
const record = raw;
|
|
83
|
+
const decisionRaw = typeof record.decision === 'string' ? record.decision.trim().toLowerCase() : '';
|
|
84
|
+
if (decisionRaw !== 'trigger' && decisionRaw !== 'skip') {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
const modeRaw = typeof record.mode === 'string' ? record.mode.trim().toLowerCase() : '';
|
|
88
|
+
const mode = modeRaw === 'on' || modeRaw === 'auto' || modeRaw === 'off'
|
|
89
|
+
? modeRaw
|
|
90
|
+
: 'off';
|
|
91
|
+
const reason = typeof record.reason === 'string' && record.reason.trim() ? record.reason.trim() : 'unknown';
|
|
92
|
+
const textLength = typeof record.textLength === 'number' && Number.isFinite(record.textLength)
|
|
93
|
+
? Math.max(0, Math.floor(record.textLength))
|
|
94
|
+
: 0;
|
|
95
|
+
const maxRepeats = typeof record.maxRepeats === 'number' && Number.isFinite(record.maxRepeats)
|
|
96
|
+
? Math.max(0, Math.floor(record.maxRepeats))
|
|
97
|
+
: 0;
|
|
98
|
+
const used = typeof record.used === 'number' && Number.isFinite(record.used)
|
|
99
|
+
? Math.max(0, Math.floor(record.used))
|
|
100
|
+
: 0;
|
|
101
|
+
const remaining = typeof record.remaining === 'number' && Number.isFinite(record.remaining)
|
|
102
|
+
? Math.max(0, Math.floor(record.remaining))
|
|
103
|
+
: Math.max(0, maxRepeats - used);
|
|
104
|
+
return {
|
|
105
|
+
armed: Boolean(record.armed),
|
|
106
|
+
mode,
|
|
107
|
+
allowModeOnly: Boolean(record.allowModeOnly),
|
|
108
|
+
textLength,
|
|
109
|
+
maxRepeats,
|
|
110
|
+
used,
|
|
111
|
+
remaining,
|
|
112
|
+
active: Boolean(record.active),
|
|
113
|
+
stopEligible: Boolean(record.stopEligible),
|
|
114
|
+
hasCapturedRequest: Boolean(record.hasCapturedRequest),
|
|
115
|
+
compactionRequest: Boolean(record.compactionRequest),
|
|
116
|
+
hasSeed: Boolean(record.hasSeed),
|
|
117
|
+
decision: decisionRaw,
|
|
118
|
+
reason,
|
|
119
|
+
...(typeof record.stage === 'string' && record.stage.trim() ? { stage: record.stage.trim() } : {}),
|
|
120
|
+
...(typeof record.bdWorkState === 'string' && record.bdWorkState.trim()
|
|
121
|
+
? { bdWorkState: record.bdWorkState.trim() }
|
|
122
|
+
: {}),
|
|
123
|
+
...(typeof record.observationHash === 'string' && record.observationHash.trim()
|
|
124
|
+
? { observationHash: record.observationHash.trim() }
|
|
125
|
+
: {}),
|
|
126
|
+
...(typeof record.observationStableCount === 'number' && Number.isFinite(record.observationStableCount)
|
|
127
|
+
? { observationStableCount: Math.max(0, Math.floor(record.observationStableCount)) }
|
|
128
|
+
: {}),
|
|
129
|
+
...(typeof record.toolSignatureHash === 'string' && record.toolSignatureHash.trim()
|
|
130
|
+
? { toolSignatureHash: record.toolSignatureHash.trim() }
|
|
131
|
+
: {})
|
|
132
|
+
};
|
|
133
|
+
}
|
|
@@ -28,6 +28,17 @@ export interface ToolCall {
|
|
|
28
28
|
name: string;
|
|
29
29
|
arguments: string;
|
|
30
30
|
}
|
|
31
|
+
export interface ServerToolAutoHookTraceEvent {
|
|
32
|
+
hookId: string;
|
|
33
|
+
phase: string;
|
|
34
|
+
priority: number;
|
|
35
|
+
queue: 'A_optional' | 'B_mandatory';
|
|
36
|
+
queueIndex: number;
|
|
37
|
+
queueTotal: number;
|
|
38
|
+
result: 'miss' | 'match' | 'error';
|
|
39
|
+
reason: string;
|
|
40
|
+
flowId?: string;
|
|
41
|
+
}
|
|
31
42
|
/**
|
|
32
43
|
* ServerSideToolEngineOptions:ServerTool 引擎入参(ChatCompletion 视角)。
|
|
33
44
|
*/
|
|
@@ -48,6 +59,7 @@ export interface ServerSideToolEngineOptions {
|
|
|
48
59
|
__sse_responses?: unknown;
|
|
49
60
|
format?: string;
|
|
50
61
|
}>;
|
|
62
|
+
onAutoHookTrace?: (event: ServerToolAutoHookTraceEvent) => void;
|
|
51
63
|
}
|
|
52
64
|
export type ServerToolFollowupInjectionOp = {
|
|
53
65
|
op: 'preserve_tools';
|
|
@@ -26,7 +26,8 @@ export class AnthropicSseToJsonConverter {
|
|
|
26
26
|
'content_block_delta',
|
|
27
27
|
'content_block_stop',
|
|
28
28
|
'message_delta',
|
|
29
|
-
'message_stop'
|
|
29
|
+
'message_stop',
|
|
30
|
+
'error'
|
|
30
31
|
])
|
|
31
32
|
});
|
|
32
33
|
const builder = createAnthropicResponseBuilder({
|
|
@@ -41,6 +42,10 @@ export class AnthropicSseToJsonConverter {
|
|
|
41
42
|
}
|
|
42
43
|
continue;
|
|
43
44
|
}
|
|
45
|
+
const upstreamError = this.extractAnthropicErrorEventMessage(result.event);
|
|
46
|
+
if (upstreamError) {
|
|
47
|
+
throw new Error(upstreamError);
|
|
48
|
+
}
|
|
44
49
|
if (result.event.protocol !== 'anthropic-messages') {
|
|
45
50
|
continue;
|
|
46
51
|
}
|
|
@@ -98,6 +103,36 @@ export class AnthropicSseToJsonConverter {
|
|
|
98
103
|
context.eventStats.textBlocks += 1;
|
|
99
104
|
}
|
|
100
105
|
}
|
|
106
|
+
extractAnthropicErrorEventMessage(event) {
|
|
107
|
+
const node = event;
|
|
108
|
+
if (node?.type !== 'error') {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const dataNode = node.data;
|
|
112
|
+
if (typeof dataNode === 'string' && dataNode.trim()) {
|
|
113
|
+
return `Anthropic SSE error event: ${dataNode.trim()}`;
|
|
114
|
+
}
|
|
115
|
+
const nestedError = dataNode && typeof dataNode === 'object' ? dataNode.error : undefined;
|
|
116
|
+
const message = (nestedError && typeof nestedError.message === 'string' && nestedError.message.trim()) ||
|
|
117
|
+
(dataNode && typeof dataNode === 'object' && typeof dataNode.message === 'string' && dataNode.message.trim()) ||
|
|
118
|
+
'Anthropic SSE upstream returned an error event';
|
|
119
|
+
const code = (nestedError && typeof nestedError.code === 'string' && nestedError.code.trim()) ||
|
|
120
|
+
(nestedError && typeof nestedError.code === 'number' ? String(nestedError.code) : '') ||
|
|
121
|
+
(dataNode && typeof dataNode === 'object' && typeof dataNode.code === 'string' && dataNode.code.trim()) ||
|
|
122
|
+
(dataNode && typeof dataNode === 'object' && typeof dataNode.code === 'number' ? String(dataNode.code) : '');
|
|
123
|
+
const requestId = (dataNode && typeof dataNode === 'object' && typeof dataNode.request_id === 'string' && dataNode.request_id.trim()) ||
|
|
124
|
+
(dataNode && typeof dataNode === 'object' && typeof dataNode.requestId === 'string' && dataNode.requestId.trim()) ||
|
|
125
|
+
'';
|
|
126
|
+
const parts = ['Anthropic SSE error event'];
|
|
127
|
+
if (code) {
|
|
128
|
+
parts.push(`[${code}]`);
|
|
129
|
+
}
|
|
130
|
+
parts.push(message);
|
|
131
|
+
if (requestId) {
|
|
132
|
+
parts.push(`(request_id=${requestId})`);
|
|
133
|
+
}
|
|
134
|
+
return parts.join(' ');
|
|
135
|
+
}
|
|
101
136
|
wrapError(code, error, requestId) {
|
|
102
137
|
return ErrorUtils.createError(error.message, code, { requestId });
|
|
103
138
|
}
|
|
@@ -136,6 +136,9 @@ export function createAnthropicResponseBuilder(options) {
|
|
|
136
136
|
},
|
|
137
137
|
getResult() {
|
|
138
138
|
if (!state.completed) {
|
|
139
|
+
// 网络提前断开时可能缺失 content_block_stop/message_stop,
|
|
140
|
+
// 先尝试 flush 当前 block,尽最大努力还原已接收内容。
|
|
141
|
+
flushCurrent();
|
|
139
142
|
// 对部分实现(或网络提前关闭)导致缺失 message_stop 的 SSE 流,
|
|
140
143
|
// 只要已经累计到可用内容,就以最佳努力方式返回结果,而不是直接抛错。
|
|
141
144
|
if (state.content.length > 0) {
|
|
@@ -135,6 +135,11 @@ export class ChatSseToJsonConverter {
|
|
|
135
135
|
return 'ping';
|
|
136
136
|
if (v === 'error')
|
|
137
137
|
return 'error';
|
|
138
|
+
// DeepSeek-web style control events (non-content).
|
|
139
|
+
if (v === 'ready' || v === 'update_session' || v === 'title')
|
|
140
|
+
return 'ping';
|
|
141
|
+
if (v === 'finish' || v === 'close')
|
|
142
|
+
return 'chat.done';
|
|
138
143
|
// Legacy aliases
|
|
139
144
|
if (v === 'chunk')
|
|
140
145
|
return 'chat_chunk';
|
|
@@ -235,7 +240,11 @@ export class ChatSseToJsonConverter {
|
|
|
235
240
|
async processChatChunk(event, context) {
|
|
236
241
|
try {
|
|
237
242
|
const payload = typeof event.data === 'string' ? event.data : JSON.stringify(event.data ?? {});
|
|
238
|
-
const
|
|
243
|
+
const parsed = JSON.parse(payload);
|
|
244
|
+
if (this.tryProcessDeepSeekWebPatchEvent(parsed, context)) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const chunk = parsed;
|
|
239
248
|
// 验证chunk格式
|
|
240
249
|
if (context.options.validateChunks) {
|
|
241
250
|
this.validateChatChunk(chunk);
|
|
@@ -259,6 +268,114 @@ export class ChatSseToJsonConverter {
|
|
|
259
268
|
throw ErrorUtils.wrapError(error, 'Failed to parse chat_chunk');
|
|
260
269
|
}
|
|
261
270
|
}
|
|
271
|
+
ensureChoiceBuilder(context, choiceIndex) {
|
|
272
|
+
let choiceBuilder = context.choiceIndexMap.get(choiceIndex);
|
|
273
|
+
if (!choiceBuilder) {
|
|
274
|
+
choiceBuilder = this.createChoiceBuilder(choiceIndex);
|
|
275
|
+
context.choiceIndexMap.set(choiceIndex, choiceBuilder);
|
|
276
|
+
context.currentResponse.choices?.push({
|
|
277
|
+
index: choiceIndex,
|
|
278
|
+
message: {
|
|
279
|
+
role: 'assistant',
|
|
280
|
+
content: ''
|
|
281
|
+
},
|
|
282
|
+
finish_reason: 'stop'
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
return choiceBuilder;
|
|
286
|
+
}
|
|
287
|
+
tryProcessDeepSeekWebPatchEvent(parsed, context) {
|
|
288
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
const payload = parsed;
|
|
292
|
+
// Standard OpenAI chunk path should continue with default processing.
|
|
293
|
+
if (Array.isArray(payload.choices) || payload.object === 'chat.completion.chunk') {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
const path = typeof payload.p === 'string' ? payload.p : '';
|
|
297
|
+
const op = typeof payload.o === 'string' ? payload.o : '';
|
|
298
|
+
const value = payload.v;
|
|
299
|
+
const deepseekState = this.getDeepSeekPatchState(context);
|
|
300
|
+
const isBareContinuation = deepseekState.patchAppendActive && !path && typeof value === 'string';
|
|
301
|
+
const looksLikeDeepSeekPatch = path.startsWith('response/')
|
|
302
|
+
|| typeof payload.request_message_id === 'number'
|
|
303
|
+
|| typeof payload.response_message_id === 'number'
|
|
304
|
+
|| typeof payload.updated_at === 'number'
|
|
305
|
+
|| (value !== null && typeof value === 'object' && !Array.isArray(value))
|
|
306
|
+
|| isBareContinuation;
|
|
307
|
+
if (!looksLikeDeepSeekPatch) {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
if (!context.currentResponse.id) {
|
|
311
|
+
context.currentResponse.id = `chat_${context.requestId}`;
|
|
312
|
+
}
|
|
313
|
+
if (!context.currentResponse.object) {
|
|
314
|
+
context.currentResponse.object = 'chat.completion';
|
|
315
|
+
}
|
|
316
|
+
if (!context.currentResponse.created) {
|
|
317
|
+
context.currentResponse.created = Math.floor(Date.now() / 1000);
|
|
318
|
+
}
|
|
319
|
+
if (!context.currentResponse.model) {
|
|
320
|
+
context.currentResponse.model = context.model;
|
|
321
|
+
}
|
|
322
|
+
const choiceBuilder = this.ensureChoiceBuilder(context, 0);
|
|
323
|
+
choiceBuilder.messageBuilder.role = choiceBuilder.messageBuilder.role || 'assistant';
|
|
324
|
+
if (path === 'response/content' && op === 'APPEND' && typeof value === 'string') {
|
|
325
|
+
deepseekState.patchAppendActive = true;
|
|
326
|
+
choiceBuilder.messageBuilder.content = (choiceBuilder.messageBuilder.content || '') + value;
|
|
327
|
+
choiceBuilder.accumulatedContent += value;
|
|
328
|
+
}
|
|
329
|
+
else if (!path && typeof value === 'string' && value.length > 0) {
|
|
330
|
+
// DeepSeek sometimes continues APPEND content via bare {"v":"..."} frames.
|
|
331
|
+
choiceBuilder.messageBuilder.content = (choiceBuilder.messageBuilder.content || '') + value;
|
|
332
|
+
choiceBuilder.accumulatedContent += value;
|
|
333
|
+
}
|
|
334
|
+
else if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
335
|
+
const inner = value;
|
|
336
|
+
const responseNode = inner.response;
|
|
337
|
+
if (responseNode && typeof responseNode === 'object' && !Array.isArray(responseNode)) {
|
|
338
|
+
const responseRecord = responseNode;
|
|
339
|
+
if (typeof responseRecord.content === 'string' && responseRecord.content.length > 0) {
|
|
340
|
+
choiceBuilder.messageBuilder.content =
|
|
341
|
+
(choiceBuilder.messageBuilder.content || '') + responseRecord.content;
|
|
342
|
+
choiceBuilder.accumulatedContent += responseRecord.content;
|
|
343
|
+
}
|
|
344
|
+
if (typeof responseRecord.status === 'string' && responseRecord.status.toUpperCase() === 'FINISHED') {
|
|
345
|
+
choiceBuilder.finishReason = 'stop';
|
|
346
|
+
choiceBuilder.isCompleted = true;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (path === 'response/accumulated_token_usage' && typeof value === 'number') {
|
|
351
|
+
context.eventStats.totalTokens = value;
|
|
352
|
+
}
|
|
353
|
+
if (path === 'response/status' && typeof value === 'string' && value.toUpperCase() === 'FINISHED') {
|
|
354
|
+
deepseekState.patchAppendActive = false;
|
|
355
|
+
choiceBuilder.finishReason = 'stop';
|
|
356
|
+
choiceBuilder.isCompleted = true;
|
|
357
|
+
context.isCompleted = true;
|
|
358
|
+
}
|
|
359
|
+
this.updateResponseChoice(0, choiceBuilder, context);
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
362
|
+
getDeepSeekPatchState(context) {
|
|
363
|
+
const carrier = context;
|
|
364
|
+
if (!carrier.deepseekPatchState) {
|
|
365
|
+
carrier.deepseekPatchState = { patchAppendActive: false };
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
get patchAppendActive() {
|
|
369
|
+
return Boolean(carrier.deepseekPatchState?.patchAppendActive);
|
|
370
|
+
},
|
|
371
|
+
set patchAppendActive(value) {
|
|
372
|
+
if (!carrier.deepseekPatchState) {
|
|
373
|
+
carrier.deepseekPatchState = {};
|
|
374
|
+
}
|
|
375
|
+
carrier.deepseekPatchState.patchAppendActive = value;
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
}
|
|
262
379
|
/**
|
|
263
380
|
* 处理choice
|
|
264
381
|
*/
|
|
@@ -3,7 +3,7 @@ export const DEFAULT_APPLY_PATCH_NORMALIZE_ACTIONS = [
|
|
|
3
3
|
{ action: 'json_container_patch_fallback' },
|
|
4
4
|
{ action: 'record_text_fields', fields: ['patch'] },
|
|
5
5
|
{ action: 'record_conflict_patch', patchField: 'patch', fileFields: ['file', 'path', 'filepath', 'filename'] },
|
|
6
|
-
{ action: 'record_text_fields', fields: ['diff', 'patchText', 'body', 'input', 'instructions'] },
|
|
6
|
+
{ action: 'record_text_fields', fields: ['diff', 'patchText', 'body', 'input', 'instructions', 'command'] },
|
|
7
7
|
{ action: 'record_raw_envelope', field: '_raw', parseJson: true, maxDepth: 3 },
|
|
8
8
|
{ action: 'record_structured_payload' },
|
|
9
9
|
{ action: 'array_structured_payload' },
|