@jsonstudio/llms 0.6.1892 → 0.6.2172

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 (159) hide show
  1. package/dist/conversion/compat/actions/deepseek-web-request.js +16 -2
  2. package/dist/conversion/compat/actions/deepseek-web-response.d.ts +7 -1
  3. package/dist/conversion/compat/actions/deepseek-web-response.js +302 -40
  4. package/dist/conversion/compat/actions/harvest-tool-calls-from-text.d.ts +5 -0
  5. package/dist/conversion/compat/actions/harvest-tool-calls-from-text.js +7 -4
  6. package/dist/conversion/compat/actions/iflow-tool-text-fallback.d.ts +1 -0
  7. package/dist/conversion/compat/actions/iflow-tool-text-fallback.js +12 -0
  8. package/dist/conversion/compat/actions/strip-orphan-function-calls-tag.js +1 -1
  9. package/dist/conversion/compat/actions/tool-text-request-guidance.d.ts +9 -0
  10. package/dist/conversion/compat/actions/tool-text-request-guidance.js +177 -0
  11. package/dist/conversion/compat/antigravity-session-signature.d.ts +6 -0
  12. package/dist/conversion/compat/antigravity-session-signature.js +15 -0
  13. package/dist/conversion/compat/profiles/chat-deepseek-web.json +52 -1
  14. package/dist/conversion/compat/profiles/chat-glm.json +22 -0
  15. package/dist/conversion/compat/profiles/chat-iflow.json +4 -0
  16. package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +13 -27
  17. package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +10 -1
  18. package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +13 -4
  19. package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.js +1 -53
  20. package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +8 -0
  21. package/dist/conversion/hub/pipeline/hub-pipeline.js +8 -4
  22. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +191 -9
  23. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +118 -15
  24. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +65 -2
  25. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.d.ts +34 -0
  26. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.js +75 -0
  27. package/dist/conversion/hub/process/chat-process.js +85 -18
  28. package/dist/conversion/hub/response/provider-response.js +21 -50
  29. package/dist/conversion/hub/response/response-runtime.js +71 -10
  30. package/dist/conversion/responses/responses-openai-bridge/response-payload.d.ts +3 -0
  31. package/dist/conversion/responses/responses-openai-bridge/response-payload.js +576 -0
  32. package/dist/conversion/responses/responses-openai-bridge/types.d.ts +42 -0
  33. package/dist/conversion/responses/responses-openai-bridge/types.js +1 -0
  34. package/dist/conversion/responses/responses-openai-bridge.d.ts +3 -44
  35. package/dist/conversion/responses/responses-openai-bridge.js +193 -504
  36. package/dist/conversion/shared/anthropic-message-utils.js +82 -2
  37. package/dist/conversion/shared/bridge-message-utils.js +92 -39
  38. package/dist/conversion/shared/snapshot-hooks.js +8 -13
  39. package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.d.ts +2 -0
  40. package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.js +129 -0
  41. package/dist/conversion/shared/text-markup-normalizer/extractors-json.d.ts +4 -0
  42. package/dist/conversion/shared/text-markup-normalizer/extractors-json.js +637 -0
  43. package/dist/conversion/shared/text-markup-normalizer/extractors-shared.d.ts +21 -0
  44. package/dist/conversion/shared/text-markup-normalizer/extractors-shared.js +177 -0
  45. package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.d.ts +5 -0
  46. package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.js +385 -0
  47. package/dist/conversion/shared/text-markup-normalizer/extractors-xml.d.ts +10 -0
  48. package/dist/conversion/shared/text-markup-normalizer/extractors-xml.js +602 -0
  49. package/dist/conversion/shared/text-markup-normalizer/extractors.d.ts +5 -0
  50. package/dist/conversion/shared/text-markup-normalizer/extractors.js +4 -0
  51. package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +2 -0
  52. package/dist/conversion/shared/text-markup-normalizer/normalize.js +76 -0
  53. package/dist/conversion/shared/text-markup-normalizer.d.ts +3 -25
  54. package/dist/conversion/shared/text-markup-normalizer.js +2 -1386
  55. package/dist/conversion/shared/tool-governor.js +136 -10
  56. package/dist/filters/utils/snapshot-writer.js +3 -3
  57. package/dist/router/virtual-router/bootstrap/auth-utils.d.ts +6 -0
  58. package/dist/router/virtual-router/bootstrap/auth-utils.js +288 -0
  59. package/dist/router/virtual-router/bootstrap/claude-code-helpers.d.ts +11 -0
  60. package/dist/router/virtual-router/bootstrap/claude-code-helpers.js +18 -0
  61. package/dist/router/virtual-router/bootstrap/config-defaults.d.ts +5 -0
  62. package/dist/router/virtual-router/bootstrap/config-defaults.js +13 -0
  63. package/dist/router/virtual-router/bootstrap/config-normalizers.d.ts +4 -0
  64. package/dist/router/virtual-router/bootstrap/config-normalizers.js +106 -0
  65. package/dist/router/virtual-router/bootstrap/profile-builder.d.ts +7 -0
  66. package/dist/router/virtual-router/bootstrap/profile-builder.js +68 -0
  67. package/dist/router/virtual-router/bootstrap/provider-normalization.d.ts +40 -0
  68. package/dist/router/virtual-router/bootstrap/provider-normalization.js +212 -0
  69. package/dist/router/virtual-router/bootstrap/responses-helpers.d.ts +15 -0
  70. package/dist/router/virtual-router/bootstrap/responses-helpers.js +65 -0
  71. package/dist/router/virtual-router/bootstrap/routing-config.d.ts +23 -0
  72. package/dist/router/virtual-router/bootstrap/routing-config.js +293 -0
  73. package/dist/router/virtual-router/bootstrap/streaming-helpers.d.ts +12 -0
  74. package/dist/router/virtual-router/bootstrap/streaming-helpers.js +128 -0
  75. package/dist/router/virtual-router/bootstrap/utils.d.ts +5 -0
  76. package/dist/router/virtual-router/bootstrap/utils.js +41 -0
  77. package/dist/router/virtual-router/bootstrap/web-search-config.d.ts +4 -0
  78. package/dist/router/virtual-router/bootstrap/web-search-config.js +131 -0
  79. package/dist/router/virtual-router/bootstrap.d.ts +0 -4
  80. package/dist/router/virtual-router/bootstrap.js +31 -1275
  81. package/dist/router/virtual-router/classifier.js +32 -14
  82. package/dist/router/virtual-router/engine/antigravity/alias-lease.js +2 -2
  83. package/dist/router/virtual-router/engine/cooldown-manager.d.ts +34 -0
  84. package/dist/router/virtual-router/engine/cooldown-manager.js +118 -0
  85. package/dist/router/virtual-router/engine/route-analytics.d.ts +28 -0
  86. package/dist/router/virtual-router/engine/route-analytics.js +44 -0
  87. package/dist/router/virtual-router/engine/routing-pools/index.js +165 -4
  88. package/dist/router/virtual-router/engine/sticky-session-manager.d.ts +29 -0
  89. package/dist/router/virtual-router/engine/sticky-session-manager.js +55 -0
  90. package/dist/router/virtual-router/engine-logging.d.ts +42 -1
  91. package/dist/router/virtual-router/engine-logging.js +82 -15
  92. package/dist/router/virtual-router/engine-selection/multimodal-capability.d.ts +3 -0
  93. package/dist/router/virtual-router/engine-selection/multimodal-capability.js +26 -0
  94. package/dist/router/virtual-router/engine-selection/route-utils.js +6 -2
  95. package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +1 -0
  96. package/dist/router/virtual-router/engine-selection/tier-selection.js +31 -1
  97. package/dist/router/virtual-router/engine.d.ts +21 -7
  98. package/dist/router/virtual-router/engine.js +198 -194
  99. package/dist/router/virtual-router/features.js +12 -4
  100. package/dist/router/virtual-router/message-utils.d.ts +8 -0
  101. package/dist/router/virtual-router/message-utils.js +170 -45
  102. package/dist/router/virtual-router/pre-command-file-resolver.js +40 -2
  103. package/dist/router/virtual-router/routing-instructions.d.ts +8 -0
  104. package/dist/router/virtual-router/routing-instructions.js +18 -2
  105. package/dist/router/virtual-router/routing-stop-message-actions.js +34 -10
  106. package/dist/router/virtual-router/routing-stop-message-state-codec.d.ts +2 -0
  107. package/dist/router/virtual-router/routing-stop-message-state-codec.js +50 -1
  108. package/dist/router/virtual-router/stop-message-state-sync.d.ts +1 -1
  109. package/dist/router/virtual-router/stop-message-state-sync.js +3 -0
  110. package/dist/router/virtual-router/token-counter.js +51 -10
  111. package/dist/router/virtual-router/tool-signals.js +4 -0
  112. package/dist/router/virtual-router/types.d.ts +15 -0
  113. package/dist/servertool/clock/session-scope.d.ts +3 -0
  114. package/dist/servertool/clock/session-scope.js +52 -0
  115. package/dist/servertool/clock/state.js +9 -0
  116. package/dist/servertool/clock/tasks.js +12 -1
  117. package/dist/servertool/clock/types.d.ts +3 -0
  118. package/dist/servertool/engine.js +177 -31
  119. package/dist/servertool/handlers/clock-auto.js +2 -8
  120. package/dist/servertool/handlers/clock.js +6 -9
  121. package/dist/servertool/handlers/recursive-detection-guard.js +53 -14
  122. package/dist/servertool/handlers/stop-message-auto/blocked-report.d.ts +16 -0
  123. package/dist/servertool/handlers/stop-message-auto/blocked-report.js +349 -0
  124. package/dist/servertool/handlers/stop-message-auto/iflow-followup.d.ts +23 -0
  125. package/dist/servertool/handlers/stop-message-auto/iflow-followup.js +503 -0
  126. package/dist/servertool/handlers/stop-message-auto/routing-state.d.ts +38 -0
  127. package/dist/servertool/handlers/stop-message-auto/routing-state.js +149 -0
  128. package/dist/servertool/handlers/stop-message-auto/runtime-utils.d.ts +67 -0
  129. package/dist/servertool/handlers/stop-message-auto/runtime-utils.js +387 -0
  130. package/dist/servertool/handlers/stop-message-auto.d.ts +1 -1
  131. package/dist/servertool/handlers/stop-message-auto.js +80 -556
  132. package/dist/servertool/handlers/stop-message-stage-policy/bd-runtime.d.ts +18 -0
  133. package/dist/servertool/handlers/stop-message-stage-policy/bd-runtime.js +398 -0
  134. package/dist/servertool/handlers/stop-message-stage-policy/decision.d.ts +9 -0
  135. package/dist/servertool/handlers/stop-message-stage-policy/decision.js +127 -0
  136. package/dist/servertool/handlers/stop-message-stage-policy/observation.d.ts +2 -0
  137. package/dist/servertool/handlers/stop-message-stage-policy/observation.js +179 -0
  138. package/dist/servertool/handlers/stop-message-stage-policy/templates.d.ts +4 -0
  139. package/dist/servertool/handlers/stop-message-stage-policy/templates.js +96 -0
  140. package/dist/servertool/handlers/stop-message-stage-policy/text-utils.d.ts +9 -0
  141. package/dist/servertool/handlers/stop-message-stage-policy/text-utils.js +89 -0
  142. package/dist/servertool/handlers/stop-message-stage-policy/types.d.ts +59 -0
  143. package/dist/servertool/handlers/stop-message-stage-policy/types.js +1 -0
  144. package/dist/servertool/handlers/stop-message-stage-policy.d.ts +3 -43
  145. package/dist/servertool/handlers/stop-message-stage-policy.js +2 -684
  146. package/dist/servertool/handlers/web-search.js +117 -0
  147. package/dist/servertool/server-side-tools.d.ts +0 -1
  148. package/dist/servertool/server-side-tools.js +4 -3
  149. package/dist/sse/sse-to-json/builders/response-builder.js +16 -0
  150. package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +1 -0
  151. package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +110 -37
  152. package/dist/telemetry/stats-center.d.ts +9 -0
  153. package/dist/telemetry/stats-center.js +29 -1
  154. package/dist/tools/apply-patch/structured/coercion.js +3 -11
  155. package/dist/tools/exec-command/validator.d.ts +1 -0
  156. package/dist/tools/exec-command/validator.js +132 -0
  157. package/dist/tools/tool-registry.d.ts +1 -0
  158. package/dist/tools/tool-registry.js +1 -1
  159. package/package.json +1 -1
