@jsonstudio/llms 0.6.1399 → 0.6.1403

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 (72) hide show
  1. package/dist/conversion/codecs/gemini-openai-codec.d.ts +1 -3
  2. package/dist/conversion/codecs/gemini-openai-codec.js +4 -10
  3. package/dist/conversion/compat/actions/gemini-cli-request.d.ts +2 -0
  4. package/dist/conversion/compat/actions/gemini-cli-request.js +490 -0
  5. package/dist/conversion/compat/profiles/chat-gemini-cli.json +27 -0
  6. package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +76 -348
  7. package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +6 -0
  8. package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +2 -0
  9. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +95 -3
  10. package/dist/conversion/hub/pipeline/hub-pipeline.js +1365 -19
  11. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +22 -0
  12. package/dist/conversion/hub/policy/policy-engine.js +50 -3
  13. package/dist/conversion/hub/process/chat-process.js +5 -146
  14. package/dist/conversion/hub/response/provider-response.js +11 -10
  15. package/dist/conversion/hub/response/response-mappers.d.ts +1 -3
  16. package/dist/conversion/hub/response/response-mappers.js +2 -20
  17. package/dist/conversion/hub/tool-surface/tool-surface-engine.js +2 -1
  18. package/dist/conversion/responses/responses-openai-bridge.js +4 -3
  19. package/dist/conversion/shared/gemini-tool-utils.d.ts +1 -6
  20. package/dist/conversion/shared/gemini-tool-utils.js +164 -542
  21. package/dist/conversion/shared/mcp-injection.js +29 -0
  22. package/dist/conversion/shared/openai-message-normalize.js +3 -17
  23. package/dist/filters/special/request-tool-list-filter.js +21 -13
  24. package/dist/filters/special/tool-filter-hooks.js +60 -3
  25. package/dist/router/virtual-router/bootstrap.js +8 -6
  26. package/dist/router/virtual-router/engine-health.d.ts +1 -1
  27. package/dist/router/virtual-router/engine-health.js +110 -11
  28. package/dist/router/virtual-router/engine-selection/alias-selection.d.ts +0 -15
  29. package/dist/router/virtual-router/engine-selection/alias-selection.js +4 -85
  30. package/dist/router/virtual-router/engine-selection/route-utils.js +6 -12
  31. package/dist/router/virtual-router/engine-selection/tier-selection-select.js +17 -40
  32. package/dist/router/virtual-router/engine-selection/tier-selection.js +2 -5
  33. package/dist/router/virtual-router/engine.js +6 -21
  34. package/dist/router/virtual-router/types.d.ts +1 -14
  35. package/dist/servertool/clock/config.d.ts +1 -1
  36. package/dist/servertool/clock/config.js +5 -9
  37. package/dist/servertool/engine.js +11 -88
  38. package/dist/servertool/handlers/gemini-empty-reply-continue.js +1 -2
  39. package/dist/sse/sse-to-json/builders/response-builder.js +0 -16
  40. package/package.json +1 -1
  41. package/dist/conversion/hub/pipeline/hub-pipeline/adapter-context.d.ts +0 -10
  42. package/dist/conversion/hub/pipeline/hub-pipeline/adapter-context.js +0 -142
  43. package/dist/conversion/hub/pipeline/hub-pipeline/anthropic-alias-map.d.ts +0 -6
  44. package/dist/conversion/hub/pipeline/hub-pipeline/anthropic-alias-map.js +0 -79
  45. package/dist/conversion/hub/pipeline/hub-pipeline/apply-patch-tool-mode.d.ts +0 -3
  46. package/dist/conversion/hub/pipeline/hub-pipeline/apply-patch-tool-mode.js +0 -46
  47. package/dist/conversion/hub/pipeline/hub-pipeline/execute-chat-process-entry.d.ts +0 -8
  48. package/dist/conversion/hub/pipeline/hub-pipeline/execute-chat-process-entry.js +0 -366
  49. package/dist/conversion/hub/pipeline/hub-pipeline/execute-request-stage.d.ts +0 -9
  50. package/dist/conversion/hub/pipeline/hub-pipeline/execute-request-stage.js +0 -390
  51. package/dist/conversion/hub/pipeline/hub-pipeline/node-results.d.ts +0 -3
  52. package/dist/conversion/hub/pipeline/hub-pipeline/node-results.js +0 -14
  53. package/dist/conversion/hub/pipeline/hub-pipeline/payload-normalize.d.ts +0 -2
  54. package/dist/conversion/hub/pipeline/hub-pipeline/payload-normalize.js +0 -144
  55. package/dist/conversion/hub/pipeline/hub-pipeline/policy.d.ts +0 -4
  56. package/dist/conversion/hub/pipeline/hub-pipeline/policy.js +0 -32
  57. package/dist/conversion/hub/pipeline/hub-pipeline/protocol.d.ts +0 -8
  58. package/dist/conversion/hub/pipeline/hub-pipeline/protocol.js +0 -63
  59. package/dist/conversion/hub/pipeline/hub-pipeline/resolve-protocol-hooks.d.ts +0 -2
  60. package/dist/conversion/hub/pipeline/hub-pipeline/resolve-protocol-hooks.js +0 -43
  61. package/dist/conversion/hub/pipeline/hub-pipeline/semantic-gate.d.ts +0 -1
  62. package/dist/conversion/hub/pipeline/hub-pipeline/semantic-gate.js +0 -29
  63. package/dist/conversion/hub/pipeline/hub-pipeline/servertool-runtime-config.d.ts +0 -2
  64. package/dist/conversion/hub/pipeline/hub-pipeline/servertool-runtime-config.js +0 -16
  65. package/dist/conversion/hub/pipeline/hub-pipeline/types.d.ts +0 -116
  66. package/dist/conversion/hub/pipeline/hub-pipeline/types.js +0 -1
  67. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_thought_signature_inject/index.d.ts +0 -10
  68. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_thought_signature_inject/index.js +0 -172
  69. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_thought_signature_capture/index.d.ts +0 -10
  70. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_thought_signature_capture/index.js +0 -71
  71. package/dist/conversion/hub/pipeline/thought-signature/thought-signature-center.d.ts +0 -14
  72. package/dist/conversion/hub/pipeline/thought-signature/thought-signature-center.js +0 -289
