@jsonstudio/llms 0.6.954 → 0.6.1172

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 (134) hide show
  1. package/dist/conversion/hub/operation-table/operation-table-runner.d.ts +18 -0
  2. package/dist/conversion/hub/operation-table/operation-table-runner.js +158 -0
  3. package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.d.ts +8 -0
  4. package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +303 -0
  5. package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.d.ts +8 -0
  6. package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +413 -0
  7. package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.d.ts +7 -0
  8. package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +841 -0
  9. package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.d.ts +21 -0
  10. package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +535 -0
  11. package/dist/conversion/hub/ops/operations.d.ts +19 -0
  12. package/dist/conversion/hub/ops/operations.js +126 -0
  13. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +9 -0
  14. package/dist/conversion/hub/pipeline/hub-pipeline.js +489 -19
  15. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +6 -0
  16. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +11 -0
  17. package/dist/conversion/hub/policy/policy-engine.js +41 -9
  18. package/dist/conversion/hub/policy/protocol-spec.d.ts +25 -0
  19. package/dist/conversion/hub/policy/protocol-spec.js +73 -23
  20. package/dist/conversion/hub/process/chat-process.js +252 -41
  21. package/dist/conversion/hub/response/provider-response.js +175 -2
  22. package/dist/conversion/hub/response/response-runtime.js +1 -1
  23. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.d.ts +1 -8
  24. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +1 -365
  25. package/dist/conversion/hub/semantic-mappers/chat-mapper.d.ts +1 -8
  26. package/dist/conversion/hub/semantic-mappers/chat-mapper.js +1 -467
  27. package/dist/conversion/hub/semantic-mappers/gemini-mapper.d.ts +1 -7
  28. package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +1 -903
  29. package/dist/conversion/hub/semantic-mappers/responses-mapper.d.ts +1 -21
  30. package/dist/conversion/hub/semantic-mappers/responses-mapper.js +1 -593
  31. package/dist/conversion/hub/tool-surface/tool-surface-engine.d.ts +18 -0
  32. package/dist/conversion/hub/tool-surface/tool-surface-engine.js +571 -0
  33. package/dist/conversion/responses/responses-openai-bridge.js +14 -2
  34. package/dist/conversion/shared/bridge-message-utils.js +2 -8
  35. package/dist/conversion/shared/bridge-policies.js +5 -105
  36. package/dist/conversion/shared/gemini-tool-utils.js +89 -15
  37. package/dist/conversion/shared/protocol-field-allowlists.d.ts +7 -0
  38. package/dist/conversion/shared/protocol-field-allowlists.js +145 -0
  39. package/dist/conversion/shared/reasoning-tool-normalizer.js +4 -2
  40. package/dist/conversion/shared/snapshot-hooks.js +166 -3
  41. package/dist/conversion/shared/text-markup-normalizer.d.ts +2 -0
  42. package/dist/conversion/shared/text-markup-normalizer.js +345 -9
  43. package/dist/conversion/shared/thought-signature-validator.d.ts +52 -0
  44. package/dist/conversion/shared/thought-signature-validator.js +170 -0
  45. package/dist/conversion/shared/tool-argument-repairer.d.ts +39 -0
  46. package/dist/conversion/shared/tool-argument-repairer.js +56 -0
  47. package/dist/conversion/shared/tool-call-id-manager.d.ts +113 -0
  48. package/dist/conversion/shared/tool-call-id-manager.js +231 -0
  49. package/dist/conversion/shared/tool-canonicalizer.js +2 -11
  50. package/dist/router/virtual-router/bootstrap.js +70 -5
  51. package/dist/router/virtual-router/context-advisor.d.ts +4 -0
  52. package/dist/router/virtual-router/context-advisor.js +3 -0
  53. package/dist/router/virtual-router/context-weighted.d.ts +31 -0
  54. package/dist/router/virtual-router/context-weighted.js +54 -0
  55. package/dist/router/virtual-router/engine-selection.js +284 -47
  56. package/dist/router/virtual-router/engine.d.ts +3 -0
  57. package/dist/router/virtual-router/engine.js +142 -33
  58. package/dist/router/virtual-router/health-weighted.d.ts +25 -0
  59. package/dist/router/virtual-router/health-weighted.js +63 -0
  60. package/dist/router/virtual-router/load-balancer.d.ts +2 -0
  61. package/dist/router/virtual-router/load-balancer.js +45 -16
  62. package/dist/router/virtual-router/routing-instructions.js +17 -1
  63. package/dist/router/virtual-router/sticky-session-store.js +136 -24
  64. package/dist/router/virtual-router/stop-message-file-resolver.d.ts +1 -0
  65. package/dist/router/virtual-router/stop-message-file-resolver.js +74 -0
  66. package/dist/router/virtual-router/stop-message-state-sync.d.ts +15 -0
  67. package/dist/router/virtual-router/stop-message-state-sync.js +57 -0
  68. package/dist/router/virtual-router/types.d.ts +98 -0
  69. package/dist/servertool/clock/config.d.ts +7 -0
  70. package/dist/servertool/clock/config.js +27 -0
  71. package/dist/servertool/clock/daemon.d.ts +3 -0
  72. package/dist/servertool/clock/daemon.js +79 -0
  73. package/dist/servertool/clock/io.d.ts +2 -0
  74. package/dist/servertool/clock/io.js +13 -0
  75. package/dist/servertool/clock/paths.d.ts +4 -0
  76. package/dist/servertool/clock/paths.js +25 -0
  77. package/dist/servertool/clock/session-store.d.ts +3 -0
  78. package/dist/servertool/clock/session-store.js +56 -0
  79. package/dist/servertool/clock/state.d.ts +5 -0
  80. package/dist/servertool/clock/state.js +62 -0
  81. package/dist/servertool/clock/task-store.d.ts +5 -0
  82. package/dist/servertool/clock/task-store.js +4 -0
  83. package/dist/servertool/clock/tasks.d.ts +17 -0
  84. package/dist/servertool/clock/tasks.js +221 -0
  85. package/dist/servertool/clock/types.d.ts +36 -0
  86. package/dist/servertool/clock/types.js +1 -0
  87. package/dist/servertool/engine.d.ts +2 -0
  88. package/dist/servertool/engine.js +161 -7
  89. package/dist/servertool/followup-shadow.d.ts +16 -0
  90. package/dist/servertool/followup-shadow.js +145 -0
  91. package/dist/servertool/handlers/apply-patch-guard.js +1 -265
  92. package/dist/servertool/handlers/clock-auto.d.ts +1 -0
  93. package/dist/servertool/handlers/clock-auto.js +160 -0
  94. package/dist/servertool/handlers/clock.d.ts +1 -0
  95. package/dist/servertool/handlers/clock.js +197 -0
  96. package/dist/servertool/handlers/exec-command-guard.js +7 -555
  97. package/dist/servertool/handlers/followup-request-builder.d.ts +15 -7
  98. package/dist/servertool/handlers/followup-request-builder.js +248 -28
  99. package/dist/servertool/handlers/gemini-empty-reply-continue.js +62 -169
  100. package/dist/servertool/handlers/iflow-model-error-retry.js +18 -28
  101. package/dist/servertool/handlers/recursive-detection-guard.d.ts +1 -0
  102. package/dist/servertool/handlers/recursive-detection-guard.js +333 -0
  103. package/dist/servertool/handlers/stop-message-auto.js +47 -175
  104. package/dist/servertool/handlers/vision.d.ts +7 -1
  105. package/dist/servertool/handlers/vision.js +61 -117
  106. package/dist/servertool/handlers/web-search.d.ts +7 -1
  107. package/dist/servertool/handlers/web-search.js +122 -105
  108. package/dist/servertool/reenter-backend.d.ts +23 -0
  109. package/dist/servertool/reenter-backend.js +18 -0
  110. package/dist/servertool/server-side-tools.d.ts +3 -2
  111. package/dist/servertool/server-side-tools.js +64 -10
  112. package/dist/servertool/types.d.ts +92 -3
  113. package/dist/sse/json-to-sse/event-generators/responses.js +3 -21
  114. package/dist/sse/shared/serializers/responses-event-serializer.d.ts +8 -0
  115. package/dist/sse/shared/serializers/responses-event-serializer.js +19 -0
  116. package/dist/sse/shared/writer.js +24 -7
  117. package/dist/tools/apply-patch/execution-capturer.js +3 -1
  118. package/dist/tools/apply-patch/json/parse-loose.d.ts +3 -0
  119. package/dist/tools/apply-patch/json/parse-loose.js +139 -0
  120. package/dist/tools/apply-patch/patch-text/context-diff.d.ts +1 -0
  121. package/dist/tools/apply-patch/patch-text/context-diff.js +173 -0
  122. package/dist/tools/apply-patch/patch-text/git-diff.d.ts +1 -0
  123. package/dist/tools/apply-patch/patch-text/git-diff.js +138 -0
  124. package/dist/tools/apply-patch/patch-text/looks-like-patch.d.ts +1 -0
  125. package/dist/tools/apply-patch/patch-text/looks-like-patch.js +13 -0
  126. package/dist/tools/apply-patch/patch-text/normalize.d.ts +3 -0
  127. package/dist/tools/apply-patch/patch-text/normalize.js +262 -0
  128. package/dist/tools/apply-patch/structured/coercion.d.ts +3 -0
  129. package/dist/tools/apply-patch/structured/coercion.js +82 -0
  130. package/dist/tools/apply-patch/validation/shared.d.ts +3 -0
  131. package/dist/tools/apply-patch/validation/shared.js +6 -0
  132. package/dist/tools/apply-patch/validator.d.ts +2 -2
  133. package/dist/tools/apply-patch/validator.js +6 -556
  134. package/package.json +1 -1
