@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.
Files changed (107) hide show
  1. package/dist/conversion/compat/actions/deepseek-web-request.d.ts +3 -0
  2. package/dist/conversion/compat/actions/deepseek-web-request.js +350 -0
  3. package/dist/conversion/compat/actions/deepseek-web-response.d.ts +3 -0
  4. package/dist/conversion/compat/actions/deepseek-web-response.js +886 -0
  5. package/dist/conversion/compat/actions/gemini-cli-request.js +3 -1
  6. package/dist/conversion/compat/profiles/chat-deepseek-web.json +18 -0
  7. package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +166 -2
  8. package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +169 -0
  9. package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +6 -0
  10. package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +12 -0
  11. package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.js +1 -0
  12. package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +4 -0
  13. package/dist/conversion/hub/pipeline/hub-pipeline.js +365 -144
  14. package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +9 -0
  15. package/dist/conversion/hub/policy/policy-engine.d.ts +2 -0
  16. package/dist/conversion/hub/policy/policy-engine.js +8 -0
  17. package/dist/conversion/hub/process/chat-process.js +466 -16
  18. package/dist/conversion/hub/response/provider-response.js +0 -35
  19. package/dist/conversion/responses/responses-openai-bridge.d.ts +2 -0
  20. package/dist/conversion/responses/responses-openai-bridge.js +166 -8
  21. package/dist/conversion/shared/anthropic-message-utils.js +10 -1
  22. package/dist/conversion/shared/protocol-field-allowlists.d.ts +2 -2
  23. package/dist/conversion/shared/protocol-field-allowlists.js +4 -0
  24. package/dist/conversion/shared/tool-governor.js +102 -0
  25. package/dist/guidance/index.js +17 -0
  26. package/dist/router/virtual-router/bootstrap.js +46 -1
  27. package/dist/router/virtual-router/classifier.js +59 -4
  28. package/dist/router/virtual-router/engine/health/index.js +6 -6
  29. package/dist/router/virtual-router/engine/routing-state/store.js +16 -3
  30. package/dist/router/virtual-router/engine-logging.js +62 -24
  31. package/dist/router/virtual-router/engine-selection/route-utils.js +20 -20
  32. package/dist/router/virtual-router/engine-selection/tier-selection.js +2 -2
  33. package/dist/router/virtual-router/engine.d.ts +3 -1
  34. package/dist/router/virtual-router/engine.js +359 -39
  35. package/dist/router/virtual-router/features.js +2 -1
  36. package/dist/router/virtual-router/pre-command-file-resolver.d.ts +2 -0
  37. package/dist/router/virtual-router/pre-command-file-resolver.js +90 -0
  38. package/dist/router/virtual-router/provider-registry.js +3 -1
  39. package/dist/router/virtual-router/routing-instructions.d.ts +15 -1
  40. package/dist/router/virtual-router/routing-instructions.js +110 -151
  41. package/dist/router/virtual-router/routing-pre-command-actions.d.ts +3 -0
  42. package/dist/router/virtual-router/routing-pre-command-actions.js +26 -0
  43. package/dist/router/virtual-router/routing-pre-command-parser.d.ts +2 -0
  44. package/dist/router/virtual-router/routing-pre-command-parser.js +85 -0
  45. package/dist/router/virtual-router/routing-pre-command-state-codec.d.ts +3 -0
  46. package/dist/router/virtual-router/routing-pre-command-state-codec.js +24 -0
  47. package/dist/router/virtual-router/routing-stop-message-actions.d.ts +2 -0
  48. package/dist/router/virtual-router/routing-stop-message-actions.js +96 -0
  49. package/dist/router/virtual-router/routing-stop-message-parser.d.ts +3 -0
  50. package/dist/router/virtual-router/routing-stop-message-parser.js +142 -0
  51. package/dist/router/virtual-router/routing-stop-message-state-codec.d.ts +4 -0
  52. package/dist/router/virtual-router/routing-stop-message-state-codec.js +85 -0
  53. package/dist/router/virtual-router/sticky-session-store.js +206 -57
  54. package/dist/router/virtual-router/stop-message-stage-template-files.d.ts +12 -0
  55. package/dist/router/virtual-router/stop-message-stage-template-files.js +67 -0
  56. package/dist/router/virtual-router/stop-message-state-sync.d.ts +1 -1
  57. package/dist/router/virtual-router/stop-message-state-sync.js +5 -0
  58. package/dist/router/virtual-router/token-file-scanner.d.ts +9 -0
  59. package/dist/router/virtual-router/token-file-scanner.js +64 -3
  60. package/dist/router/virtual-router/tool-signals.d.ts +5 -0
  61. package/dist/router/virtual-router/tool-signals.js +42 -3
  62. package/dist/router/virtual-router/types.d.ts +19 -1
  63. package/dist/router/virtual-router/types.js +1 -0
  64. package/dist/servertool/clock/config.d.ts +1 -1
  65. package/dist/servertool/clock/config.js +27 -4
  66. package/dist/servertool/clock/state.js +41 -2
  67. package/dist/servertool/clock/task-store.d.ts +2 -2
  68. package/dist/servertool/clock/task-store.js +1 -1
  69. package/dist/servertool/clock/tasks.d.ts +3 -1
  70. package/dist/servertool/clock/tasks.js +209 -18
  71. package/dist/servertool/clock/types.d.ts +17 -0
  72. package/dist/servertool/continue-execution/log.d.ts +3 -0
  73. package/dist/servertool/continue-execution/log.js +13 -0
  74. package/dist/servertool/engine.js +414 -68
  75. package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.js +6 -6
  76. package/dist/servertool/handlers/clock-auto.js +54 -71
  77. package/dist/servertool/handlers/clock.js +121 -6
  78. package/dist/servertool/handlers/continue-execution.d.ts +1 -0
  79. package/dist/servertool/handlers/continue-execution.js +91 -0
  80. package/dist/servertool/handlers/followup-request-builder.js +13 -0
  81. package/dist/servertool/handlers/gemini-empty-reply-continue.js +1 -1
  82. package/dist/servertool/handlers/iflow-model-error-retry.js +1 -1
  83. package/dist/servertool/handlers/recursive-detection-guard.js +1 -1
  84. package/dist/servertool/handlers/stop-message-auto.js +386 -257
  85. package/dist/servertool/handlers/stop-message-stage-policy.d.ts +43 -0
  86. package/dist/servertool/handlers/stop-message-stage-policy.js +684 -0
  87. package/dist/servertool/handlers/vision.js +1 -1
  88. package/dist/servertool/log/progress-file.d.ts +14 -0
  89. package/dist/servertool/log/progress-file.js +88 -0
  90. package/dist/servertool/pre-command-hooks.d.ts +17 -0
  91. package/dist/servertool/pre-command-hooks.js +491 -0
  92. package/dist/servertool/registry.d.ts +23 -6
  93. package/dist/servertool/registry.js +66 -1
  94. package/dist/servertool/server-side-tools.d.ts +1 -0
  95. package/dist/servertool/server-side-tools.js +216 -14
  96. package/dist/servertool/stop-gateway-context.d.ts +14 -0
  97. package/dist/servertool/stop-gateway-context.js +167 -0
  98. package/dist/servertool/stop-message-compare-context.d.ts +24 -0
  99. package/dist/servertool/stop-message-compare-context.js +133 -0
  100. package/dist/servertool/types.d.ts +12 -0
  101. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +1 -0
  102. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +36 -1
  103. package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +3 -0
  104. package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +3 -0
  105. package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +118 -1
  106. package/dist/tools/apply-patch/args-normalizer/default-actions.js +1 -1
  107. 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';
@@ -12,6 +12,7 @@ export declare class AnthropicSseToJsonConverter {
12
12
  private createContext;
13
13
  private chunkStrings;
14
14
  private updateStats;
15
+ private extractAnthropicErrorEventMessage;
15
16
  private wrapError;
16
17
  }
17
18
  export {};
@@ -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) {
@@ -39,6 +39,9 @@ export declare class ChatSseToJsonConverter {
39
39
  * 处理chat_chunk事件
40
40
  */
41
41
  private processChatChunk;
42
+ private ensureChoiceBuilder;
43
+ private tryProcessDeepSeekWebPatchEvent;
44
+ private getDeepSeekPatchState;
42
45
  /**
43
46
  * 处理choice
44
47
  */
@@ -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 chunk = JSON.parse(payload);
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' },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsonstudio/llms",
3
- "version": "0.6.1739",
3
+ "version": "0.6.1890",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",