@@ -1,7 +1,29 @@
1
1
  import { captureResponsesContext, buildChatRequestFromResponses } from '../../../../../responses/responses-openai-bridge.js';
2
2
  import { captureResponsesRequestContext } from '../../../../../shared/responses-conversation-store.js';
3
+ import { readRuntimeMetadata } from '../../../../../shared/runtime-metadata.js';
3
4
  import { recordStage } from '../../../stages/utils.js';
4
5
  export async function runReqInboundStage3ContextCapture(options) {
6
+ // 对由 server-side 工具触发的二跳/内部跳转请求(例如 stopMessage followup),
7
+ // 跳过工具输出扫描与 apply_patch 诊断日志,避免在内部流中重复放大客户端已收到的
8
+ // 工具错误信息。此类请求的工具治理在 chat-process 阶段完成,这里仅保留最小快照。
9
+ try {
10
+ const ctx = options.adapterContext;
11
+ const rt = readRuntimeMetadata(ctx);
12
+ const followupFlag = rt?.serverToolFollowup;
13
+ const isFollowup = followupFlag === true ||
14
+ (typeof followupFlag === 'string' && followupFlag.trim().toLowerCase() === 'true');
15
+ if (isFollowup) {
16
+ const snapshot = {
17
+ providerProtocol: options.adapterContext.providerProtocol ?? 'unknown',
18
+ tool_outputs: []
19
+ };
20
+ recordStage(options.stageRecorder, 'chat_process.req.stage3.context_capture', snapshot);
21
+ return snapshot;
22
+ }
23
+ }
24
+ catch {
25
+ // best-effort: 若检测 serverToolFollowup 失败,则继续走通用路径
26
+ }
5
27
  let context;
6
28
  if (options.captureContext) {
7
29
  try {
@@ -20,6 +20,43 @@ function shouldSample(rate) {
20
20
  function isJsonRecord(value) {
21
21
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
22
22
  }
23
+ function hasGeminiCliRequestWrapper(payload) {
24
+ const request = payload.request;
25
+ if (!isJsonRecord(request)) {
26
+ return false;
27
+ }
28
+ const req = request;
29
+ return (Object.prototype.hasOwnProperty.call(req, 'contents') ||
30
+ Object.prototype.hasOwnProperty.call(req, 'systemInstruction') ||
31
+ Object.prototype.hasOwnProperty.call(req, 'tools') ||
32
+ Object.prototype.hasOwnProperty.call(req, 'toolConfig') ||
33
+ Object.prototype.hasOwnProperty.call(req, 'generationConfig') ||
34
+ Object.prototype.hasOwnProperty.call(req, 'safetySettings'));
35
+ }
36
+ function isGeminiCliPayload(payload) {
37
+ const record = payload;
38
+ return (typeof record.project === 'string' ||
39
+ typeof record.requestType === 'string' ||
40
+ typeof record.userAgent === 'string' ||
41
+ typeof record.requestId === 'string' ||
42
+ hasGeminiCliRequestWrapper(payload));
43
+ }
44
+ function extendGeminiAllowlistIfNeeded(providerProtocol, payload, allowedTopLevelKeys) {
45
+ if (providerProtocol !== 'gemini-chat') {
46
+ return allowedTopLevelKeys;
47
+ }
48
+ if (!isGeminiCliPayload(payload)) {
49
+ return allowedTopLevelKeys;
50
+ }
51
+ const extended = allowedTopLevelKeys ? new Set(allowedTopLevelKeys) : new Set();
52
+ extended.add('request');
53
+ extended.add('project');
54
+ extended.add('requestId');
55
+ extended.add('requestType');
56
+ extended.add('userAgent');
57
+ extended.add('action');
58
+ return extended;
59
+ }
23
60
  function applyProviderOutboundPolicy(providerProtocol, payload) {
24
61
  const removedTopLevelKeys = [];
25
62
  const flattenedWrappers = [];
@@ -43,6 +80,8 @@ function applyProviderOutboundPolicy(providerProtocol, payload) {
43
80
  spec.providerOutbound.enforceAllowedTopLevelKeys === true
44
81
  ? new Set(spec.providerOutbound.allowedTopLevelKeys)
45
82
  : undefined;
83
+ const isGeminiCli = providerProtocol === 'gemini-chat' && isGeminiCliPayload(payload);
84
+ const allowedTopLevelKeysResolved = extendGeminiAllowlistIfNeeded(providerProtocol, payload, allowedTopLevelKeys);
46
85
  // Reserved/private keys must never be sent upstream.
47
86
  for (const key of Object.keys(payload)) {
48
87
  if (spec.providerOutbound.reservedKeyPrefixes.some((prefix) => key.startsWith(prefix))) {
@@ -57,6 +96,9 @@ function applyProviderOutboundPolicy(providerProtocol, payload) {
57
96
  if (!wrapperKey || typeof wrapperKey !== 'string') {
58
97
  continue;
59
98
  }
99
+ if (isGeminiCli && wrapperKey === 'request') {
100
+ continue;
101
+ }
60
102
  if (!isJsonRecord(out[wrapperKey])) {
61
103
  continue;
62
104
  }
@@ -84,9 +126,9 @@ function applyProviderOutboundPolicy(providerProtocol, payload) {
84
126
  // Enforce protocol allowlist (top-level). Only runs when explicitly enabled
85
127
  // for this protocol, and only after wrapper flatten so allowed fields are
86
128
  // present at the correct level.
87
- if (allowedTopLevelKeys) {
129
+ if (allowedTopLevelKeysResolved) {
88
130
  for (const key of Object.keys(out)) {
89
- if (allowedTopLevelKeys.has(key))
131
+ if (allowedTopLevelKeysResolved.has(key))
90
132
  continue;
91
133
  ensureOutClone();
92
134
  delete out[key];
@@ -106,13 +148,18 @@ function observeProviderPayload(options) {
106
148
  // Do NOT modify payload here.
107
149
  const spec = resolveHubProtocolSpec(options.providerProtocol);
108
150
  const allowlistEnabled = options.phase === 'provider_outbound';
151
+ const isGeminiCli = options.providerProtocol === 'gemini-chat' && isGeminiCliPayload(options.payload);
109
152
  const allowedTopLevelKeys = allowlistEnabled && Array.isArray(spec.providerOutbound.allowedTopLevelKeys)
110
153
  ? new Set(spec.providerOutbound.allowedTopLevelKeys)
111
154
  : undefined;
155
+ const allowedTopLevelKeysResolved = extendGeminiAllowlistIfNeeded(options.providerProtocol, options.payload, allowedTopLevelKeys);
112
156
  for (const rule of spec.providerOutbound.forbidWrappers) {
113
157
  if (rule.code !== 'forbid_wrapper') {
114
158
  continue;
115
159
  }
160
+ if (isGeminiCli && rule.path === 'request') {
161
+ continue;
162
+ }
116
163
  if (rule.path in options.payload && isJsonRecord(options.payload[rule.path])) {
117
164
  violations.push({
118
165
  code: 'unexpected_wrapper',
@@ -130,7 +177,7 @@ function observeProviderPayload(options) {
130
177
  });
131
178
  continue;
132
179
  }
133
- if (allowedTopLevelKeys && !allowedTopLevelKeys.has(key)) {
180
+ if (allowedTopLevelKeysResolved && !allowedTopLevelKeysResolved.has(key)) {
134
181
  violations.push({
135
182
  code: 'unexpected_field',
136
183
  path: key,
@@ -112,7 +112,7 @@ async function applyRequestToolGovernance(request, context) {
112
112
  // Server-side web_search tool injection (config-driven, best-effort).
113
113
  merged = applyHubOperations(merged, buildWebSearchOperations(merged, metadata));
114
114
  // Server-side clock tool + scheduled reminders injection (config-driven, best-effort).
115
- merged = applyHubOperations(merged, buildClockOperations(merged, metadata));
115
+ merged = applyHubOperations(merged, buildClockOperations(metadata));
116
116
  merged = await maybeInjectClockRemindersAndApplyDirectives(merged, metadata, context.requestId);
117
117
  const { request: sanitized, summary } = toolGovernanceEngine.governRequest(merged, providerProtocol);
118
118
  if (summary.applied) {
@@ -124,129 +124,12 @@ async function applyRequestToolGovernance(request, context) {
124
124
  }
125
125
  };
126
126
  }
127
- return pruneUndeclaredToolHistory(sanitized);
127
+ return sanitized;
128
128
  }
129
129
  function resolveSessionIdForPending(metadata, request) {
130
130
  const candidate = readString(metadata.sessionId) ?? readString(request.metadata?.sessionId);
131
131
  return candidate && candidate.trim() ? candidate.trim() : null;
132
132
  }
133
- function pruneUndeclaredToolHistory(request) {
134
- const tools = Array.isArray(request.tools) ? request.tools : [];
135
- const allowedToolNames = new Set();
136
- for (const tool of tools) {
137
- const name = tool && typeof tool === 'object' && tool.function && typeof tool.function.name === 'string'
138
- ? String(tool.function.name).trim()
139
- : '';
140
- if (name) {
141
- allowedToolNames.add(name);
142
- }
143
- }
144
- // If no tools are declared, do not carry any tool calls/results in history.
145
- const hasAnyTools = allowedToolNames.size > 0;
146
- let prunedToolCalls = 0;
147
- let prunedToolResults = 0;
148
- const prunedToolNames = new Set();
149
- const keptToolCallIds = new Set();
150
- const nextMessages = [];
151
- for (const msg of request.messages) {
152
- if (!msg || typeof msg !== 'object')
153
- continue;
154
- if (msg.role === 'assistant' && Array.isArray(msg.tool_calls) && msg.tool_calls.length) {
155
- if (!hasAnyTools) {
156
- prunedToolCalls += msg.tool_calls.length;
157
- for (const tc of msg.tool_calls) {
158
- const n = tc && tc.function && typeof tc.function.name === 'string' ? tc.function.name.trim() : '';
159
- if (n)
160
- prunedToolNames.add(n);
161
- }
162
- // Drop tool_calls when no tools are declared.
163
- const keptContent = msg.content;
164
- const hasContent = typeof keptContent === 'string'
165
- ? keptContent.trim().length > 0
166
- : Array.isArray(keptContent)
167
- ? keptContent.length > 0
168
- : false;
169
- if (hasContent) {
170
- nextMessages.push({ ...msg, tool_calls: [] });
171
- }
172
- continue;
173
- }
174
- const keptCalls = [];
175
- for (const tc of msg.tool_calls) {
176
- if (!tc || typeof tc !== 'object')
177
- continue;
178
- const name = tc.function && typeof tc.function.name === 'string' ? tc.function.name.trim() : '';
179
- if (!name || !allowedToolNames.has(name)) {
180
- prunedToolCalls += 1;
181
- if (name)
182
- prunedToolNames.add(name);
183
- continue;
184
- }
185
- keptCalls.push(tc);
186
- if (typeof tc.id === 'string' && tc.id.trim()) {
187
- keptToolCallIds.add(tc.id.trim());
188
- }
189
- }
190
- const keptContent = msg.content;
191
- const hasContent = typeof keptContent === 'string'
192
- ? keptContent.trim().length > 0
193
- : Array.isArray(keptContent)
194
- ? keptContent.length > 0
195
- : false;
196
- if (!hasContent && keptCalls.length === 0) {
197
- continue;
198
- }
199
- if (keptCalls.length === msg.tool_calls.length) {
200
- nextMessages.push(msg);
201
- }
202
- else {
203
- nextMessages.push({ ...msg, tool_calls: keptCalls.length ? keptCalls : undefined });
204
- }
205
- continue;
206
- }
207
- if (msg.role === 'tool') {
208
- const name = typeof msg.name === 'string' ? msg.name.trim() : '';
209
- const toolCallId = typeof msg.tool_call_id === 'string' ? msg.tool_call_id.trim() : '';
210
- if (!hasAnyTools) {
211
- prunedToolResults += 1;
212
- if (name)
213
- prunedToolNames.add(name);
214
- continue;
215
- }
216
- if (name && !allowedToolNames.has(name)) {
217
- prunedToolResults += 1;
218
- prunedToolNames.add(name);
219
- continue;
220
- }
221
- // If the result references a tool_call_id that no longer exists, drop it to avoid
222
- // provider-side strict pairing errors (Gemini/Anthropic tool pairing).
223
- if (toolCallId && !keptToolCallIds.has(toolCallId)) {
224
- prunedToolResults += 1;
225
- if (name)
226
- prunedToolNames.add(name);
227
- continue;
228
- }
229
- nextMessages.push(msg);
230
- continue;
231
- }
232
- nextMessages.push(msg);
233
- }
234
- if (prunedToolCalls === 0 && prunedToolResults === 0) {
235
- return request;
236
- }
237
- return {
238
- ...request,
239
- messages: nextMessages,
240
- metadata: {
241
- ...request.metadata,
242
- toolHistoryPrune: {
243
- prunedToolCalls,
244
- prunedToolResults,
245
- prunedToolNames: Array.from(prunedToolNames).sort()
246
- }
247
- }
248
- };
249
- }
250
133
  function extractToolCallIdsFromToolMessages(messages) {
251
134
  const ids = new Set();
252
135
  for (const msg of messages) {
@@ -613,32 +496,8 @@ function buildToolChoiceOperations(toolChoice) {
613
496
  }
614
497
  ];
615
498
  }
616
- function isGeminiAntigravityLike(metadata) {
617
- const providerProtocol = readString(metadata.providerProtocol) ?? readString(metadata.provider) ?? '';
618
- if (!providerProtocol.toLowerCase().includes('gemini')) {
619
- return false;
620
- }
621
- const rt = readRuntimeMetadata(metadata);
622
- const providerId = readString(metadata.providerId) ??
623
- readString(rt?.providerId) ??
624
- '';
625
- const providerKey = readString(metadata.providerKey) ??
626
- readString(rt?.providerKey) ??
627
- '';
628
- const loweredId = providerId.toLowerCase();
629
- const loweredKey = providerKey.toLowerCase();
630
- return (loweredId.includes('antigravity') ||
631
- loweredId === 'gemini-cli' ||
632
- loweredKey.startsWith('antigravity.') ||
633
- loweredKey.startsWith('gemini-cli.'));
634
- }
635
499
  function buildWebSearchOperations(request, metadata) {
636
500
  const rt = readRuntimeMetadata(metadata);
637
- // gcli2api-style: do not force-inject server-side web_search tools for Gemini/Antigravity.
638
- // Tools must be present only when supplied by the client payload/config, not auto-appended.
639
- if (isGeminiAntigravityLike(metadata)) {
640
- return [];
641
- }
642
501
  // ServerTool 二/三跳(serverToolFollowup=true)不再注入 web_search 工具,
643
502
  // 以避免在 web_search 流程内部形成循环命中。
644
503
  if (rt?.serverToolFollowup === true) {
@@ -750,10 +609,10 @@ function buildWebSearchOperations(request, metadata) {
750
609
  });
751
610
  return ops;
752
611
  }
753
- function buildClockOperations(request, metadata) {
612
+ function buildClockOperations(metadata) {
754
613
  const rt = readRuntimeMetadata(metadata);
755
- // gcli2api-style: do not force-inject server-side clock tools for Gemini/Antigravity.
756
- if (isGeminiAntigravityLike(metadata)) {
614
+ // Do not inject clock tool into internal servertool followup hops.
615
+ if (rt?.serverToolFollowup === true) {
757
616
  return [];
758
617
  }
759
618
  const rawConfig = rt?.clock;
@@ -8,7 +8,6 @@ import { OpenAIChatResponseMapper, ResponsesResponseMapper, AnthropicResponseMap
8
8
  import { runRespInboundStage1SseDecode } from '../pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js';
9
9
  import { runRespInboundStage2FormatParse } from '../pipeline/stages/resp_inbound/resp_inbound_stage2_format_parse/index.js';
10
10
  import { runRespInboundStage3SemanticMap } from '../pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.js';
11
- import { runRespInboundStage3ThoughtSignatureCapture } from '../pipeline/stages/resp_inbound/resp_inbound_stage3_thought_signature_capture/index.js';
12
11
  import { runRespInboundStageCompatResponse } from '../pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js';
13
12
  import { runRespProcessStage1ToolGovernance } from '../pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js';
14
13
  import { runRespProcessStage2Finalize } from '../pipeline/stages/resp_process/resp_process_stage2_finalize/index.js';
@@ -260,14 +259,21 @@ export async function convertProviderResponse(options) {
260
259
  // Client protocol remapping happens only on the outermost request.
261
260
  const clientProtocol = isFollowup ? 'openai-chat' : resolveClientProtocol(options.entryEndpoint);
262
261
  const hasServerToolSupport = Boolean(options.providerInvoker) || Boolean(options.reenterPipeline);
263
- // ServerTool followup hop: always return a fully materialized ChatCompletion JSON (non-SSE).
264
- // This is an internal hop used by the servertool engine, and it must be deterministic.
262
+ // 是否跳过 ServerTool 编排:
263
+ // - Provider 不支持 ServerTool(没有 invoker/reenterPipeline)时跳过;
264
+ // - 对于 serverToolFollowup=true 的二/三跳内部请求,必须跳过:
265
+ // followup 的语义是“本轮 ServerTool 已决定并发起下一跳”,下一跳响应不应再次触发 ServerTool,
266
+ // 否则会形成嵌套/循环(例如 stop_message_flow 反复触发)。
267
+ const skipServerTools = isFollowup || !hasServerToolSupport;
268
+ // 对于由 server-side 工具触发的内部跳转(二跳/三跳),统一禁用 SSE 聚合输出,
269
+ // 始终返回完整的 ChatCompletion JSON,便于在 llms 内部直接解析,而不是拿到
270
+ // __sse_responses 可读流。
265
271
  const wantsStream = isFollowup ? false : options.wantsStream;
266
272
  try {
267
273
  // eslint-disable-next-line no-console
268
274
  console.log(`\x1b[38;5;33m[servertool][orchestrator][debug] requestId=${options.context.requestId} ` +
269
275
  `protocol=${options.providerProtocol} endpoint=${options.entryEndpoint} ` +
270
- `serverTools=${hasServerToolSupport} hasInvoker=${Boolean(options.providerInvoker)} ` +
276
+ `skipServerTools=${skipServerTools} hasInvoker=${Boolean(options.providerInvoker)} ` +
271
277
  `hasReenter=${Boolean(options.reenterPipeline)}\x1b[0m`);
272
278
  }
273
279
  catch {
@@ -300,11 +306,6 @@ export async function convertProviderResponse(options) {
300
306
  stageRecorder: options.stageRecorder
301
307
  });
302
308
  stripInternalPolicyDebugFields(formatEnvelope.payload);
303
- formatEnvelope.payload = await runRespInboundStage3ThoughtSignatureCapture({
304
- payload: formatEnvelope.payload,
305
- adapterContext: options.context,
306
- stageRecorder: options.stageRecorder
307
- });
308
309
  // Phase 2 (shadow): response tool surface mismatch detection (provider inbound).
309
310
  // Only records diffs; does not rewrite payload.
310
311
  try {
@@ -352,7 +353,7 @@ export async function convertProviderResponse(options) {
352
353
  // 检查是否需要进行 ServerTool 编排
353
354
  // 使用新的 ChatEnvelope 级别的 servertool 实现
354
355
  let effectiveChatResponse = chatResponse;
355
- if (hasServerToolSupport) {
356
+ if (!skipServerTools && options.reenterPipeline) {
356
357
  try {
357
358
  // eslint-disable-next-line no-console
358
359
  console.log(`\x1b[38;5;33m[servertool][orchestrator] start requestId=${options.context.requestId} ` +
@@ -20,7 +20,5 @@ export declare class AnthropicResponseMapper implements ResponseMapper {
20
20
  }): ChatCompletionLike;
21
21
  }
22
22
  export declare class GeminiResponseMapper implements ResponseMapper {
23
- toChatCompletion(format: FormatEnvelope, ctx: AdapterContext, options?: {
24
- requestSemantics?: ChatSemantics | JsonObject;
25
- }): ChatCompletionLike;
23
+ toChatCompletion(format: FormatEnvelope, _ctx: AdapterContext): ChatCompletionLike;
26
24
  }
@@ -18,9 +18,8 @@ export class AnthropicResponseMapper {
18
18
  }
19
19
  }
20
20
  export class GeminiResponseMapper {
21
- toChatCompletion(format, ctx, options) {
22
- const aliasMap = extractToolNameAliasMapFromSemantics(options?.requestSemantics) ?? extractGeminiToolNameAliasMapFromContext(ctx);
23
- return buildOpenAIChatFromGeminiResponse(format.payload ?? {}, { aliasMap });
21
+ toChatCompletion(format, _ctx) {
22
+ return buildOpenAIChatFromGeminiResponse(format.payload ?? {});
24
23
  }
25
24
  }
26
25
  function extractToolNameAliasMapFromSemantics(semantics) {
@@ -48,20 +47,3 @@ function extractToolNameAliasMapFromSemantics(semantics) {
48
47
  }
49
48
  return Object.keys(normalized).length ? normalized : undefined;
50
49
  }
51
- function extractGeminiToolNameAliasMapFromContext(ctx) {
52
- const candidate = ctx?.geminiToolNameAliasMap;
53
- if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
54
- return undefined;
55
- }
56
- const normalized = {};
57
- for (const [key, value] of Object.entries(candidate)) {
58
- if (typeof key !== 'string' || typeof value !== 'string')
59
- continue;
60
- const trimmedKey = key.trim();
61
- const trimmedValue = value.trim();
62
- if (!trimmedKey.length || !trimmedValue.length)
63
- continue;
64
- normalized[trimmedKey] = trimmedValue;
65
- }
66
- return Object.keys(normalized).length ? normalized : undefined;
67
- }
@@ -477,7 +477,8 @@ export function applyProviderOutboundToolSurface(args) {
477
477
  // best-effort only
478
478
  }
479
479
  const totalDiffCount = (schemaDiff.diffCount || 0) + (historyDiff.diffCount || 0);
480
- if (totalDiffCount > 0) {
480
+ const shouldRecord = totalDiffCount > 0 || Boolean(candidate?.candidateTools) || Boolean(historyReason);
481
+ if (shouldRecord) {
481
482
  const diffHeadMerged = [];
482
483
  for (const entry of schemaDiff.diffHead) {
483
484
  if (diffHeadMerged.length >= 10)
@@ -170,9 +170,10 @@ function stripRoutingTagsFromText(text) {
170
170
  if (typeof text !== 'string') {
171
171
  return typeof text === 'string' ? text : String(text ?? '');
172
172
  }
173
- // 移除形如 <** ... **> 的路由指令标记(例如 stopMessage/!provider 等),
174
- // 避免泄露到上游 provider 或持久化的 Responses 历史中。
175
- return text.replace(/<\*\*[^*]+\*\*>/g, '').trim();
173
+ // NOTE: Do not strip <**...**> here. Routing instructions must reach the
174
+ // virtual router so allowlist/sticky directives can be applied. The router
175
+ // will clean them from messages after parsing.
176
+ return text;
176
177
  }
177
178
  function sanitizeBridgeHistory(history) {
178
179
  if (!history || typeof history !== 'object') {
@@ -1,12 +1,7 @@
1
1
  import type { BridgeToolDefinition } from './bridge-message-types.js';
2
2
  import type { MissingField } from '../hub/types/chat-envelope.js';
3
3
  import type { JsonValue, JsonObject } from '../hub/types/json.js';
4
- export declare function isGeminiFunctionNameSafe(name: string): boolean;
5
- export declare function sanitizeGeminiFunctionName(name: string, options?: {
6
- maxLen?: number;
7
- }): string;
8
- export type GeminiToolSchemaMode = 'default' | 'antigravity';
9
4
  export declare function prepareGeminiToolsForBridge(rawTools: JsonValue | undefined, missing?: MissingField[]): BridgeToolDefinition[] | undefined;
10
5
  export declare function buildGeminiToolsFromBridge(defs: BridgeToolDefinition[] | undefined, options?: {
11
- mode?: GeminiToolSchemaMode;
6
+ mode?: 'antigravity' | 'default';
12
7
  }): JsonObject[] | undefined;