@@ -8,6 +8,7 @@ import { clearClockSession, parseDueAtMs, resolveClockConfig, reserveDueTasksFor
8
8
  import { logClock } from '../../../servertool/clock/log.js';
9
9
  import { logContinueExecution } from '../../../servertool/continue-execution/log.js';
10
10
  import { buildTimeTagLine, getClockTimeSnapshot } from '../../../servertool/clock/ntp.js';
11
+ import { resolveClockSessionScope } from '../../../servertool/clock/session-scope.js';
11
12
  import { clearPendingServerToolInjection, loadPendingServerToolInjection } from '../../../servertool/pending-session.js';
12
13
  import { loadRoutingInstructionStateSync } from '../../../router/virtual-router/sticky-session-store.js';
13
14
  import { isJsonObject } from '../types/json.js';
@@ -592,6 +593,12 @@ function buildWebSearchOperations(request, metadata) {
592
593
  engines = preferred;
593
594
  }
594
595
  }
596
+ // DeepSeek native search path:
597
+ // when deepseek web_search engine is configured as top priority,
598
+ // route directly to deepseek-search model instead of servertool tool injection.
599
+ if (shouldBypassServerToolWebSearch(intent, engines, semanticsWebSearch)) {
600
+ return [];
601
+ }
595
602
  if (!engines.length) {
596
603
  return [];
597
604
  }
