@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.
- package/dist/conversion/compat/actions/deepseek-web-request.js +16 -2
- package/dist/conversion/compat/actions/deepseek-web-response.d.ts +7 -1
- package/dist/conversion/compat/actions/deepseek-web-response.js +302 -40
- package/dist/conversion/compat/actions/harvest-tool-calls-from-text.d.ts +5 -0
- package/dist/conversion/compat/actions/harvest-tool-calls-from-text.js +7 -4
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.d.ts +1 -0
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.js +12 -0
- package/dist/conversion/compat/actions/strip-orphan-function-calls-tag.js +1 -1
- package/dist/conversion/compat/actions/tool-text-request-guidance.d.ts +9 -0
- package/dist/conversion/compat/actions/tool-text-request-guidance.js +177 -0
- package/dist/conversion/compat/antigravity-session-signature.d.ts +6 -0
- package/dist/conversion/compat/antigravity-session-signature.js +15 -0
- package/dist/conversion/compat/profiles/chat-deepseek-web.json +52 -1
- package/dist/conversion/compat/profiles/chat-glm.json +22 -0
- package/dist/conversion/compat/profiles/chat-iflow.json +4 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +13 -27
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +10 -1
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +13 -4
- package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.js +1 -53
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +8 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +8 -4
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +191 -9
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +118 -15
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +65 -2
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.d.ts +34 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.js +75 -0
- package/dist/conversion/hub/process/chat-process.js +85 -18
- package/dist/conversion/hub/response/provider-response.js +21 -50
- package/dist/conversion/hub/response/response-runtime.js +71 -10
- package/dist/conversion/responses/responses-openai-bridge/response-payload.d.ts +3 -0
- package/dist/conversion/responses/responses-openai-bridge/response-payload.js +576 -0
- package/dist/conversion/responses/responses-openai-bridge/types.d.ts +42 -0
- package/dist/conversion/responses/responses-openai-bridge/types.js +1 -0
- package/dist/conversion/responses/responses-openai-bridge.d.ts +3 -44
- package/dist/conversion/responses/responses-openai-bridge.js +193 -504
- package/dist/conversion/shared/anthropic-message-utils.js +82 -2
- package/dist/conversion/shared/bridge-message-utils.js +92 -39
- package/dist/conversion/shared/snapshot-hooks.js +8 -13
- package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.d.ts +2 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.js +129 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-json.d.ts +4 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-json.js +637 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-shared.d.ts +21 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-shared.js +177 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.d.ts +5 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.js +385 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-xml.d.ts +10 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-xml.js +602 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors.d.ts +5 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors.js +4 -0
- package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +2 -0
- package/dist/conversion/shared/text-markup-normalizer/normalize.js +76 -0
- package/dist/conversion/shared/text-markup-normalizer.d.ts +3 -25
- package/dist/conversion/shared/text-markup-normalizer.js +2 -1386
- package/dist/conversion/shared/tool-governor.js +136 -10
- package/dist/filters/utils/snapshot-writer.js +3 -3
- package/dist/router/virtual-router/bootstrap/auth-utils.d.ts +6 -0
- package/dist/router/virtual-router/bootstrap/auth-utils.js +288 -0
- package/dist/router/virtual-router/bootstrap/claude-code-helpers.d.ts +11 -0
- package/dist/router/virtual-router/bootstrap/claude-code-helpers.js +18 -0
- package/dist/router/virtual-router/bootstrap/config-defaults.d.ts +5 -0
- package/dist/router/virtual-router/bootstrap/config-defaults.js +13 -0
- package/dist/router/virtual-router/bootstrap/config-normalizers.d.ts +4 -0
- package/dist/router/virtual-router/bootstrap/config-normalizers.js +106 -0
- package/dist/router/virtual-router/bootstrap/profile-builder.d.ts +7 -0
- package/dist/router/virtual-router/bootstrap/profile-builder.js +68 -0
- package/dist/router/virtual-router/bootstrap/provider-normalization.d.ts +40 -0
- package/dist/router/virtual-router/bootstrap/provider-normalization.js +212 -0
- package/dist/router/virtual-router/bootstrap/responses-helpers.d.ts +15 -0
- package/dist/router/virtual-router/bootstrap/responses-helpers.js +65 -0
- package/dist/router/virtual-router/bootstrap/routing-config.d.ts +23 -0
- package/dist/router/virtual-router/bootstrap/routing-config.js +293 -0
- package/dist/router/virtual-router/bootstrap/streaming-helpers.d.ts +12 -0
- package/dist/router/virtual-router/bootstrap/streaming-helpers.js +128 -0
- package/dist/router/virtual-router/bootstrap/utils.d.ts +5 -0
- package/dist/router/virtual-router/bootstrap/utils.js +41 -0
- package/dist/router/virtual-router/bootstrap/web-search-config.d.ts +4 -0
- package/dist/router/virtual-router/bootstrap/web-search-config.js +131 -0
- package/dist/router/virtual-router/bootstrap.d.ts +0 -4
- package/dist/router/virtual-router/bootstrap.js +31 -1275
- package/dist/router/virtual-router/classifier.js +32 -14
- package/dist/router/virtual-router/engine/antigravity/alias-lease.js +2 -2
- package/dist/router/virtual-router/engine/cooldown-manager.d.ts +34 -0
- package/dist/router/virtual-router/engine/cooldown-manager.js +118 -0
- package/dist/router/virtual-router/engine/route-analytics.d.ts +28 -0
- package/dist/router/virtual-router/engine/route-analytics.js +44 -0
- package/dist/router/virtual-router/engine/routing-pools/index.js +165 -4
- package/dist/router/virtual-router/engine/sticky-session-manager.d.ts +29 -0
- package/dist/router/virtual-router/engine/sticky-session-manager.js +55 -0
- package/dist/router/virtual-router/engine-logging.d.ts +42 -1
- package/dist/router/virtual-router/engine-logging.js +82 -15
- package/dist/router/virtual-router/engine-selection/multimodal-capability.d.ts +3 -0
- package/dist/router/virtual-router/engine-selection/multimodal-capability.js +26 -0
- package/dist/router/virtual-router/engine-selection/route-utils.js +6 -2
- package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +1 -0
- package/dist/router/virtual-router/engine-selection/tier-selection.js +31 -1
- package/dist/router/virtual-router/engine.d.ts +21 -7
- package/dist/router/virtual-router/engine.js +198 -194
- package/dist/router/virtual-router/features.js +12 -4
- package/dist/router/virtual-router/message-utils.d.ts +8 -0
- package/dist/router/virtual-router/message-utils.js +170 -45
- package/dist/router/virtual-router/pre-command-file-resolver.js +40 -2
- package/dist/router/virtual-router/routing-instructions.d.ts +8 -0
- package/dist/router/virtual-router/routing-instructions.js +18 -2
- package/dist/router/virtual-router/routing-stop-message-actions.js +34 -10
- package/dist/router/virtual-router/routing-stop-message-state-codec.d.ts +2 -0
- package/dist/router/virtual-router/routing-stop-message-state-codec.js +50 -1
- package/dist/router/virtual-router/stop-message-state-sync.d.ts +1 -1
- package/dist/router/virtual-router/stop-message-state-sync.js +3 -0
- package/dist/router/virtual-router/token-counter.js +51 -10
- package/dist/router/virtual-router/tool-signals.js +4 -0
- package/dist/router/virtual-router/types.d.ts +15 -0
- package/dist/servertool/clock/session-scope.d.ts +3 -0
- package/dist/servertool/clock/session-scope.js +52 -0
- package/dist/servertool/clock/state.js +9 -0
- package/dist/servertool/clock/tasks.js +12 -1
- package/dist/servertool/clock/types.d.ts +3 -0
- package/dist/servertool/engine.js +177 -31
- package/dist/servertool/handlers/clock-auto.js +2 -8
- package/dist/servertool/handlers/clock.js +6 -9
- package/dist/servertool/handlers/recursive-detection-guard.js +53 -14
- package/dist/servertool/handlers/stop-message-auto/blocked-report.d.ts +16 -0
- package/dist/servertool/handlers/stop-message-auto/blocked-report.js +349 -0
- package/dist/servertool/handlers/stop-message-auto/iflow-followup.d.ts +23 -0
- package/dist/servertool/handlers/stop-message-auto/iflow-followup.js +503 -0
- package/dist/servertool/handlers/stop-message-auto/routing-state.d.ts +38 -0
- package/dist/servertool/handlers/stop-message-auto/routing-state.js +149 -0
- package/dist/servertool/handlers/stop-message-auto/runtime-utils.d.ts +67 -0
- package/dist/servertool/handlers/stop-message-auto/runtime-utils.js +387 -0
- package/dist/servertool/handlers/stop-message-auto.d.ts +1 -1
- package/dist/servertool/handlers/stop-message-auto.js +80 -556
- package/dist/servertool/handlers/stop-message-stage-policy/bd-runtime.d.ts +18 -0
- package/dist/servertool/handlers/stop-message-stage-policy/bd-runtime.js +398 -0
- package/dist/servertool/handlers/stop-message-stage-policy/decision.d.ts +9 -0
- package/dist/servertool/handlers/stop-message-stage-policy/decision.js +127 -0
- package/dist/servertool/handlers/stop-message-stage-policy/observation.d.ts +2 -0
- package/dist/servertool/handlers/stop-message-stage-policy/observation.js +179 -0
- package/dist/servertool/handlers/stop-message-stage-policy/templates.d.ts +4 -0
- package/dist/servertool/handlers/stop-message-stage-policy/templates.js +96 -0
- package/dist/servertool/handlers/stop-message-stage-policy/text-utils.d.ts +9 -0
- package/dist/servertool/handlers/stop-message-stage-policy/text-utils.js +89 -0
- package/dist/servertool/handlers/stop-message-stage-policy/types.d.ts +59 -0
- package/dist/servertool/handlers/stop-message-stage-policy/types.js +1 -0
- package/dist/servertool/handlers/stop-message-stage-policy.d.ts +3 -43
- package/dist/servertool/handlers/stop-message-stage-policy.js +2 -684
- package/dist/servertool/handlers/web-search.js +117 -0
- package/dist/servertool/server-side-tools.d.ts +0 -1
- package/dist/servertool/server-side-tools.js +4 -3
- package/dist/sse/sse-to-json/builders/response-builder.js +16 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +1 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +110 -37
- package/dist/telemetry/stats-center.d.ts +9 -0
- package/dist/telemetry/stats-center.js +29 -1
- package/dist/tools/apply-patch/structured/coercion.js +3 -11
- package/dist/tools/exec-command/validator.d.ts +1 -0
- package/dist/tools/exec-command/validator.js +132 -0
- package/dist/tools/tool-registry.d.ts +1 -0
- package/dist/tools/tool-registry.js +1 -1
- 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
|
|
909
|
-
|
|
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
|
|
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
|
-
//
|
|
1547
|
-
//
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
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
|
|
1562
|
-
content =
|
|
1628
|
+
if (typeof lastMessage.content === 'string') {
|
|
1629
|
+
content = lastMessage.content;
|
|
1563
1630
|
}
|
|
1564
|
-
else if (Array.isArray(
|
|
1565
|
-
const parts =
|
|
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:
|
|
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
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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
|
-
|
|
44
|
-
|
|
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
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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:
|
|
400
|
-
output_tokens:
|
|
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;
|