@jsonstudio/llms 0.6.1449 → 0.6.1643
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/codecs/gemini-openai-codec.js +6 -1
- package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.d.ts +4 -6
- package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.js +179 -41
- package/dist/conversion/compat/actions/antigravity-thought-signature-cache.js +73 -14
- package/dist/conversion/compat/actions/antigravity-thought-signature-prepare.js +165 -10
- package/dist/conversion/compat/actions/gemini-cli-request.js +72 -13
- package/dist/conversion/compat/antigravity-session-signature.d.ts +68 -1
- package/dist/conversion/compat/antigravity-session-signature.js +833 -21
- package/dist/conversion/compat/profiles/anthropic-claude-code.json +17 -0
- package/dist/conversion/compat/profiles/chat-gemini-cli.json +1 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +33 -8
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +17 -1
- package/dist/conversion/hub/pipeline/compat/compat-profile-store.js +12 -3
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +1 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +24 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +20 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +26 -1
- package/dist/conversion/hub/process/chat-process.js +300 -67
- package/dist/conversion/hub/response/provider-response.js +4 -3
- package/dist/conversion/shared/gemini-tool-utils.js +134 -9
- package/dist/conversion/shared/text-markup-normalizer.js +90 -1
- package/dist/conversion/shared/thought-signature-validator.d.ts +1 -1
- package/dist/conversion/shared/thought-signature-validator.js +2 -1
- package/dist/quota/apikey-reset.d.ts +17 -0
- package/dist/quota/apikey-reset.js +43 -0
- package/dist/quota/index.d.ts +2 -0
- package/dist/quota/index.js +1 -0
- package/dist/quota/quota-manager.d.ts +44 -0
- package/dist/quota/quota-manager.js +491 -0
- package/dist/quota/quota-state.d.ts +6 -0
- package/dist/quota/quota-state.js +167 -0
- package/dist/quota/types.d.ts +61 -0
- package/dist/quota/types.js +1 -0
- package/dist/router/virtual-router/bootstrap.js +103 -6
- package/dist/router/virtual-router/engine-health.js +104 -0
- package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +18 -0
- package/dist/router/virtual-router/engine-selection/tier-priority.d.ts +1 -2
- package/dist/router/virtual-router/engine-selection/tier-priority.js +2 -2
- package/dist/router/virtual-router/engine-selection/tier-selection-select.js +34 -10
- package/dist/router/virtual-router/engine-selection/tier-selection.js +250 -6
- package/dist/router/virtual-router/engine-selection.js +2 -2
- package/dist/router/virtual-router/engine.d.ts +16 -1
- package/dist/router/virtual-router/engine.js +320 -42
- package/dist/router/virtual-router/features.js +20 -2
- package/dist/router/virtual-router/success-center.d.ts +10 -0
- package/dist/router/virtual-router/success-center.js +32 -0
- package/dist/router/virtual-router/types.d.ts +48 -0
- package/dist/servertool/clock/config.d.ts +2 -0
- package/dist/servertool/clock/config.js +10 -2
- package/dist/servertool/clock/daemon.js +3 -0
- package/dist/servertool/clock/ntp.d.ts +18 -0
- package/dist/servertool/clock/ntp.js +318 -0
- package/dist/servertool/clock/paths.d.ts +1 -0
- package/dist/servertool/clock/paths.js +3 -0
- package/dist/servertool/clock/state.d.ts +2 -0
- package/dist/servertool/clock/state.js +15 -2
- package/dist/servertool/clock/tasks.d.ts +1 -0
- package/dist/servertool/clock/tasks.js +24 -1
- package/dist/servertool/clock/types.d.ts +21 -0
- package/dist/servertool/engine.js +105 -1
- package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.d.ts +1 -0
- package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.js +201 -0
- package/dist/servertool/handlers/clock-auto.js +39 -4
- package/dist/servertool/handlers/clock.js +145 -16
- package/dist/servertool/handlers/followup-request-builder.js +84 -0
- package/dist/servertool/handlers/stop-message-auto.js +1 -1
- package/dist/servertool/server-side-tools.d.ts +1 -0
- package/dist/servertool/server-side-tools.js +1 -0
- package/dist/servertool/types.d.ts +2 -0
- package/dist/tools/apply-patch/execution-capturer.js +24 -3
- package/package.json +3 -2
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "anthropic:claude-code",
|
|
3
|
+
"protocol": "anthropic-messages",
|
|
4
|
+
"request": {
|
|
5
|
+
"mappings": [
|
|
6
|
+
{ "action": "snapshot", "phase": "compat-pre" },
|
|
7
|
+
{
|
|
8
|
+
"action": "anthropic_claude_code_system_prompt",
|
|
9
|
+
"config": { "preserveExistingSystemAsUserMessage": true }
|
|
10
|
+
},
|
|
11
|
+
{ "action": "snapshot", "phase": "compat-post" }
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"response": {
|
|
15
|
+
"mappings": []
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -6,6 +6,7 @@ import { prepareGeminiToolsForBridge, buildGeminiToolsFromBridge } from '../../.
|
|
|
6
6
|
import { ensureProtocolState, getProtocolState } from '../../../shared/protocol-state.js';
|
|
7
7
|
import { sanitizeReasoningTaggedText } from '../../../shared/reasoning-utils.js';
|
|
8
8
|
import { applyClaudeThinkingToolSchemaCompat } from '../../../compat/actions/claude-thinking-tools.js';
|
|
9
|
+
import { extractAntigravityGeminiSessionId } from '../../../compat/antigravity-session-signature.js';
|
|
9
10
|
const GENERATION_CONFIG_KEYS = [
|
|
10
11
|
{ source: 'temperature', target: 'temperature' },
|
|
11
12
|
{ source: 'topP', target: 'top_p' },
|
|
@@ -660,23 +661,25 @@ function buildGeminiRequestFromChat(chat, metadata) {
|
|
|
660
661
|
const isAntigravityProvider = providerIdPrefix === 'antigravity';
|
|
661
662
|
const isGeminiCliProvider = providerIdPrefix === 'gemini-cli';
|
|
662
663
|
const requiresThoughtSignature = isAntigravityProvider || isGeminiCliProvider;
|
|
664
|
+
const parameters = chat.parameters && typeof chat.parameters === 'object' ? chat.parameters : {};
|
|
663
665
|
const isAntigravityClaudeThinking = providerIdPrefix === 'antigravity' &&
|
|
664
|
-
typeof
|
|
665
|
-
|
|
666
|
-
const keepReasoning = Boolean(
|
|
667
|
-
Boolean(
|
|
666
|
+
typeof parameters.model === 'string' &&
|
|
667
|
+
String(parameters.model).includes('claude-sonnet-4-5-thinking');
|
|
668
|
+
const keepReasoning = Boolean(parameters.keep_thinking) ||
|
|
669
|
+
Boolean(parameters.keep_reasoning);
|
|
668
670
|
const stripReasoningTags = isAntigravityProvider &&
|
|
669
|
-
typeof
|
|
670
|
-
|
|
671
|
+
typeof parameters.model === 'string' &&
|
|
672
|
+
String(parameters.model).startsWith('claude-') &&
|
|
671
673
|
!keepReasoning;
|
|
672
674
|
// Cloud Code / Antigravity requires stable tool call IDs in context (maps to tool_use.id),
|
|
673
675
|
// while standard Gemini endpoints do not require (and may reject) extra id fields.
|
|
674
676
|
const includeToolCallIds = providerIdPrefix === 'antigravity';
|
|
675
677
|
// Function calling protocol:
|
|
676
|
-
// - For gemini-cli.* we
|
|
678
|
+
// - For gemini-cli.* we allow structured tool loops when tools are present (Codex/agent clients),
|
|
679
|
+
// otherwise keep a conservative path (text-only tool transcripts).
|
|
677
680
|
// - For antigravity.* and other Gemini backends, send tool schemas and emit functionCall/functionResponse parts
|
|
678
681
|
// so tool loops remain structured and recoverable.
|
|
679
|
-
const allowFunctionCallingProtocol = providerIdPrefix !== 'gemini-cli';
|
|
682
|
+
const allowFunctionCallingProtocol = providerIdPrefix !== 'gemini-cli' || (Array.isArray(chat.tools) && chat.tools.length > 0);
|
|
680
683
|
const omitFunctionCallPartsForCli = !allowFunctionCallingProtocol;
|
|
681
684
|
const semanticsNode = readGeminiSemantics(chat);
|
|
682
685
|
const systemTextBlocksFromSemantics = readSystemTextBlocksFromSemantics(chat);
|
|
@@ -959,12 +962,27 @@ function buildGeminiRequestFromChat(chat, metadata) {
|
|
|
959
962
|
}
|
|
960
963
|
deepCleanUndefined(requestPayload);
|
|
961
964
|
const mappedLower = String(requestPayload.model || '').toLowerCase();
|
|
965
|
+
const isFlashModel = mappedLower.includes('flash');
|
|
962
966
|
const isImageModel = config.requestType === 'image_gen' || mappedLower.includes('image');
|
|
963
967
|
const isThinkingModel = !isImageModel && (mappedLower.includes('think') || mappedLower.includes('pro'));
|
|
964
968
|
if (isThinkingModel && (!requestPayload.generationConfig || !isJsonObject(requestPayload.generationConfig))) {
|
|
965
969
|
requestPayload.generationConfig = {};
|
|
966
970
|
}
|
|
967
971
|
const generationConfig = requestPayload.generationConfig;
|
|
972
|
+
if (isFlashModel && isJsonObject(generationConfig)) {
|
|
973
|
+
// Antigravity-Manager alignment: Gemini Flash models reject overly-large thinking budgets.
|
|
974
|
+
// Clamp proactively to avoid 400 Bad Request when clients set an aggressive budget.
|
|
975
|
+
const MAX_FLASH_THINKING_BUDGET = 24576;
|
|
976
|
+
const gc = generationConfig;
|
|
977
|
+
const thinkingConfigRaw = gc.thinkingConfig;
|
|
978
|
+
const thinkingConfig = isJsonObject(thinkingConfigRaw) ? thinkingConfigRaw : undefined;
|
|
979
|
+
const budgetRaw = thinkingConfig && thinkingConfig.thinkingBudget;
|
|
980
|
+
const budget = typeof budgetRaw === 'number' && Number.isFinite(budgetRaw) ? budgetRaw : undefined;
|
|
981
|
+
if (thinkingConfig && budget !== undefined && budget > MAX_FLASH_THINKING_BUDGET) {
|
|
982
|
+
thinkingConfig.thinkingBudget = MAX_FLASH_THINKING_BUDGET;
|
|
983
|
+
gc.thinkingConfig = thinkingConfig;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
968
986
|
if (isThinkingModel && isJsonObject(generationConfig)) {
|
|
969
987
|
const gc = generationConfig;
|
|
970
988
|
const thinkingConfig = isJsonObject(gc.thinkingConfig)
|
|
@@ -1061,6 +1079,13 @@ function buildGeminiRequestFromChat(chat, metadata) {
|
|
|
1061
1079
|
request.metadata[key] = value;
|
|
1062
1080
|
}
|
|
1063
1081
|
}
|
|
1082
|
+
if (isAntigravityProvider) {
|
|
1083
|
+
request.metadata = request.metadata ?? {};
|
|
1084
|
+
const existing = request.metadata.antigravitySessionId;
|
|
1085
|
+
if (typeof existing !== 'string' || !existing.trim()) {
|
|
1086
|
+
request.metadata.antigravitySessionId = extractAntigravityGeminiSessionId(request);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1064
1089
|
// Apply claude-thinking compat at Gemini mapping time to ensure it is always active
|
|
1065
1090
|
// for Claude models, regardless of compatibilityProfile wiring. Provider层负责进一步的
|
|
1066
1091
|
// 传输层收紧(如 session_id / generationConfig),这里不做非标裁剪。
|
|
@@ -28,6 +28,9 @@ export function runRequestCompatPipeline(profileId, payload, options) {
|
|
|
28
28
|
if (!profile) {
|
|
29
29
|
return { payload };
|
|
30
30
|
}
|
|
31
|
+
if (!isProtocolCompatible(profile, options?.adapterContext)) {
|
|
32
|
+
return { payload };
|
|
33
|
+
}
|
|
31
34
|
const stage = pickStageConfig(profile, 'request');
|
|
32
35
|
if (!stage) {
|
|
33
36
|
return { payload };
|
|
@@ -49,6 +52,9 @@ export function runResponseCompatPipeline(profileId, payload, options) {
|
|
|
49
52
|
if (!profile) {
|
|
50
53
|
return { payload };
|
|
51
54
|
}
|
|
55
|
+
if (!isProtocolCompatible(profile, options?.adapterContext)) {
|
|
56
|
+
return { payload };
|
|
57
|
+
}
|
|
52
58
|
const stage = pickStageConfig(profile, 'response');
|
|
53
59
|
if (!stage) {
|
|
54
60
|
return { payload };
|
|
@@ -95,6 +101,16 @@ function pickStageConfig(profile, stage) {
|
|
|
95
101
|
}
|
|
96
102
|
return null;
|
|
97
103
|
}
|
|
104
|
+
function isProtocolCompatible(profile, adapterContext) {
|
|
105
|
+
const required = typeof profile.protocol === 'string' ? profile.protocol.trim().toLowerCase() : '';
|
|
106
|
+
if (!required) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
const actual = typeof adapterContext?.providerProtocol === 'string' && adapterContext.providerProtocol.trim()
|
|
110
|
+
? adapterContext.providerProtocol.trim().toLowerCase()
|
|
111
|
+
: '';
|
|
112
|
+
return Boolean(actual) && actual === required;
|
|
113
|
+
}
|
|
98
114
|
function applyMapping(root, mapping, state) {
|
|
99
115
|
switch (mapping.action) {
|
|
100
116
|
case 'remove':
|
|
@@ -221,7 +237,7 @@ function applyMapping(root, mapping, state) {
|
|
|
221
237
|
break;
|
|
222
238
|
case 'anthropic_claude_code_system_prompt':
|
|
223
239
|
if (state.direction === 'request') {
|
|
224
|
-
replaceRoot(root, applyAnthropicClaudeCodeSystemPromptCompat(root, mapping.config));
|
|
240
|
+
replaceRoot(root, applyAnthropicClaudeCodeSystemPromptCompat(root, mapping.config, state.adapterContext));
|
|
225
241
|
}
|
|
226
242
|
break;
|
|
227
243
|
case 'glm_image_content':
|
|
@@ -16,10 +16,18 @@ function normalizeProfiles(profiles) {
|
|
|
16
16
|
if (!id) {
|
|
17
17
|
continue;
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
const normalized = {
|
|
20
20
|
...profile,
|
|
21
21
|
id
|
|
22
|
-
}
|
|
22
|
+
};
|
|
23
|
+
// Treat profile IDs as case-insensitive for lookup purposes.
|
|
24
|
+
// Many configs are hand-authored and may use different casing (e.g. "Chat:Claude-Code"),
|
|
25
|
+
// while built-in profiles are lower-case.
|
|
26
|
+
map.set(id, normalized);
|
|
27
|
+
const lower = id.toLowerCase();
|
|
28
|
+
if (lower !== id) {
|
|
29
|
+
map.set(lower, normalized);
|
|
30
|
+
}
|
|
23
31
|
}
|
|
24
32
|
return map;
|
|
25
33
|
}
|
|
@@ -72,5 +80,6 @@ export function getCompatProfile(profileId) {
|
|
|
72
80
|
if (!profileMap) {
|
|
73
81
|
profileMap = buildProfileMap();
|
|
74
82
|
}
|
|
75
|
-
|
|
83
|
+
const key = profileId.trim();
|
|
84
|
+
return profileMap.get(key) ?? profileMap.get(key.toLowerCase()) ?? null;
|
|
76
85
|
}
|
|
@@ -76,6 +76,7 @@ export declare class HubPipeline {
|
|
|
76
76
|
private readonly routerEngine;
|
|
77
77
|
private config;
|
|
78
78
|
private unsubscribeProviderErrors?;
|
|
79
|
+
private unsubscribeProviderSuccess?;
|
|
79
80
|
constructor(config: HubPipelineConfig);
|
|
80
81
|
updateRuntimeDeps(deps: {
|
|
81
82
|
healthStore?: HubPipelineConfig['healthStore'] | null;
|
|
@@ -2,6 +2,7 @@ import { Readable } from 'node:stream';
|
|
|
2
2
|
import { isJsonObject, jsonClone } from '../types/json.js';
|
|
3
3
|
import { VirtualRouterEngine } from '../../../router/virtual-router/engine.js';
|
|
4
4
|
import { providerErrorCenter } from '../../../router/virtual-router/error-center.js';
|
|
5
|
+
import { providerSuccessCenter } from '../../../router/virtual-router/success-center.js';
|
|
5
6
|
import { defaultSseCodecRegistry } from '../../../sse/index.js';
|
|
6
7
|
import { ResponsesFormatAdapter } from '../format-adapters/responses-format-adapter.js';
|
|
7
8
|
import { ResponsesSemanticMapper } from '../semantic-mappers/responses-mapper.js';
|
|
@@ -111,6 +112,7 @@ export class HubPipeline {
|
|
|
111
112
|
routerEngine;
|
|
112
113
|
config;
|
|
113
114
|
unsubscribeProviderErrors;
|
|
115
|
+
unsubscribeProviderSuccess;
|
|
114
116
|
constructor(config) {
|
|
115
117
|
this.config = config;
|
|
116
118
|
this.routerEngine = new VirtualRouterEngine({
|
|
@@ -133,6 +135,19 @@ export class HubPipeline {
|
|
|
133
135
|
catch {
|
|
134
136
|
this.unsubscribeProviderErrors = undefined;
|
|
135
137
|
}
|
|
138
|
+
try {
|
|
139
|
+
this.unsubscribeProviderSuccess = providerSuccessCenter.subscribe((event) => {
|
|
140
|
+
try {
|
|
141
|
+
this.routerEngine.handleProviderSuccess(event);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// ignore subscriber errors
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
this.unsubscribeProviderSuccess = undefined;
|
|
150
|
+
}
|
|
136
151
|
}
|
|
137
152
|
updateRuntimeDeps(deps) {
|
|
138
153
|
if (!deps || typeof deps !== 'object') {
|
|
@@ -175,6 +190,15 @@ export class HubPipeline {
|
|
|
175
190
|
}
|
|
176
191
|
this.unsubscribeProviderErrors = undefined;
|
|
177
192
|
}
|
|
193
|
+
if (this.unsubscribeProviderSuccess) {
|
|
194
|
+
try {
|
|
195
|
+
this.unsubscribeProviderSuccess();
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
// ignore dispose failures
|
|
199
|
+
}
|
|
200
|
+
this.unsubscribeProviderSuccess = undefined;
|
|
201
|
+
}
|
|
178
202
|
}
|
|
179
203
|
async executeRequestStagePipeline(normalized, hooks) {
|
|
180
204
|
const formatAdapter = hooks.createFormatAdapter();
|
package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { chatEnvelopeToStandardized } from '../../../../standardized-bridge.js';
|
|
2
2
|
import { validateChatEnvelope } from '../../../../../shared/chat-envelope-validator.js';
|
|
3
|
+
import { buildAnthropicToolAliasMap } from '../../../../../shared/anthropic-message-utils.js';
|
|
3
4
|
import { applyHubOperationTableInbound } from '../../../../operation-table/operation-table-runner.js';
|
|
4
5
|
import { recordStage } from '../../../stages/utils.js';
|
|
5
6
|
import { isJsonObject, jsonClone } from '../../../../types/json.js';
|
|
@@ -27,6 +28,25 @@ export async function runReqInboundStage2SemanticMap(options) {
|
|
|
27
28
|
if (rawTools.length && toolsNode.clientToolsRaw === undefined) {
|
|
28
29
|
toolsNode.clientToolsRaw = jsonClone(rawTools);
|
|
29
30
|
}
|
|
31
|
+
// /v1/messages tool names are case-sensitive to the client (e.g. Bash/Glob/Read).
|
|
32
|
+
// Capture an alias map here (from the *raw* client tools) so later response remap
|
|
33
|
+
// can convert canonical tool calls (e.g. shell_command/glob/read) back to the
|
|
34
|
+
// original client tool names.
|
|
35
|
+
try {
|
|
36
|
+
const protocol = String(options.formatEnvelope?.protocol || '').toLowerCase();
|
|
37
|
+
const endpoint = String(options.adapterContext?.entryEndpoint || '').toLowerCase();
|
|
38
|
+
const shouldCapture = protocol === 'anthropic-messages' || endpoint.includes('/v1/messages');
|
|
39
|
+
const hasAliasMap = isJsonObject(toolsNode.toolNameAliasMap) || isJsonObject(toolsNode.toolAliasMap);
|
|
40
|
+
if (shouldCapture && !hasAliasMap && rawTools.length) {
|
|
41
|
+
const aliasMap = buildAnthropicToolAliasMap(rawTools);
|
|
42
|
+
if (aliasMap) {
|
|
43
|
+
toolsNode.toolNameAliasMap = jsonClone(aliasMap);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// best-effort: never block request handling due to alias map propagation failures
|
|
49
|
+
}
|
|
30
50
|
if (options.responsesResume && isJsonObject(options.responsesResume)) {
|
|
31
51
|
if (!semantics.responses || !isJsonObject(semantics.responses)) {
|
|
32
52
|
semantics.responses = {};
|
package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { isJsonObject, jsonClone } from '../../../../types/json.js';
|
|
1
2
|
import { buildAnthropicResponseFromChat } from '../../../../response/response-runtime.js';
|
|
2
3
|
import { buildResponsesPayloadFromChat } from '../../../../../responses/responses-openai-bridge.js';
|
|
4
|
+
import { buildAnthropicToolAliasMap } from '../../../../../shared/anthropic-message-utils.js';
|
|
3
5
|
import { recordStage } from '../../../stages/utils.js';
|
|
4
6
|
export function runRespOutboundStage1ClientRemap(options) {
|
|
5
7
|
let clientPayload;
|
|
@@ -18,6 +20,16 @@ export function runRespOutboundStage1ClientRemap(options) {
|
|
|
18
20
|
...(toolsRaw ? { toolsRaw } : {})
|
|
19
21
|
});
|
|
20
22
|
}
|
|
23
|
+
// Preserve upstream error envelope when present (used by host status mapping + servertool auto flows).
|
|
24
|
+
try {
|
|
25
|
+
const err = options.payload.error;
|
|
26
|
+
if (isJsonObject(err)) {
|
|
27
|
+
clientPayload.error = jsonClone(err);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// best-effort
|
|
32
|
+
}
|
|
21
33
|
recordStage(options.stageRecorder, 'chat_process.resp.stage9.client_remap', clientPayload);
|
|
22
34
|
return clientPayload;
|
|
23
35
|
}
|
|
@@ -29,7 +41,20 @@ function resolveAliasMapFromSemantics(semantics) {
|
|
|
29
41
|
if (!toolsNode || typeof toolsNode !== 'object' || Array.isArray(toolsNode)) {
|
|
30
42
|
return undefined;
|
|
31
43
|
}
|
|
32
|
-
const
|
|
44
|
+
const toolsRecord = toolsNode;
|
|
45
|
+
// Prefer explicit alias map.
|
|
46
|
+
const candidate = toolsRecord.toolNameAliasMap;
|
|
47
|
+
const fromCandidate = normalizeAliasMap(candidate);
|
|
48
|
+
if (fromCandidate) {
|
|
49
|
+
return fromCandidate;
|
|
50
|
+
}
|
|
51
|
+
// Fallback: derive from captured raw client tools if present.
|
|
52
|
+
// This covers callers that captured `clientToolsRaw` but did not persist `toolNameAliasMap`.
|
|
53
|
+
const rawTools = toolsRecord.clientToolsRaw;
|
|
54
|
+
const derived = buildAnthropicToolAliasMap(rawTools);
|
|
55
|
+
return normalizeAliasMap(derived);
|
|
56
|
+
}
|
|
57
|
+
function normalizeAliasMap(candidate) {
|
|
33
58
|
if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
|
|
34
59
|
return undefined;
|
|
35
60
|
}
|