@jsonstudio/llms 0.6.1172 → 0.6.1397
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.d.ts +3 -1
- package/dist/conversion/codecs/gemini-openai-codec.js +10 -4
- package/dist/conversion/compat/actions/gemini-web-search.d.ts +1 -1
- package/dist/conversion/compat/actions/gemini-web-search.js +5 -2
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.d.ts +12 -0
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.js +199 -0
- package/dist/conversion/compat/actions/iflow-web-search.d.ts +1 -1
- package/dist/conversion/compat/actions/iflow-web-search.js +5 -2
- package/dist/conversion/compat/profiles/chat-gemini.json +5 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +47 -56
- package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +1 -13
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +748 -52
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +18 -38
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +6 -0
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +3 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/adapter-context.d.ts +10 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/adapter-context.js +142 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/anthropic-alias-map.d.ts +6 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/anthropic-alias-map.js +79 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/apply-patch-tool-mode.d.ts +3 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/apply-patch-tool-mode.js +46 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/execute-chat-process-entry.d.ts +8 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/execute-chat-process-entry.js +366 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/execute-request-stage.d.ts +9 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/execute-request-stage.js +390 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/node-results.d.ts +3 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/node-results.js +14 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/payload-normalize.d.ts +2 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/payload-normalize.js +144 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/policy.d.ts +4 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/policy.js +32 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/protocol.d.ts +8 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/protocol.js +63 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/resolve-protocol-hooks.d.ts +2 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/resolve-protocol-hooks.js +43 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/semantic-gate.d.ts +1 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/semantic-gate.js +29 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/servertool-runtime-config.d.ts +2 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/servertool-runtime-config.js +16 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/types.d.ts +116 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/types.js +1 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +3 -95
- package/dist/conversion/hub/pipeline/hub-pipeline.js +19 -1281
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.js +1 -1
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +7 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +65 -1
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +25 -22
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +1 -1
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_format_build/index.d.ts +1 -1
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_format_build/index.js +2 -2
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_thought_signature_inject/index.d.ts +10 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_thought_signature_inject/index.js +172 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +2 -2
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.js +1 -1
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.js +1 -1
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +11 -11
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage2_format_parse/index.js +1 -1
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.d.ts +1 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.js +4 -2
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_thought_signature_capture/index.d.ts +10 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_thought_signature_capture/index.js +71 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.d.ts +1 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +17 -9
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.js +2 -2
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +40 -2
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.js +1 -1
- package/dist/conversion/hub/pipeline/target-utils.js +9 -5
- package/dist/conversion/hub/pipeline/thought-signature/thought-signature-center.d.ts +14 -0
- package/dist/conversion/hub/pipeline/thought-signature/thought-signature-center.js +289 -0
- package/dist/conversion/hub/process/chat-process.js +256 -16
- package/dist/conversion/hub/response/provider-response.d.ts +8 -0
- package/dist/conversion/hub/response/provider-response.js +91 -27
- package/dist/conversion/hub/response/response-mappers.d.ts +10 -3
- package/dist/conversion/hub/response/response-mappers.js +30 -6
- package/dist/conversion/hub/response/response-runtime.js +4 -38
- package/dist/conversion/hub/snapshot-recorder.js +5 -1
- package/dist/conversion/hub/standardized-bridge.js +23 -15
- package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.js +36 -5
- package/dist/conversion/responses/responses-openai-bridge.js +20 -4
- package/dist/conversion/shared/gemini-tool-utils.d.ts +8 -1
- package/dist/conversion/shared/gemini-tool-utils.js +580 -108
- package/dist/conversion/shared/jsonish.js +1 -1
- package/dist/conversion/shared/mcp-injection.js +67 -33
- package/dist/conversion/shared/openai-finalizer.js +2 -1
- package/dist/conversion/shared/openai-message-normalize.js +76 -21
- package/dist/conversion/shared/responses-output-builder.js +6 -0
- package/dist/conversion/shared/runtime-metadata.d.ts +7 -0
- package/dist/conversion/shared/runtime-metadata.js +23 -0
- package/dist/conversion/shared/text-markup-normalizer.d.ts +2 -0
- package/dist/conversion/shared/text-markup-normalizer.js +284 -4
- package/dist/conversion/shared/tool-canonicalizer.js +2 -1
- package/dist/conversion/shared/tool-governor.js +3 -3
- package/dist/filters/engine.js +5 -5
- package/dist/filters/special/request-tool-list-filter.js +194 -60
- package/dist/filters/special/request-tools-normalize.js +1 -1
- package/dist/filters/special/response-tool-text-canonicalize.d.ts +4 -7
- package/dist/filters/special/response-tool-text-canonicalize.js +7 -35
- package/dist/filters/special/tool-filter-hooks.js +58 -62
- package/dist/guidance/index.js +5 -1
- package/dist/http/sse-response.js +6 -6
- package/dist/router/virtual-router/bootstrap.js +54 -4
- package/dist/router/virtual-router/engine-health.d.ts +1 -1
- package/dist/router/virtual-router/engine-health.js +11 -110
- package/dist/router/virtual-router/engine-selection/alias-selection.d.ts +30 -0
- package/dist/router/virtual-router/engine-selection/alias-selection.js +237 -0
- package/dist/router/virtual-router/engine-selection/context-weight-multipliers.d.ts +11 -0
- package/dist/router/virtual-router/engine-selection/context-weight-multipliers.js +23 -0
- package/dist/router/virtual-router/engine-selection/direct-provider-model.d.ts +9 -0
- package/dist/router/virtual-router/engine-selection/direct-provider-model.js +49 -0
- package/dist/router/virtual-router/engine-selection/instruction-target.d.ts +6 -0
- package/dist/router/virtual-router/engine-selection/instruction-target.js +54 -0
- package/dist/router/virtual-router/engine-selection/key-parsing.d.ts +8 -0
- package/dist/router/virtual-router/engine-selection/key-parsing.js +64 -0
- package/dist/router/virtual-router/engine-selection/route-utils.d.ts +12 -0
- package/dist/router/virtual-router/engine-selection/route-utils.js +150 -0
- package/dist/router/virtual-router/engine-selection/routing-state-filter.d.ts +4 -0
- package/dist/router/virtual-router/engine-selection/routing-state-filter.js +50 -0
- package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +39 -0
- package/dist/router/virtual-router/engine-selection/selection-deps.js +1 -0
- package/dist/router/virtual-router/engine-selection/sticky-pool.d.ts +11 -0
- package/dist/router/virtual-router/engine-selection/sticky-pool.js +109 -0
- package/dist/router/virtual-router/engine-selection/tier-priority.d.ts +12 -0
- package/dist/router/virtual-router/engine-selection/tier-priority.js +55 -0
- package/dist/router/virtual-router/engine-selection/tier-selection-select.d.ts +22 -0
- package/dist/router/virtual-router/engine-selection/tier-selection-select.js +423 -0
- package/dist/router/virtual-router/engine-selection/tier-selection.d.ts +3 -0
- package/dist/router/virtual-router/engine-selection/tier-selection.js +228 -0
- package/dist/router/virtual-router/engine-selection.d.ts +4 -30
- package/dist/router/virtual-router/engine-selection.js +10 -962
- package/dist/router/virtual-router/engine.d.ts +1 -0
- package/dist/router/virtual-router/engine.js +64 -11
- package/dist/router/virtual-router/routing-instructions.js +6 -1
- package/dist/router/virtual-router/stop-message-state-sync.d.ts +5 -0
- package/dist/router/virtual-router/stop-message-state-sync.js +6 -14
- package/dist/router/virtual-router/types.d.ts +38 -1
- package/dist/servertool/clock/config.d.ts +8 -0
- package/dist/servertool/clock/config.js +22 -0
- package/dist/servertool/clock/log.d.ts +3 -0
- package/dist/servertool/clock/log.js +13 -0
- package/dist/servertool/clock/task-store.d.ts +1 -1
- package/dist/servertool/clock/task-store.js +1 -1
- package/dist/servertool/clock/tasks.js +1 -1
- package/dist/servertool/engine.js +146 -21
- package/dist/servertool/handlers/clock-auto.js +11 -6
- package/dist/servertool/handlers/clock.js +36 -10
- package/dist/servertool/handlers/followup-request-builder.js +8 -2
- package/dist/servertool/handlers/gemini-empty-reply-continue.js +15 -9
- package/dist/servertool/handlers/iflow-model-error-retry.js +6 -4
- package/dist/servertool/handlers/recursive-detection-guard.js +4 -2
- package/dist/servertool/handlers/stop-message-auto.js +100 -10
- package/dist/servertool/handlers/vision.js +4 -1
- package/dist/servertool/handlers/web-search.js +3 -1
- package/dist/servertool/pending-session.d.ts +19 -0
- package/dist/servertool/pending-session.js +97 -0
- package/dist/servertool/reenter-backend.js +5 -3
- package/dist/servertool/server-side-tools.js +235 -6
- package/dist/servertool/types.d.ts +13 -0
- package/dist/sse/json-to-sse/event-generators/responses.js +1 -1
- package/dist/sse/shared/chat-serializer.js +2 -2
- package/dist/sse/shared/constants.js +1 -1
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +7 -1
- package/dist/sse/sse-to-json/builders/response-builder.js +16 -0
- package/dist/sse/sse-to-json/responses-sse-to-json-converter.d.ts +1 -1
- package/dist/tools/apply-patch/execution-capturer.js +1 -1
- package/dist/tools/exec-command/normalize.js +4 -0
- package/dist/tools/exec-command/regression-capturer.js +1 -1
- package/package.json +10 -5
package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js
CHANGED
|
@@ -8,24 +8,28 @@ export function runRespOutboundStage1ClientRemap(options) {
|
|
|
8
8
|
}
|
|
9
9
|
else if (options.clientProtocol === 'anthropic-messages') {
|
|
10
10
|
clientPayload = buildAnthropicResponseFromChat(options.payload, {
|
|
11
|
-
aliasMap:
|
|
11
|
+
aliasMap: resolveAliasMapFromSemantics(options.requestSemantics)
|
|
12
12
|
});
|
|
13
13
|
}
|
|
14
14
|
else {
|
|
15
|
-
const toolsRaw =
|
|
15
|
+
const toolsRaw = resolveClientToolsRawFromSemantics(options.requestSemantics);
|
|
16
16
|
clientPayload = buildResponsesPayloadFromChat(options.payload, {
|
|
17
17
|
requestId: options.requestId,
|
|
18
18
|
...(toolsRaw ? { toolsRaw } : {})
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
|
-
recordStage(options.stageRecorder, '
|
|
21
|
+
recordStage(options.stageRecorder, 'chat_process.resp.stage9.client_remap', clientPayload);
|
|
22
22
|
return clientPayload;
|
|
23
23
|
}
|
|
24
|
-
function
|
|
25
|
-
if (!
|
|
24
|
+
function resolveAliasMapFromSemantics(semantics) {
|
|
25
|
+
if (!semantics || typeof semantics !== 'object' || Array.isArray(semantics)) {
|
|
26
26
|
return undefined;
|
|
27
27
|
}
|
|
28
|
-
const
|
|
28
|
+
const toolsNode = semantics.tools;
|
|
29
|
+
if (!toolsNode || typeof toolsNode !== 'object' || Array.isArray(toolsNode)) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
const candidate = toolsNode.toolNameAliasMap;
|
|
29
33
|
if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
|
|
30
34
|
return undefined;
|
|
31
35
|
}
|
|
@@ -43,11 +47,15 @@ function resolveAliasMapFromContext(adapterContext) {
|
|
|
43
47
|
}
|
|
44
48
|
return Object.keys(map).length ? map : undefined;
|
|
45
49
|
}
|
|
46
|
-
function
|
|
47
|
-
if (!
|
|
50
|
+
function resolveClientToolsRawFromSemantics(semantics) {
|
|
51
|
+
if (!semantics || typeof semantics !== 'object' || Array.isArray(semantics)) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const toolsNode = semantics.tools;
|
|
55
|
+
if (!toolsNode || typeof toolsNode !== 'object' || Array.isArray(toolsNode)) {
|
|
48
56
|
return undefined;
|
|
49
57
|
}
|
|
50
|
-
const candidate =
|
|
58
|
+
const candidate = toolsNode.clientToolsRaw;
|
|
51
59
|
if (!candidate || !Array.isArray(candidate)) {
|
|
52
60
|
return undefined;
|
|
53
61
|
}
|
package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { defaultSseCodecRegistry } from '../../../../../../sse/index.js';
|
|
|
2
2
|
import { recordStage } from '../../../stages/utils.js';
|
|
3
3
|
export async function runRespOutboundStage2SseStream(options) {
|
|
4
4
|
if (!options.wantsStream) {
|
|
5
|
-
recordStage(options.stageRecorder, '
|
|
5
|
+
recordStage(options.stageRecorder, 'chat_process.resp.stage10.sse_stream', {
|
|
6
6
|
passthrough: false,
|
|
7
7
|
protocol: options.clientProtocol,
|
|
8
8
|
payload: options.clientPayload
|
|
@@ -13,7 +13,7 @@ export async function runRespOutboundStage2SseStream(options) {
|
|
|
13
13
|
const stream = await codec.convertJsonToSse(options.clientPayload, {
|
|
14
14
|
requestId: options.requestId
|
|
15
15
|
});
|
|
16
|
-
recordStage(options.stageRecorder, '
|
|
16
|
+
recordStage(options.stageRecorder, 'chat_process.resp.stage10.sse_stream', {
|
|
17
17
|
passthrough: false,
|
|
18
18
|
protocol: options.clientProtocol,
|
|
19
19
|
payload: options.clientPayload
|
|
@@ -1,17 +1,55 @@
|
|
|
1
1
|
import { runChatResponseToolFilters } from '../../../../../shared/tool-filter-pipeline.js';
|
|
2
2
|
import { normalizeApplyPatchToolCallsOnResponse } from '../../../../../shared/tool-governor.js';
|
|
3
|
+
import { buildChatResponseFromResponses } from '../../../../../shared/responses-response-utils.js';
|
|
3
4
|
import { ToolGovernanceEngine } from '../../../../tool-governance/index.js';
|
|
4
5
|
import { recordStage } from '../../../stages/utils.js';
|
|
5
6
|
const toolGovernanceEngine = new ToolGovernanceEngine();
|
|
7
|
+
function isCanonicalChatCompletion(payload) {
|
|
8
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
const obj = payload;
|
|
12
|
+
const choices = Array.isArray(obj.choices) ? obj.choices : [];
|
|
13
|
+
if (!choices.length)
|
|
14
|
+
return false;
|
|
15
|
+
const first = choices[0] && typeof choices[0] === 'object' && !Array.isArray(choices[0]) ? choices[0] : null;
|
|
16
|
+
if (!first)
|
|
17
|
+
return false;
|
|
18
|
+
const msg = first.message;
|
|
19
|
+
return Boolean(msg && typeof msg === 'object' && !Array.isArray(msg));
|
|
20
|
+
}
|
|
21
|
+
function coerceToCanonicalChatCompletion(payload) {
|
|
22
|
+
if (isCanonicalChatCompletion(payload)) {
|
|
23
|
+
return payload;
|
|
24
|
+
}
|
|
25
|
+
// ServerTool followups may re-enter via the client protocol shape (e.g. OpenAI Responses object:'response').
|
|
26
|
+
// Response tool governance requires an OpenAI-chat-like surface (choices[].message) so text tool harvesting
|
|
27
|
+
// and tool governance remain a single fixed path.
|
|
28
|
+
try {
|
|
29
|
+
const coerced = buildChatResponseFromResponses(payload);
|
|
30
|
+
if (isCanonicalChatCompletion(coerced)) {
|
|
31
|
+
return coerced;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// best-effort: keep original payload when bridge fails
|
|
36
|
+
}
|
|
37
|
+
return payload;
|
|
38
|
+
}
|
|
6
39
|
export async function runRespProcessStage1ToolGovernance(options) {
|
|
7
|
-
const
|
|
40
|
+
const canonicalInput = coerceToCanonicalChatCompletion(options.payload);
|
|
41
|
+
recordStage(options.stageRecorder, 'chat_process.resp.stage6.canonicalize_chat_completion', {
|
|
42
|
+
converted: canonicalInput !== options.payload,
|
|
43
|
+
canonicalPayload: canonicalInput
|
|
44
|
+
});
|
|
45
|
+
const filtered = await runChatResponseToolFilters(canonicalInput, {
|
|
8
46
|
entryEndpoint: options.entryEndpoint,
|
|
9
47
|
requestId: options.requestId,
|
|
10
48
|
profile: 'openai-chat'
|
|
11
49
|
});
|
|
12
50
|
const patched = normalizeApplyPatchToolCallsOnResponse(filtered);
|
|
13
51
|
const { payload: governed, summary } = toolGovernanceEngine.governResponse(patched, options.clientProtocol);
|
|
14
|
-
recordStage(options.stageRecorder, '
|
|
52
|
+
recordStage(options.stageRecorder, 'chat_process.resp.stage7.tool_governance', {
|
|
15
53
|
summary,
|
|
16
54
|
applied: summary?.applied,
|
|
17
55
|
filteredPayload: patched,
|
package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.js
CHANGED
|
@@ -11,7 +11,7 @@ export async function runRespProcessStage2Finalize(options) {
|
|
|
11
11
|
const processedRequest = buildProcessedRequestFromChatResponse(finalized, {
|
|
12
12
|
stream: options.wantsStream
|
|
13
13
|
});
|
|
14
|
-
recordStage(options.stageRecorder, '
|
|
14
|
+
recordStage(options.stageRecorder, 'chat_process.resp.stage8.finalize', {
|
|
15
15
|
model: finalized.model,
|
|
16
16
|
stream: options.wantsStream
|
|
17
17
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ensureRuntimeMetadata } from '../../shared/runtime-metadata.js';
|
|
1
2
|
export function applyTargetMetadata(metadata, target, routeName, originalModel) {
|
|
2
3
|
if (!metadata || typeof metadata !== 'object') {
|
|
3
4
|
return;
|
|
@@ -9,11 +10,14 @@ export function applyTargetMetadata(metadata, target, routeName, originalModel)
|
|
|
9
10
|
metadata.providerType = target.providerType;
|
|
10
11
|
metadata.modelId = target.modelId;
|
|
11
12
|
metadata.processMode = target.processMode || 'chat';
|
|
12
|
-
if (target.forceWebSearch === true) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
if (target.forceWebSearch === true || target.forceVision === true) {
|
|
14
|
+
const rt = ensureRuntimeMetadata(metadata);
|
|
15
|
+
if (target.forceWebSearch === true) {
|
|
16
|
+
rt.forceWebSearch = true;
|
|
17
|
+
}
|
|
18
|
+
if (target.forceVision === true) {
|
|
19
|
+
rt.forceVision = true;
|
|
20
|
+
}
|
|
17
21
|
}
|
|
18
22
|
if (target.responsesConfig?.toolCallIdStyle) {
|
|
19
23
|
metadata.toolCallIdStyle = target.responsesConfig.toolCallIdStyle;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AdapterContext } from '../../types/chat-envelope.js';
|
|
2
|
+
import type { JsonObject } from '../../types/json.js';
|
|
3
|
+
export declare const SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
|
|
4
|
+
type LastEntry = {
|
|
5
|
+
text: string;
|
|
6
|
+
signature: string;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
};
|
|
9
|
+
export declare function buildThoughtSignatureSessionKey(ctx: AdapterContext, payload?: JsonObject): string | undefined;
|
|
10
|
+
export declare function cacheThoughtSignature(sessionKey: string, text: unknown, signature: unknown): void;
|
|
11
|
+
export declare function getCachedThoughtSignature(sessionKey: string, text: unknown): string | undefined;
|
|
12
|
+
export declare function getLastThoughtSignature(sessionKey: string): LastEntry | undefined;
|
|
13
|
+
export declare function shouldHandleThoughtSignature(ctx: AdapterContext): boolean;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
export const SKIP_THOUGHT_SIGNATURE = 'skip_thought_signature_validator';
|
|
6
|
+
const MEMORY_TTL_MS = 12 * 60 * 60 * 1000;
|
|
7
|
+
const DISK_TTL_MS = 12 * 60 * 60 * 1000;
|
|
8
|
+
const WRITE_INTERVAL_MS = 60 * 1000;
|
|
9
|
+
const MAX_ENTRIES_PER_SESSION = 50;
|
|
10
|
+
const MAX_SESSIONS = 200;
|
|
11
|
+
const TEXT_HASH_HEX_LEN = 16;
|
|
12
|
+
const sessionStores = new Map();
|
|
13
|
+
const sessionLast = new Map();
|
|
14
|
+
const diskEntries = new Map();
|
|
15
|
+
let dirty = false;
|
|
16
|
+
let writeTimer;
|
|
17
|
+
let cleanupTimer;
|
|
18
|
+
const stats = {
|
|
19
|
+
memoryHits: 0,
|
|
20
|
+
diskHits: 0,
|
|
21
|
+
misses: 0,
|
|
22
|
+
writes: 0,
|
|
23
|
+
lastWrite: 0
|
|
24
|
+
};
|
|
25
|
+
function resolveDefaultCachePath() {
|
|
26
|
+
const env = (process.env.ROUTECODEX_THOUGHT_SIGNATURE_CACHE_PATH ||
|
|
27
|
+
process.env.RCC_THOUGHT_SIGNATURE_CACHE_PATH ||
|
|
28
|
+
'').trim();
|
|
29
|
+
if (env)
|
|
30
|
+
return env;
|
|
31
|
+
const home = process.env.HOME || os.homedir() || '';
|
|
32
|
+
return path.join(home, '.routecodex', 'antigravity-signature-cache.json');
|
|
33
|
+
}
|
|
34
|
+
const persistencePath = resolveDefaultCachePath();
|
|
35
|
+
function now() {
|
|
36
|
+
return Date.now();
|
|
37
|
+
}
|
|
38
|
+
function normalizeText(value) {
|
|
39
|
+
if (typeof value !== 'string')
|
|
40
|
+
return undefined;
|
|
41
|
+
const trimmed = value.trim();
|
|
42
|
+
return trimmed.length ? trimmed : undefined;
|
|
43
|
+
}
|
|
44
|
+
function normalizeSignature(value) {
|
|
45
|
+
if (typeof value !== 'string')
|
|
46
|
+
return undefined;
|
|
47
|
+
const trimmed = value.trim();
|
|
48
|
+
return trimmed.length ? trimmed : undefined;
|
|
49
|
+
}
|
|
50
|
+
function hashText(text) {
|
|
51
|
+
return createHash('sha256').update(text, 'utf8').digest('hex').slice(0, TEXT_HASH_HEX_LEN);
|
|
52
|
+
}
|
|
53
|
+
function makeDiskKey(sessionKey, textHash) {
|
|
54
|
+
return `${sessionKey}:${textHash}`;
|
|
55
|
+
}
|
|
56
|
+
function ensureSession(sessionKey) {
|
|
57
|
+
let store = sessionStores.get(sessionKey);
|
|
58
|
+
if (!store) {
|
|
59
|
+
pruneSessionsIfNeeded();
|
|
60
|
+
store = new Map();
|
|
61
|
+
sessionStores.set(sessionKey, store);
|
|
62
|
+
}
|
|
63
|
+
return store;
|
|
64
|
+
}
|
|
65
|
+
function pruneSession(store) {
|
|
66
|
+
const cutoff = now() - MEMORY_TTL_MS;
|
|
67
|
+
for (const [key, entry] of store) {
|
|
68
|
+
if (entry.timestamp < cutoff) {
|
|
69
|
+
store.delete(key);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (store.size < MAX_ENTRIES_PER_SESSION)
|
|
73
|
+
return;
|
|
74
|
+
const entries = Array.from(store.entries()).sort((a, b) => a[1].timestamp - b[1].timestamp);
|
|
75
|
+
const toRemove = entries.slice(0, Math.floor(MAX_ENTRIES_PER_SESSION / 4));
|
|
76
|
+
for (const [key] of toRemove) {
|
|
77
|
+
store.delete(key);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function ensureCacheDir(filePath) {
|
|
81
|
+
try {
|
|
82
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// best-effort
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function loadPersistedCache() {
|
|
89
|
+
try {
|
|
90
|
+
if (!fs.existsSync(persistencePath))
|
|
91
|
+
return;
|
|
92
|
+
const raw = fs.readFileSync(persistencePath, 'utf-8');
|
|
93
|
+
if (!raw.trim())
|
|
94
|
+
return;
|
|
95
|
+
const parsed = JSON.parse(raw);
|
|
96
|
+
if (!parsed || parsed.version !== '1.0')
|
|
97
|
+
return;
|
|
98
|
+
const cutoff = now() - DISK_TTL_MS;
|
|
99
|
+
for (const [key, entry] of Object.entries(parsed.entries || {})) {
|
|
100
|
+
if (!entry || typeof entry.signature !== 'string')
|
|
101
|
+
continue;
|
|
102
|
+
const ts = typeof entry.timestamp === 'number' ? entry.timestamp : now();
|
|
103
|
+
if (ts < cutoff)
|
|
104
|
+
continue;
|
|
105
|
+
diskEntries.set(key, { signature: entry.signature, timestamp: ts });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// best-effort
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function schedulePersist() {
|
|
113
|
+
if (writeTimer)
|
|
114
|
+
return;
|
|
115
|
+
writeTimer = setInterval(() => {
|
|
116
|
+
if (dirty) {
|
|
117
|
+
persistCache();
|
|
118
|
+
}
|
|
119
|
+
}, WRITE_INTERVAL_MS);
|
|
120
|
+
if (typeof writeTimer.unref === 'function') {
|
|
121
|
+
writeTimer.unref();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function scheduleCleanup() {
|
|
125
|
+
if (cleanupTimer)
|
|
126
|
+
return;
|
|
127
|
+
cleanupTimer = setInterval(() => {
|
|
128
|
+
const cutoff = now() - MEMORY_TTL_MS;
|
|
129
|
+
for (const store of sessionStores.values()) {
|
|
130
|
+
for (const [key, entry] of store.entries()) {
|
|
131
|
+
if (entry.timestamp < cutoff) {
|
|
132
|
+
store.delete(key);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}, 30 * 60 * 1000);
|
|
137
|
+
if (typeof cleanupTimer.unref === 'function') {
|
|
138
|
+
cleanupTimer.unref();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function pruneSessionsIfNeeded() {
|
|
142
|
+
if (sessionStores.size < MAX_SESSIONS)
|
|
143
|
+
return;
|
|
144
|
+
const entries = [];
|
|
145
|
+
for (const key of sessionStores.keys()) {
|
|
146
|
+
const last = sessionLast.get(key);
|
|
147
|
+
entries.push({ key, ts: last?.timestamp ?? 0 });
|
|
148
|
+
}
|
|
149
|
+
entries.sort((a, b) => a.ts - b.ts);
|
|
150
|
+
const removeCount = Math.max(1, sessionStores.size - (MAX_SESSIONS - 1));
|
|
151
|
+
for (const entry of entries.slice(0, removeCount)) {
|
|
152
|
+
sessionStores.delete(entry.key);
|
|
153
|
+
sessionLast.delete(entry.key);
|
|
154
|
+
for (const diskKey of diskEntries.keys()) {
|
|
155
|
+
if (diskKey.startsWith(`${entry.key}:`)) {
|
|
156
|
+
diskEntries.delete(diskKey);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function persistCache() {
|
|
162
|
+
try {
|
|
163
|
+
ensureCacheDir(persistencePath);
|
|
164
|
+
const nowTs = now();
|
|
165
|
+
const validDisk = {};
|
|
166
|
+
for (const [key, entry] of diskEntries.entries()) {
|
|
167
|
+
if (nowTs - entry.timestamp <= DISK_TTL_MS) {
|
|
168
|
+
validDisk[key] = entry;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const merged = { ...validDisk };
|
|
172
|
+
for (const [sessionKey, store] of sessionStores.entries()) {
|
|
173
|
+
for (const [textHash, entry] of store.entries()) {
|
|
174
|
+
const diskKey = makeDiskKey(sessionKey, textHash);
|
|
175
|
+
merged[diskKey] = { signature: entry.signature, timestamp: entry.timestamp };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const data = {
|
|
179
|
+
version: '1.0',
|
|
180
|
+
memory_ttl_seconds: MEMORY_TTL_MS / 1000,
|
|
181
|
+
disk_ttl_seconds: DISK_TTL_MS / 1000,
|
|
182
|
+
entries: merged,
|
|
183
|
+
statistics: {
|
|
184
|
+
memory_hits: stats.memoryHits,
|
|
185
|
+
disk_hits: stats.diskHits,
|
|
186
|
+
misses: stats.misses,
|
|
187
|
+
writes: stats.writes + 1,
|
|
188
|
+
last_write: nowTs
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
const tmpPath = path.join(os.tmpdir(), `antigravity-cache-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
|
|
192
|
+
fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2), 'utf-8');
|
|
193
|
+
try {
|
|
194
|
+
fs.renameSync(tmpPath, persistencePath);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
fs.writeFileSync(persistencePath, fs.readFileSync(tmpPath));
|
|
198
|
+
try {
|
|
199
|
+
fs.unlinkSync(tmpPath);
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// ignore cleanup errors
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
stats.writes += 1;
|
|
206
|
+
stats.lastWrite = nowTs;
|
|
207
|
+
dirty = false;
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// best-effort
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
loadPersistedCache();
|
|
214
|
+
schedulePersist();
|
|
215
|
+
scheduleCleanup();
|
|
216
|
+
export function buildThoughtSignatureSessionKey(ctx, payload) {
|
|
217
|
+
const sessionId = typeof ctx.sessionId === 'string'
|
|
218
|
+
? String(ctx.sessionId).trim()
|
|
219
|
+
: typeof ctx.conversationId === 'string'
|
|
220
|
+
? String(ctx.conversationId).trim()
|
|
221
|
+
: typeof ctx.requestId === 'string'
|
|
222
|
+
? String(ctx.requestId).trim()
|
|
223
|
+
: '';
|
|
224
|
+
if (!sessionId)
|
|
225
|
+
return undefined;
|
|
226
|
+
const model = (payload && typeof payload.model === 'string' && String(payload.model).trim()) ||
|
|
227
|
+
(typeof ctx.clientModelId === 'string' ? String(ctx.clientModelId).trim() : '') ||
|
|
228
|
+
(typeof ctx.originalModelId === 'string' ? String(ctx.originalModelId).trim() : '');
|
|
229
|
+
const protocol = typeof ctx.providerProtocol === 'string' && ctx.providerProtocol.trim()
|
|
230
|
+
? ctx.providerProtocol.trim()
|
|
231
|
+
: 'unknown';
|
|
232
|
+
const modelKey = model || 'unknown';
|
|
233
|
+
return `${protocol}:${modelKey}:${sessionId}`;
|
|
234
|
+
}
|
|
235
|
+
export function cacheThoughtSignature(sessionKey, text, signature) {
|
|
236
|
+
const normalizedText = normalizeText(text);
|
|
237
|
+
const normalizedSignature = normalizeSignature(signature);
|
|
238
|
+
if (!sessionKey || !normalizedText || !normalizedSignature)
|
|
239
|
+
return;
|
|
240
|
+
const textHash = hashText(normalizedText);
|
|
241
|
+
const store = ensureSession(sessionKey);
|
|
242
|
+
if (store.size >= MAX_ENTRIES_PER_SESSION) {
|
|
243
|
+
pruneSession(store);
|
|
244
|
+
}
|
|
245
|
+
store.set(textHash, { signature: normalizedSignature, timestamp: now() });
|
|
246
|
+
sessionLast.set(sessionKey, { text: normalizedText, signature: normalizedSignature, timestamp: now() });
|
|
247
|
+
dirty = true;
|
|
248
|
+
}
|
|
249
|
+
export function getCachedThoughtSignature(sessionKey, text) {
|
|
250
|
+
if (!sessionKey)
|
|
251
|
+
return undefined;
|
|
252
|
+
const normalizedText = normalizeText(text);
|
|
253
|
+
if (!normalizedText)
|
|
254
|
+
return undefined;
|
|
255
|
+
const textHash = hashText(normalizedText);
|
|
256
|
+
const store = sessionStores.get(sessionKey);
|
|
257
|
+
if (store) {
|
|
258
|
+
const entry = store.get(textHash);
|
|
259
|
+
if (entry) {
|
|
260
|
+
if (now() - entry.timestamp <= MEMORY_TTL_MS) {
|
|
261
|
+
stats.memoryHits += 1;
|
|
262
|
+
return entry.signature;
|
|
263
|
+
}
|
|
264
|
+
store.delete(textHash);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const diskKey = makeDiskKey(sessionKey, textHash);
|
|
268
|
+
const diskEntry = diskEntries.get(diskKey);
|
|
269
|
+
if (diskEntry && now() - diskEntry.timestamp <= DISK_TTL_MS) {
|
|
270
|
+
stats.diskHits += 1;
|
|
271
|
+
const mem = ensureSession(sessionKey);
|
|
272
|
+
mem.set(textHash, { signature: diskEntry.signature, timestamp: now() });
|
|
273
|
+
return diskEntry.signature;
|
|
274
|
+
}
|
|
275
|
+
stats.misses += 1;
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
export function getLastThoughtSignature(sessionKey) {
|
|
279
|
+
if (!sessionKey)
|
|
280
|
+
return undefined;
|
|
281
|
+
return sessionLast.get(sessionKey);
|
|
282
|
+
}
|
|
283
|
+
export function shouldHandleThoughtSignature(ctx) {
|
|
284
|
+
const provider = typeof ctx.providerId === 'string' ? ctx.providerId.toLowerCase() : '';
|
|
285
|
+
if (provider === 'antigravity')
|
|
286
|
+
return true;
|
|
287
|
+
const profile = typeof ctx.profileId === 'string' ? ctx.profileId.toLowerCase() : '';
|
|
288
|
+
return profile.includes('antigravity');
|
|
289
|
+
}
|