@@ -1,12 +1,15 @@
1
1
  import { getServerToolHandler, listAutoServerToolHandlers } from './registry.js';
2
2
  import { ProviderProtocolError } from '../conversion/shared/errors.js';
3
- import './handlers/web-search.js';
4
- import './handlers/vision.js';
3
+ import { executeWebSearchBackendPlan } from './handlers/web-search.js';
4
+ import { executeVisionBackendPlan } from './handlers/vision.js';
5
5
  import './handlers/iflow-model-error-retry.js';
6
6
  import './handlers/gemini-empty-reply-continue.js';
7
7
  import './handlers/stop-message-auto.js';
8
+ import './handlers/clock.js';
9
+ import './handlers/clock-auto.js';
8
10
  import './handlers/exec-command-guard.js';
9
11
  import './handlers/apply-patch-guard.js';
12
+ import './handlers/recursive-detection-guard.js';
10
13
  export async function runServerSideToolEngine(options) {
11
14
  const base = asObject(options.chatResponse);
12
15
  if (!base) {
@@ -20,14 +23,21 @@ export async function runServerSideToolEngine(options) {
20
23
  base,
21
24
  toolCalls,
22
25
  adapterContext: options.adapterContext,
23
- options
26
+ requestId: options.requestId,
27
+ entryEndpoint: options.entryEndpoint,
28
+ providerProtocol: options.providerProtocol,
29
+ capabilities: {
30
+ reenterPipeline: typeof options.reenterPipeline === 'function',
31
+ providerInvoker: typeof options.providerInvoker === 'function'
32
+ }
24
33
  };
25
34
  for (const toolCall of toolCalls) {
26
35
  const entry = getServerToolHandler(toolCall.name);
27
36
  if (!entry || entry.trigger !== 'tool_call')
28
37
  continue;
29
38
  const ctx = { ...contextBase, toolCall };
30
- const result = await runHandler(entry.handler, ctx);
39
+ const planned = await runHandler(entry.handler, ctx);
40
+ const result = planned ? await materializePlannedResult(planned, options) : null;
31
41
  if (result) {
32
42
  return {
33
43
  mode: 'tool_flow',
@@ -37,7 +47,8 @@ export async function runServerSideToolEngine(options) {
37
47
  }
38
48
  }
39
49
  for (const entry of listAutoServerToolHandlers()) {
40
- const result = await runHandler(entry.handler, contextBase);
50
+ const planned = await runHandler(entry.handler, contextBase);
51
+ const result = planned ? await materializePlannedResult(planned, options) : null;
41
52
  if (result) {
42
53
  return {
43
54
  mode: 'tool_flow',
@@ -62,9 +73,9 @@ async function runHandler(handler, ctx) {
62
73
  category: 'INTERNAL_ERROR',
63
74
  details: {
64
75
  toolName,
65
- requestId: ctx.options?.requestId,
66
- entryEndpoint: ctx.options?.entryEndpoint,
67
- providerProtocol: ctx.options?.providerProtocol,
76
+ requestId: ctx.requestId,
77
+ entryEndpoint: ctx.entryEndpoint,
78
+ providerProtocol: ctx.providerProtocol,
68
79
  error: message
69
80
  }
70
81
  });
@@ -73,6 +84,27 @@ async function runHandler(handler, ctx) {
73
84
  throw wrapped;
74
85
  }
75
86
  }
87
+ async function materializePlannedResult(planned, options) {
88
+ if (planned && typeof planned === 'object' && !Array.isArray(planned) && typeof planned.finalize === 'function') {
89
+ const plan = planned;
90
+ const backendResult = plan.backend ? await executeBackendPlan(plan.backend, options) : undefined;
91
+ return await plan.finalize({ ...(backendResult ? { backendResult } : {}) });
92
+ }
93
+ return planned;
94
+ }
95
+ async function executeBackendPlan(plan, options) {
96
+ if (!plan)
97
+ return undefined;
98
+ if (plan.kind === 'vision_analysis') {
99
+ if (!options.reenterPipeline)
100
+ return undefined;
101
+ return await executeVisionBackendPlan({ plan, options });
102
+ }
103
+ if (plan.kind === 'web_search') {
104
+ return await executeWebSearchBackendPlan({ plan, options });
105
+ }
106
+ return undefined;
107
+ }
76
108
  export function extractToolCalls(chatResponse) {
77
109
  const choices = getArray(chatResponse.choices);
78
110
  const calls = [];
@@ -89,9 +121,31 @@ export function extractToolCalls(chatResponse) {
89
121
  if (!tc)
90
122
  continue;
91
123
  const id = typeof tc.id === 'string' && tc.id.trim() ? tc.id.trim() : '';
92
- const fn = asObject(tc.function);
124
+ const fn = asObject(tc.function) ??
125
+ asObject(tc.functionCall) ??
126
+ asObject(tc.function_call);
93
127
  const name = fn && typeof fn.name === 'string' && fn.name.trim() ? fn.name.trim() : '';
94
- const args = fn && typeof fn.arguments === 'string' ? fn.arguments : '';
128
+ const rawArgs = (fn ? fn.arguments : undefined) ??
129
+ (fn ? fn.args : undefined) ??
130
+ (fn ? fn.input : undefined) ??
131
+ tc.arguments ??
132
+ tc.args ??
133
+ tc.input;
134
+ let args = '';
135
+ if (typeof rawArgs === 'string') {
136
+ args = rawArgs;
137
+ }
138
+ else if (rawArgs && typeof rawArgs === 'object') {
139
+ try {
140
+ args = JSON.stringify(rawArgs);
141
+ }
142
+ catch {
143
+ args = '';
144
+ }
145
+ }
146
+ else if (rawArgs !== undefined && rawArgs !== null) {
147
+ args = String(rawArgs);
148
+ }
95
149
  if (!id || !name)
96
150
  continue;
97
151
  calls.push({ id, name, arguments: args });
@@ -49,11 +49,94 @@ export interface ServerSideToolEngineOptions {
49
49
  format?: string;
50
50
  }>;
51
51
  }
52
- export interface ServerToolFollowupPlan {
52
+ export type ServerToolFollowupInjectionOp = {
53
+ op: 'append_assistant_message';
54
+ required?: boolean;
55
+ } | {
56
+ op: 'append_tool_messages_from_tool_outputs';
57
+ required?: boolean;
58
+ } | {
59
+ op: 'inject_system_text';
60
+ text: string;
61
+ } | {
62
+ op: 'append_user_text';
63
+ text: string;
64
+ } | {
65
+ op: 'drop_tool_by_name';
66
+ name: string;
67
+ } | {
68
+ op: 'inject_vision_summary';
69
+ summary: string;
70
+ } | {
71
+ op: 'trim_openai_messages';
72
+ maxNonSystemMessages: number;
73
+ };
74
+ export type ServerToolFollowupInjectionPlan = {
75
+ ops: ServerToolFollowupInjectionOp[];
76
+ };
77
+ export type ServerToolFollowupPlan = {
53
78
  requestIdSuffix: string;
54
79
  payload: JsonObject;
55
80
  metadata?: JsonObject;
56
81
  entryEndpoint?: string;
82
+ } | {
83
+ requestIdSuffix: string;
84
+ injection: ServerToolFollowupInjectionPlan;
85
+ metadata?: JsonObject;
86
+ entryEndpoint?: string;
87
+ };
88
+ export type ServerToolBackendPlan = {
89
+ kind: 'vision_analysis';
90
+ requestIdSuffix: string;
91
+ entryEndpoint: string;
92
+ payload: JsonObject;
93
+ } | {
94
+ kind: 'web_search';
95
+ requestIdSuffix: string;
96
+ query: string;
97
+ recency?: string;
98
+ resultCount: number;
99
+ engines: {
100
+ id: string;
101
+ providerKey: string;
102
+ description?: string;
103
+ default?: boolean;
104
+ serverToolsDisabled?: boolean;
105
+ searchEngineList?: string[];
106
+ }[];
107
+ };
108
+ export type ServerToolBackendResult = {
109
+ kind: 'vision_analysis';
110
+ response: {
111
+ body?: JsonObject;
112
+ __sse_responses?: unknown;
113
+ format?: string;
114
+ };
115
+ } | {
116
+ kind: 'web_search';
117
+ chosenEngine?: {
118
+ id: string;
119
+ providerKey: string;
120
+ };
121
+ result: {
122
+ ok: boolean;
123
+ summary: string;
124
+ hits: {
125
+ title?: string;
126
+ link: string;
127
+ media?: string;
128
+ publish_date?: string;
129
+ content?: string;
130
+ refer?: string;
131
+ }[];
132
+ };
133
+ };
134
+ export interface ServerToolHandlerPlan {
135
+ flowId: string;
136
+ backend?: ServerToolBackendPlan;
137
+ finalize: (args: {
138
+ backendResult?: ServerToolBackendResult;
139
+ }) => Promise<ServerToolHandlerResult | null>;
57
140
  }
58
141
  export interface ServerToolExecution {
59
142
  flowId: string;
@@ -81,7 +164,13 @@ export interface ServerToolHandlerContext {
81
164
  toolCall?: ToolCall;
82
165
  toolCalls: ToolCall[];
83
166
  adapterContext: AdapterContext;
84
- options: ServerSideToolEngineOptions;
167
+ requestId: string;
168
+ entryEndpoint: string;
169
+ providerProtocol: string;
170
+ capabilities: {
171
+ reenterPipeline: boolean;
172
+ providerInvoker: boolean;
173
+ };
85
174
  }
86
175
  export interface ServerToolHandlerResult {
87
176
  chatResponse: JsonObject;
@@ -91,5 +180,5 @@ export interface ServerToolHandlerResult {
91
180
  * ServerToolHandler:统一的 ServerTool handler 接口。
92
181
  * 后续 web_search / vision / 其它工具都会以 handler 形式挂载到注册表。
93
182
  */
94
- export type ServerToolHandler = (ctx: ServerToolHandlerContext) => Promise<ServerToolHandlerResult | null>;
183
+ export type ServerToolHandler = (ctx: ServerToolHandlerContext) => Promise<ServerToolHandlerPlan | null>;
95
184
  export type { JsonObject, JsonValue } from '../conversion/hub/types/json.js';
@@ -512,30 +512,12 @@ export function buildReasoningDoneEvent(reasoning, context, config = DEFAULT_RES
512
512
  */
513
513
  export function buildOutputItemDoneEvent(outputItem, context, config = DEFAULT_RESPONSES_EVENT_GENERATOR_CONFIG) {
514
514
  const baseEvent = createBaseEvent(context, config);
515
+ // NOTE: Codex CLI expects `output_item.done` to contain a fully-formed output item
516
+ // (e.g. message includes role/content). A minimal `{id,type,status}` breaks parsing.
515
517
  const itemDescriptor = {
516
- id: outputItem.id,
517
- type: outputItem.type,
518
+ ...outputItem,
518
519
  status: 'completed'
519
520
  };
520
- if (outputItem.name) {
521
- itemDescriptor.name = outputItem.name;
522
- }
523
- if (outputItem.arguments) {
524
- itemDescriptor.arguments = outputItem.arguments;
525
- }
526
- if (outputItem.call_id) {
527
- itemDescriptor.call_id = outputItem.call_id;
528
- }
529
- if (outputItem.type === 'function_call_output') {
530
- const result = outputItem;
531
- if (result.call_id) {
532
- itemDescriptor.call_id = result.call_id;
533
- }
534
- if (result.tool_call_id) {
535
- itemDescriptor.tool_call_id = result.tool_call_id;
536
- }
537
- itemDescriptor.output = result.output;
538
- }
539
521
  return {
540
522
  type: 'response.output_item.done',
541
523
  timestamp: baseEvent.timestamp,
@@ -55,6 +55,14 @@ export declare class ResponsesEventSerializer implements EventSerializer<Respons
55
55
  * 序列化response.output_item.done事件
56
56
  */
57
57
  private serializeOutputItemDone;
58
+ /**
59
+ * 序列化response.output_text.delta事件
60
+ */
61
+ private serializeOutputTextDelta;
62
+ /**
63
+ * 序列化response.output_text.done事件
64
+ */
65
+ private serializeOutputTextDone;
58
66
  /**
59
67
  * 序列化response.function_call_arguments.delta事件
60
68
  */
@@ -28,6 +28,10 @@ export class ResponsesEventSerializer {
28
28
  return this.serializeOutputItemAdded(event);
29
29
  case 'response.output_item.done':
30
30
  return this.serializeOutputItemDone(event);
31
+ case 'response.output_text.delta':
32
+ return this.serializeOutputTextDelta(event);
33
+ case 'response.output_text.done':
34
+ return this.serializeOutputTextDone(event);
31
35
  case 'response.function_call_arguments.delta':
32
36
  return this.serializeFunctionCallArgumentsDelta(event);
33
37
  case 'response.function_call_arguments.done':
@@ -43,6 +47,9 @@ export class ResponsesEventSerializer {
43
47
  case 'response.cancelled':
44
48
  return this.serializeResponseCancelled(event);
45
49
  default:
50
+ if (typeof event.type === 'string' && event.type.startsWith('response.')) {
51
+ return this.buildSSEEvent(event.type, event.data, event.timestamp, event.sequenceNumber);
52
+ }
46
53
  throw new Error(`Unsupported ResponsesSseEvent type: ${event.type}`);
47
54
  }
48
55
  }
@@ -159,6 +166,18 @@ export class ResponsesEventSerializer {
159
166
  serializeOutputItemDone(event) {
160
167
  return this.buildSSEEvent('response.output_item.done', event.data, event.timestamp, event.sequenceNumber);
161
168
  }
169
+ /**
170
+ * 序列化response.output_text.delta事件
171
+ */
172
+ serializeOutputTextDelta(event) {
173
+ return this.buildSSEEvent('response.output_text.delta', event.data, event.timestamp, event.sequenceNumber);
174
+ }
175
+ /**
176
+ * 序列化response.output_text.done事件
177
+ */
178
+ serializeOutputTextDone(event) {
179
+ return this.buildSSEEvent('response.output_text.done', event.data, event.timestamp, event.sequenceNumber);
180
+ }
162
181
  /**
163
182
  * 序列化response.function_call_arguments.delta事件
164
183
  */
@@ -156,14 +156,31 @@ export class StreamWriter {
156
156
  catch {
157
157
  // ignore and fallback
158
158
  }
159
+ const eventType = String(event.type ?? 'response.unknown');
159
160
  const rawData = event.data;
160
- const dataPayload = typeof rawData === 'string'
161
- ? rawData
162
- : JSON.stringify({
163
- type: event.type,
164
- ...(rawData ?? {})
165
- });
166
- return `event: ${event.type}\ndata: ${dataPayload}\n\n`;
161
+ const timestamp = typeof event.timestamp === 'number' ? event.timestamp : undefined;
162
+ const sequenceNumber = typeof event.sequenceNumber === 'number' ? event.sequenceNumber : undefined;
163
+ let wire = `event: ${eventType}\n`;
164
+ if (rawData === '[DONE]') {
165
+ wire += 'data: [DONE]\n';
166
+ }
167
+ else if (typeof rawData === 'string') {
168
+ wire += `data: ${rawData}\n`;
169
+ }
170
+ else {
171
+ const payload = rawData && typeof rawData === 'object' ? { ...rawData } : {};
172
+ if (!Object.prototype.hasOwnProperty.call(payload, 'type'))
173
+ payload.type = eventType;
174
+ if (sequenceNumber !== undefined && !Object.prototype.hasOwnProperty.call(payload, 'sequence_number')) {
175
+ payload.sequence_number = sequenceNumber;
176
+ }
177
+ wire += `data: ${JSON.stringify(payload)}\n`;
178
+ }
179
+ if (timestamp !== undefined) {
180
+ wire += `id: ${timestamp}\n`;
181
+ }
182
+ wire += '\n';
183
+ return wire;
167
184
  }
168
185
  /**
169
186
  * 异步写入事件流
@@ -112,6 +112,8 @@ export function captureApplyPatchExecutionFailuresFromProcessedRequest(processed
112
112
  const entryEndpoint = typeof metadata?.originalEndpoint === 'string' ? metadata.originalEndpoint : undefined;
113
113
  const providerKey = typeof metadata?.providerKey === 'string' ? metadata.providerKey : undefined;
114
114
  const model = typeof anyReq?.model === 'string' ? anyReq.model : undefined;
115
+ const applyPatchToolMode = typeof metadata?.applyPatchToolMode === 'string' ? String(metadata.applyPatchToolMode).trim().toLowerCase() : '';
116
+ const resolvedMode = applyPatchToolMode === 'schema' ? 'schema' : 'freeform';
115
117
  const toolCallArgsById = new Map();
116
118
  for (const msg of messages) {
117
119
  if (!msg || typeof msg !== 'object')
@@ -146,7 +148,7 @@ export function captureApplyPatchExecutionFailuresFromProcessedRequest(processed
146
148
  providerKey,
147
149
  model,
148
150
  source: 'req_process_stage1_tool_governance',
149
- meta: { applyPatchToolMode: 'freeform' },
151
+ meta: { applyPatchToolMode: resolvedMode },
150
152
  toolCallId,
151
153
  toolCallArgs
152
154
  });
@@ -0,0 +1,3 @@
1
+ declare const tryParseJson: (value: unknown) => unknown;
2
+ declare const tryParseJsonLoose: (value: unknown) => unknown;
3
+ export { tryParseJson, tryParseJsonLoose };
@@ -0,0 +1,139 @@
1
+ const tryParseJson = (value) => {
2
+ if (typeof value !== 'string')
3
+ return undefined;
4
+ const trimmed = value.trim();
5
+ if (!trimmed)
6
+ return undefined;
7
+ if (!(trimmed.startsWith('{') || trimmed.startsWith('[')))
8
+ return undefined;
9
+ try {
10
+ return JSON.parse(trimmed);
11
+ }
12
+ catch {
13
+ return undefined;
14
+ }
15
+ };
16
+ const escapeUnescapedQuotesInJsonStrings = (input) => {
17
+ // Best-effort: when JSON is almost valid but contains unescaped `"` inside string values
18
+ // (e.g. JSX snippets like className="..."), escape quotes that are not followed by a
19
+ // valid JSON token delimiter. Deterministic; does not attempt to fix structural issues.
20
+ let out = '';
21
+ let inString = false;
22
+ let escaped = false;
23
+ for (let i = 0; i < input.length; i += 1) {
24
+ const ch = input[i] ?? '';
25
+ if (!inString) {
26
+ if (ch === '"') {
27
+ inString = true;
28
+ escaped = false;
29
+ }
30
+ out += ch;
31
+ continue;
32
+ }
33
+ if (escaped) {
34
+ out += ch;
35
+ escaped = false;
36
+ continue;
37
+ }
38
+ if (ch === '\\') {
39
+ out += ch;
40
+ escaped = true;
41
+ continue;
42
+ }
43
+ if (ch === '"') {
44
+ let j = i + 1;
45
+ while (j < input.length && /\s/.test(input[j] ?? ''))
46
+ j += 1;
47
+ const next = j < input.length ? input[j] : '';
48
+ if (next === '' || next === ':' || next === ',' || next === '}' || next === ']') {
49
+ inString = false;
50
+ out += ch;
51
+ }
52
+ else {
53
+ out += '\\"';
54
+ }
55
+ continue;
56
+ }
57
+ out += ch;
58
+ }
59
+ return out;
60
+ };
61
+ const balanceJsonContainers = (input) => {
62
+ // Best-effort bracket/brace balancing for JSON-like strings.
63
+ // Only operates outside string literals. When encountering a closing token that doesn't
64
+ // match the current stack top, inserts the missing closer(s) to recover.
65
+ let out = '';
66
+ let inString = false;
67
+ let escaped = false;
68
+ const stack = [];
69
+ const closeFor = (open) => (open === '{' ? '}' : ']');
70
+ for (let i = 0; i < input.length; i += 1) {
71
+ const ch = input[i] ?? '';
72
+ if (inString) {
73
+ out += ch;
74
+ if (escaped) {
75
+ escaped = false;
76
+ continue;
77
+ }
78
+ if (ch === '\\') {
79
+ escaped = true;
80
+ continue;
81
+ }
82
+ if (ch === '"') {
83
+ inString = false;
84
+ }
85
+ continue;
86
+ }
87
+ if (ch === '"') {
88
+ inString = true;
89
+ out += ch;
90
+ continue;
91
+ }
92
+ if (ch === '{' || ch === '[') {
93
+ stack.push(ch);
94
+ out += ch;
95
+ continue;
96
+ }
97
+ if (ch === '}' || ch === ']') {
98
+ const expectedOpen = ch === '}' ? '{' : '[';
99
+ while (stack.length && stack[stack.length - 1] !== expectedOpen) {
100
+ const open = stack.pop();
101
+ out += closeFor(open);
102
+ }
103
+ if (stack.length && stack[stack.length - 1] === expectedOpen) {
104
+ stack.pop();
105
+ }
106
+ out += ch;
107
+ continue;
108
+ }
109
+ out += ch;
110
+ }
111
+ while (stack.length) {
112
+ const open = stack.pop();
113
+ out += closeFor(open);
114
+ }
115
+ return out;
116
+ };
117
+ const tryParseJsonLoose = (value) => {
118
+ const parsed = tryParseJson(value);
119
+ if (parsed !== undefined)
120
+ return parsed;
121
+ if (typeof value !== 'string')
122
+ return undefined;
123
+ const trimmed = value.trim();
124
+ if (!trimmed)
125
+ return undefined;
126
+ if (!(trimmed.startsWith('{') || trimmed.startsWith('[')))
127
+ return undefined;
128
+ let repaired = escapeUnescapedQuotesInJsonStrings(trimmed);
129
+ repaired = balanceJsonContainers(repaired);
130
+ if (!repaired || repaired === trimmed)
131
+ return undefined;
132
+ try {
133
+ return JSON.parse(repaired);
134
+ }
135
+ catch {
136
+ return undefined;
137
+ }
138
+ };
139
+ export { tryParseJson, tryParseJsonLoose };
@@ -0,0 +1 @@
1
+ export declare const convertContextDiffToApplyPatch: (text: string) => string | null;