@@ -656,6 +663,36 @@ function buildWebSearchOperations(request, metadata) {
656
663
  });
657
664
  return ops;
658
665
  }
666
+ function shouldBypassServerToolWebSearch(intent, engines, semanticsWebSearch) {
667
+ if (!intent.hasIntent || intent.googlePreferred) {
668
+ return false;
669
+ }
670
+ // Explicit semantic force should keep servertool orchestration.
671
+ if (semanticsWebSearch?.force === true) {
672
+ return false;
673
+ }
674
+ const deepseekIndex = engines.findIndex(isDeepSeekNativeWebSearchEngine);
675
+ if (deepseekIndex < 0) {
676
+ return false;
677
+ }
678
+ const deepseekEngine = engines[deepseekIndex];
679
+ // Treat explicit default as highest priority; otherwise require first position.
680
+ if (deepseekEngine.default !== true && deepseekIndex !== 0) {
681
+ return false;
682
+ }
683
+ return true;
684
+ }
685
+ function isDeepSeekNativeWebSearchEngine(engine) {
686
+ const id = typeof engine.id === 'string' ? engine.id.trim().toLowerCase() : '';
687
+ const providerKey = typeof engine.providerKey === 'string' ? engine.providerKey.trim().toLowerCase() : '';
688
+ if (id === 'deepseek:web_search') {
689
+ return true;
690
+ }
691
+ if (!providerKey.startsWith('deepseek-web.')) {
692
+ return false;
693
+ }
694
+ return providerKey.endsWith('.deepseek-chat-search') || providerKey.endsWith('.deepseek-reasoner-search');
695
+ }
659
696
  function buildClockOperations(metadata) {
660
697
  const rt = readRuntimeMetadata(metadata);
661
698
  // Do not inject clock tool into internal servertool followup hops.
@@ -905,8 +942,10 @@ function appendDirectiveToUserContent(content, directive) {
905
942
  return next;
906
943
  }
907
944
  function resolveSessionIdForClock(metadata, request) {
908
- const candidate = readString(metadata.sessionId) ?? readString(request.metadata?.sessionId);
909
- return candidate && candidate.trim() ? candidate.trim() : null;
945
+ const requestMetadata = request.metadata && typeof request.metadata === 'object' && !Array.isArray(request.metadata)
946
+ ? request.metadata
947
+ : null;
948
+ return resolveClockSessionScope(metadata, requestMetadata);
910
949
  }
911
950
  function stripClockClearDirectiveFromText(text) {
912
951
  const pattern = /<\*\*\s*clock\s*:\s*clear\s*\*\*>/gi;
@@ -1231,6 +1270,7 @@ async function maybeInjectClockRemindersAndApplyDirectives(request, metadata, re
1231
1270
  const marker = clockScheduleDirectives[index];
1232
1271
  const itemBase = {
1233
1272
  dueAtMs: marker.dueAtMs,
1273
+ setBy: 'user',
1234
1274
  task: marker.task,
1235
1275
  ...(marker.recurrence ? { recurrence: marker.recurrence } : {})
1236
1276
  };
@@ -1242,7 +1282,7 @@ async function maybeInjectClockRemindersAndApplyDirectives(request, metadata, re
1242
1282
  markerToolMessages = markerToolMessages.concat(buildClockMarkerScheduleMessages(requestId, index, marker, {
1243
1283
  ok: false,
1244
1284
  action: 'schedule',
1245
- message: 'clock requires sessionId (x-session-id header or metadata.sessionId).'
1285
+ message: 'clock requires session scope (sessionId/conversationId or clockDaemonId).'
1246
1286
  }));
1247
1287
  continue;
1248
1288
  }
@@ -1368,6 +1408,39 @@ async function maybeInjectClockRemindersAndApplyDirectives(request, metadata, re
1368
1408
  }
1369
1409
  function buildClockStandardToolsOperations() {
1370
1410
  const tools = [
1411
+ {
1412
+ type: 'function',
1413
+ function: {
1414
+ name: 'clock',
1415
+ description: 'Time + Alarm for this session. Use schedule/update/list/cancel/clear. For any wait requirement, call clock.schedule now.',
1416
+ parameters: {
1417
+ type: 'object',
1418
+ properties: {
1419
+ action: {
1420
+ type: 'string',
1421
+ enum: ['get', 'schedule', 'update', 'list', 'cancel', 'clear']
1422
+ },
1423
+ items: {
1424
+ type: 'array',
1425
+ items: {
1426
+ type: 'object',
1427
+ properties: {
1428
+ dueAt: { type: 'string' },
1429
+ task: { type: 'string' },
1430
+ tool: { type: 'string' },
1431
+ arguments: { type: 'string' }
1432
+ },
1433
+ required: ['dueAt', 'task', 'tool', 'arguments'],
1434
+ additionalProperties: false
1435
+ }
1436
+ },
1437
+ taskId: { type: 'string' }
1438
+ },
1439
+ required: ['action', 'items', 'taskId'],
1440
+ additionalProperties: false
1441
+ }
1442
+ }
1443
+ },
1371
1444
  {
1372
1445
  type: 'function',
1373
1446
  function: {
@@ -1543,26 +1616,20 @@ function detectWebSearchIntent(request) {
1543
1616
  if (!messages.length) {
1544
1617
  return { hasIntent: false, googlePreferred: false };
1545
1618
  }
1546
- // 从末尾向前找到最近一条 user 消息,忽略 tool / assistant 的工具调用轮次,
1547
- // 以便在 Responses / 多轮工具调用场景下仍然根据“最近一条用户输入”判断意图。
1548
- let lastUser;
1549
- for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
1550
- const candidate = messages[idx];
1551
- if (candidate && candidate.role === 'user') {
1552
- lastUser = candidate;
1553
- break;
1554
- }
1555
- }
1556
- if (!lastUser) {
1619
+ // 仅使用“当前请求最后一条消息且角色为 user”的文本判断 web_search 意图:
1620
+ // - 不读取系统提示词(system/developer)。
1621
+ // - 不读取历史 user 消息(避免历史上下文误触发)。
1622
+ const lastMessage = messages[messages.length - 1];
1623
+ if (!lastMessage || lastMessage.role !== 'user') {
1557
1624
  return { hasIntent: false, googlePreferred: false };
1558
1625
  }
1559
1626
  // 支持多模态 content:既可能是纯文本字符串,也可能是带 image_url 的分段数组。
1560
1627
  let content = '';
1561
- if (typeof lastUser.content === 'string') {
1562
- content = lastUser.content;
1628
+ if (typeof lastMessage.content === 'string') {
1629
+ content = lastMessage.content;
1563
1630
  }
1564
- else if (Array.isArray(lastUser.content)) {
1565
- const parts = lastUser.content;
1631
+ else if (Array.isArray(lastMessage.content)) {
1632
+ const parts = lastMessage.content;
1566
1633
  const texts = [];
1567
1634
  for (const part of parts) {
1568
1635
  if (typeof part === 'string') {
@@ -11,12 +11,12 @@ import { runRespInboundStage3SemanticMap } from '../pipeline/stages/resp_inbound
11
11
  import { runRespInboundStageCompatResponse } from '../pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js';
12
12
  import { runRespProcessStage1ToolGovernance } from '../pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js';
13
13
  import { runRespProcessStage2Finalize } from '../pipeline/stages/resp_process/resp_process_stage2_finalize/index.js';
14
+ import { runRespProcessStage3ServerToolOrchestration } from '../pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.js';
14
15
  import { runRespOutboundStage1ClientRemap } from '../pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js';
15
16
  import { runRespOutboundStage2SseStream } from '../pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.js';
16
17
  import { recordResponsesResponse } from '../../shared/responses-conversation-store.js';
17
18
  import { ProviderProtocolError } from '../../shared/errors.js';
18
19
  import { readRuntimeMetadata } from '../../shared/runtime-metadata.js';
19
- import { runServerToolOrchestration } from '../../../servertool/engine.js';
20
20
  import { commitClockReservation, resolveClockConfig } from '../../../servertool/clock/task-store.js';
21
21
  const PROVIDER_RESPONSE_REGISTRY = {
22
22
  'openai-chat': {
@@ -284,20 +284,6 @@ export async function convertProviderResponse(options) {
284
284
  // to re-enter the hub chat process deterministically (tools harvesting, governance, etc.).
285
285
  // Client protocol remapping happens only on the outermost request.
286
286
  const clientProtocol = isFollowup ? 'openai-chat' : resolveClientProtocol(options.entryEndpoint);
287
- const hasServerToolSupport = Boolean(options.providerInvoker) || Boolean(options.reenterPipeline);
288
- // 是否跳过 ServerTool 编排:
289
- // - Provider 不支持 ServerTool(没有 invoker/reenterPipeline)时跳过;
290
- // - 对于 serverToolFollowup=true 的二/三跳内部请求,通常需要跳过以防嵌套;
291
- // - 例外:stop_message_flow 允许链式触发(同一 flow 内重复检查直到 maxRepeats)。
292
- const rt = readRuntimeMetadata(options.context);
293
- const loopState = rt?.serverToolLoopState;
294
- const flowId = loopState && typeof loopState === 'object' && !Array.isArray(loopState)
295
- ? String(loopState.flowId || '').trim()
296
- : '';
297
- const isStopMessageFlow = flowId === 'stop_message_flow';
298
- const allowNestedServerTools = isStopMessageFlow || flowId === 'antigravity_thought_signature_bootstrap';
299
- // stop_message_flow 的 followup 允许再次触发(直到 maxRepeats),其他 followup 跳过。
300
- const skipServerTools = (isFollowup && !allowNestedServerTools) || !hasServerToolSupport;
301
287
  // 对于由 server-side 工具触发的内部跳转(二跳/三跳),统一禁用 SSE 聚合输出,
302
288
  // 始终返回完整的 ChatCompletion JSON,便于在 llms 内部直接解析,而不是拿到
303
289
  // __sse_responses 可读流。
@@ -315,20 +301,22 @@ export async function convertProviderResponse(options) {
315
301
  wantsStream,
316
302
  stageRecorder: options.stageRecorder
317
303
  });
304
+ // Hard order guarantee: provider -> compat -> inbound(parse/map) -> chat_process -> outbound -> client.
305
+ // Transport-level SSE decode stays before compat to materialize a JSON provider payload.
306
+ const compatPayload = runRespInboundStageCompatResponse({
307
+ payload: inboundStage1.payload,
308
+ adapterContext: options.context,
309
+ stageRecorder: options.stageRecorder
310
+ });
311
+ stripInternalPolicyDebugFields(compatPayload);
318
312
  const formatAdapter = plan.createFormatAdapter();
319
313
  const mapper = plan.createMapper();
320
314
  const formatEnvelope = await runRespInboundStage2FormatParse({
321
315
  adapterContext: options.context,
322
- payload: inboundStage1.payload,
316
+ payload: compatPayload,
323
317
  formatAdapter,
324
318
  stageRecorder: options.stageRecorder
325
319
  });
326
- formatEnvelope.payload = runRespInboundStageCompatResponse({
327
- payload: formatEnvelope.payload,
328
- adapterContext: options.context,
329
- stageRecorder: options.stageRecorder
330
- });
331
- stripInternalPolicyDebugFields(formatEnvelope.payload);
332
320
  // Phase 2 (shadow): response tool surface mismatch detection (provider inbound).
333
321
  // Only records diffs; does not rewrite payload.
334
322
  try {
@@ -375,34 +363,17 @@ export async function convertProviderResponse(options) {
375
363
  recordStage(options.stageRecorder, 'chat_process.resp.stage4.semantic_map_to_chat.chat', chatResponse);
376
364
  // 检查是否需要进行 ServerTool 编排
377
365
  // 使用新的 ChatEnvelope 级别的 servertool 实现
378
- let effectiveChatResponse = chatResponse;
379
- if (!skipServerTools && options.reenterPipeline) {
380
- const orchestration = await runServerToolOrchestration({
381
- chat: chatResponse,
382
- adapterContext: options.context,
383
- requestId: options.context.requestId,
384
- entryEndpoint: options.entryEndpoint,
385
- providerProtocol: options.providerProtocol,
386
- stageRecorder: options.stageRecorder,
387
- providerInvoker: options.providerInvoker,
388
- reenterPipeline: options.reenterPipeline
389
- });
390
- if (orchestration.executed) {
391
- effectiveChatResponse = orchestration.chat;
392
- recordStage(options.stageRecorder, 'chat_process.resp.stage5.servertool_orchestration', {
393
- executed: true,
394
- flowId: orchestration.flowId,
395
- inputShape: detectProviderResponseShape(chatResponse),
396
- outputShape: detectProviderResponseShape(effectiveChatResponse)
397
- });
398
- }
399
- else {
400
- recordStage(options.stageRecorder, 'chat_process.resp.stage5.servertool_orchestration', {
401
- executed: false,
402
- inputShape: detectProviderResponseShape(chatResponse)
403
- });
404
- }
405
- }
366
+ const orchestration = await runRespProcessStage3ServerToolOrchestration({
367
+ payload: chatResponse,
368
+ adapterContext: options.context,
369
+ requestId: options.context.requestId,
370
+ entryEndpoint: options.entryEndpoint,
371
+ providerProtocol: options.providerProtocol,
372
+ stageRecorder: options.stageRecorder,
373
+ providerInvoker: options.providerInvoker,
374
+ reenterPipeline: options.reenterPipeline
375
+ });
376
+ let effectiveChatResponse = orchestration.payload;
406
377
  // Hard gate: response-side chat_process requires an OpenAI-chat-like surface (choices[].message).
407
378
  // ServerTool followups must never replace the canonical chat completion with a client-protocol shape.
408
379
  effectiveChatResponse = await coerceClientPayloadToCanonicalChatCompletionOrThrow({
@@ -30,18 +30,63 @@ function sanitizeAnthropicToolUseId(raw) {
30
30
  }
31
31
  return `call_${Math.random().toString(36).slice(2, 10)}`;
32
32
  }
33
+ function coerceNonNegativeNumber(...candidates) {
34
+ for (const value of candidates) {
35
+ if (typeof value === 'number' && Number.isFinite(value) && value >= 0) {
36
+ return value;
37
+ }
38
+ if (typeof value === 'string') {
39
+ const trimmed = value.trim();
40
+ if (!trimmed.length)
41
+ continue;
42
+ const parsed = Number(trimmed);
43
+ if (Number.isFinite(parsed) && parsed >= 0) {
44
+ return parsed;
45
+ }
46
+ }
47
+ }
48
+ return undefined;
49
+ }
33
50
  function createToolNameResolver(options) {
34
51
  const reverse = new Map();
52
+ const shouldReplaceAlias = (existingCanonical, nextCanonical, providerKey) => {
53
+ const existing = existingCanonical.trim().toLowerCase();
54
+ const next = nextCanonical.trim().toLowerCase();
55
+ if (!existing) {
56
+ return true;
57
+ }
58
+ // Prefer exact identity mapping first (providerName == canonicalName).
59
+ if (next === providerKey && existing !== providerKey) {
60
+ return true;
61
+ }
62
+ if (existing === providerKey && next !== providerKey) {
63
+ return false;
64
+ }
65
+ // When provider emits exec_command, never downgrade back to shell_command.
66
+ if (providerKey === 'exec_command') {
67
+ if (next === 'exec_command' && existing !== 'exec_command') {
68
+ return true;
69
+ }
70
+ if (existing === 'exec_command' && next !== 'exec_command') {
71
+ return false;
72
+ }
73
+ }
74
+ return false;
75
+ };
35
76
  const aliasMap = options?.aliasMap;
36
77
  if (aliasMap && typeof aliasMap === 'object') {
37
78
  for (const [canonical, providerName] of Object.entries(aliasMap)) {
38
79
  if (typeof canonical !== 'string' || typeof providerName !== 'string')
39
80
  continue;
81
+ const canonicalName = canonical.trim();
82
+ if (!canonicalName.length)
83
+ continue;
40
84
  const normalizedProvider = providerName.trim().toLowerCase();
41
85
  if (!normalizedProvider.length)
42
86
  continue;
43
- if (!reverse.has(normalizedProvider)) {
44
- reverse.set(normalizedProvider, canonical.trim());
87
+ const existing = reverse.get(normalizedProvider);
88
+ if (!existing || shouldReplaceAlias(existing, canonicalName, normalizedProvider)) {
89
+ reverse.set(normalizedProvider, canonicalName);
45
90
  }
46
91
  }
47
92
  }
@@ -259,11 +304,21 @@ export function buildOpenAIChatFromAnthropicMessage(payload, options) {
259
304
  function mapShellCommandArgsForAnthropic(raw) {
260
305
  const result = {};
261
306
  const source = (raw && typeof raw === 'object' && !Array.isArray(raw)) ? raw : {};
262
- const commandRaw = typeof source.command === 'string' && source.command.trim().length
263
- ? source.command
264
- : typeof source.cmd === 'string' && source.cmd.trim().length
265
- ? source.cmd
266
- : '';
307
+ const coerceCommand = (value) => {
308
+ if (typeof value === 'string' && value.trim().length) {
309
+ return value.trim();
310
+ }
311
+ if (Array.isArray(value)) {
312
+ const parts = value
313
+ .map((entry) => (typeof entry === 'string' ? entry.trim() : ''))
314
+ .filter((entry) => entry.length > 0);
315
+ if (parts.length) {
316
+ return parts.join(' ');
317
+ }
318
+ }
319
+ return '';
320
+ };
321
+ const commandRaw = coerceCommand(source.command) || coerceCommand(source.cmd);
267
322
  const command = commandRaw.trim();
268
323
  if (command) {
269
324
  result.command = command;
@@ -336,7 +391,7 @@ export function buildAnthropicResponseFromChat(chatResponse, options) {
336
391
  if (typeof fn?.name !== 'string')
337
392
  continue;
338
393
  const canonicalName = normalizeAnthropicToolName(fn.name) ?? fn.name;
339
- const serializedName = outboundAliasSerializer(fn.name);
394
+ const serializedName = outboundAliasSerializer(canonicalName || fn.name);
340
395
  let parsedArgs = {};
341
396
  const args = fn.arguments;
342
397
  if (typeof args === 'string') {
@@ -373,6 +428,12 @@ export function buildAnthropicResponseFromChat(chatResponse, options) {
373
428
  contentBlocks.push(sanitized);
374
429
  }
375
430
  const usage = chatResponse?.usage;
431
+ const usageInputTokens = usage && typeof usage === 'object'
432
+ ? coerceNonNegativeNumber(usage.input_tokens, usage.prompt_tokens)
433
+ : undefined;
434
+ const usageOutputTokens = usage && typeof usage === 'object'
435
+ ? coerceNonNegativeNumber(usage.output_tokens, usage.completion_tokens)
436
+ : undefined;
376
437
  const stopReason = typeof choice?.finish_reason === 'string'
377
438
  ? choice.finish_reason
378
439
  : undefined;
@@ -396,8 +457,8 @@ export function buildAnthropicResponseFromChat(chatResponse, options) {
396
457
  stop_reason: stopReasonMapped,
397
458
  usage: usage && typeof usage === 'object'
398
459
  ? {
399
- input_tokens: usage.prompt_tokens ?? 0,
400
- output_tokens: usage.completion_tokens ?? 0
460
+ input_tokens: usageInputTokens ?? 0,
461
+ output_tokens: usageOutputTokens ?? 0
401
462
  }
402
463
  : undefined
403
464
  };
@@ -0,0 +1,3 @@
1
+ import type { ResponsesRequestContext } from './types.js';
2
+ export declare function buildResponsesPayloadFromChat(payload: unknown, context?: ResponsesRequestContext): Record<string, unknown> | unknown;
3
+ export declare function extractRequestIdFromResponse(response: any): string | undefined;