@jsonstudio/llms 0.6.3685 → 0.6.3686
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/antigravity-thought-signature-cache.js +2 -22
- package/dist/conversion/compat/actions/deepseek-web-response.js +7 -0
- package/dist/conversion/compat/actions/field-mapping.js +153 -2
- package/dist/conversion/compat/actions/lmstudio-responses-input-stringify.js +104 -3
- package/dist/conversion/hub/node-support.js +1 -1
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +1 -9
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +28 -35
- package/dist/conversion/hub/pipeline/hub-pipeline.js +121 -197
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.d.ts +4 -4
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.js +37 -20
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +7 -6
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +41 -69
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/context-capture-orchestration.d.ts +0 -3
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/context-capture-orchestration.js +1 -2
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/context-factories.js +0 -2
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +0 -1
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/responses-context-snapshot.d.ts +2 -3
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/responses-context-snapshot.js +5 -18
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/context-merge.d.ts +2 -1
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/context-merge.js +16 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.d.ts +1 -1
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +52 -27
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.d.ts +0 -1
- 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.d.ts +1 -1
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.js +5 -9
- package/dist/conversion/hub/process/chat-process-continue-execution.js +3 -0
- package/dist/conversion/hub/process/chat-process-media.d.ts +2 -1
- package/dist/conversion/hub/process/chat-process-media.js +63 -9
- package/dist/conversion/hub/process/chat-process-session-usage.d.ts +6 -24
- package/dist/conversion/hub/process/chat-process-session-usage.js +101 -200
- package/dist/conversion/hub/response/provider-response.js +13 -13
- package/dist/conversion/hub/types/chat-envelope.d.ts +0 -1
- package/dist/conversion/pipeline/codecs/v2/openai-openai-pipeline.js +4 -0
- package/dist/conversion/responses/responses-openai-bridge.d.ts +0 -1
- package/dist/conversion/responses/responses-openai-bridge.js +34 -28
- package/dist/conversion/shared/anthropic-message-utils.js +1 -14
- package/dist/conversion/shared/reasoning-normalizer.js +22 -41
- package/dist/conversion/shared/responses-tool-utils.js +2 -3
- package/dist/conversion/shared/tool-governor.js +4 -2
- package/dist/native/router_hotpath_napi.node +0 -0
- package/dist/router/virtual-router/engine/routing-state/store.js +2 -21
- package/dist/router/virtual-router/engine-selection/native-chat-process-governed-filter-semantics.d.ts +0 -1
- package/dist/router/virtual-router/engine-selection/native-chat-process-governed-filter-semantics.js +0 -1
- package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.d.ts +0 -3
- package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.js +0 -72
- package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.d.ts +1 -1
- package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js +1 -1
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-edge-stage-semantics.d.ts +2 -2
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-edge-stage-semantics.js +96 -80
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-inbound-outbound-semantics.d.ts +1 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-inbound-outbound-semantics.js +29 -0
- package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +2 -6
- package/dist/router/virtual-router/engine.js +6 -9
- package/dist/router/virtual-router/routing-instructions/state.js +27 -37
- package/dist/router/virtual-router/routing-instructions/types.d.ts +4 -6
- package/dist/router/virtual-router/token-estimator.js +0 -21
- package/dist/servertool/handlers/stop-message-auto.js +1 -11
- package/dist/tools/apply-patch/execution-capturer.d.ts +1 -1
- package/dist/tools/apply-patch/execution-capturer.js +2 -1
- package/dist/tools/apply-patch/regression-capturer.js +1 -2
- package/dist/tools/tool-registry.js +2 -1
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { analyzeChatProcessMedia, stripChatProcessHistoricalImages } from
|
|
1
|
+
import { analyzeChatProcessMedia, stripChatProcessHistoricalImages, } from "../../../router/virtual-router/engine-selection/native-router-hotpath.js";
|
|
2
2
|
export function stripHistoricalImageAttachments(messages) {
|
|
3
3
|
if (!Array.isArray(messages) || !messages.length) {
|
|
4
4
|
return messages;
|
|
5
5
|
}
|
|
6
|
-
const placeholderText =
|
|
6
|
+
const placeholderText = "[Image omitted]";
|
|
7
7
|
const stripped = stripChatProcessHistoricalImages(messages, placeholderText);
|
|
8
8
|
if (stripped.changed !== true || !Array.isArray(stripped.messages)) {
|
|
9
9
|
return messages;
|
|
@@ -12,17 +12,17 @@ export function stripHistoricalImageAttachments(messages) {
|
|
|
12
12
|
}
|
|
13
13
|
const INLINE_MEDIA_DATA_RE = /data:(image|video)\/[a-z0-9.+-]+;base64,[a-z0-9+/=\s]+/i;
|
|
14
14
|
function isVisualToolMessage(message) {
|
|
15
|
-
if (!message || typeof message !==
|
|
15
|
+
if (!message || typeof message !== "object") {
|
|
16
16
|
return false;
|
|
17
17
|
}
|
|
18
|
-
if (message.role !==
|
|
18
|
+
if (message.role !== "tool") {
|
|
19
19
|
return false;
|
|
20
20
|
}
|
|
21
|
-
const name = typeof message.name ===
|
|
22
|
-
if (name ===
|
|
21
|
+
const name = typeof message.name === "string" ? message.name.trim().toLowerCase() : "";
|
|
22
|
+
if (name === "view_image") {
|
|
23
23
|
return true;
|
|
24
24
|
}
|
|
25
|
-
const content = typeof message.content ===
|
|
25
|
+
const content = typeof message.content === "string" ? message.content : "";
|
|
26
26
|
return INLINE_MEDIA_DATA_RE.test(content);
|
|
27
27
|
}
|
|
28
28
|
export function stripHistoricalVisualToolOutputs(messages) {
|
|
@@ -34,14 +34,14 @@ export function stripHistoricalVisualToolOutputs(messages) {
|
|
|
34
34
|
if (!isVisualToolMessage(message)) {
|
|
35
35
|
return message;
|
|
36
36
|
}
|
|
37
|
-
const content = typeof message.content ===
|
|
37
|
+
const content = typeof message.content === "string" ? message.content : "";
|
|
38
38
|
if (!INLINE_MEDIA_DATA_RE.test(content)) {
|
|
39
39
|
return message;
|
|
40
40
|
}
|
|
41
41
|
changed = true;
|
|
42
42
|
return {
|
|
43
43
|
...message,
|
|
44
|
-
content:
|
|
44
|
+
content: "[Image omitted]",
|
|
45
45
|
};
|
|
46
46
|
});
|
|
47
47
|
return changed ? next : messages;
|
|
@@ -52,3 +52,57 @@ export function containsImageAttachment(messages) {
|
|
|
52
52
|
}
|
|
53
53
|
return analyzeChatProcessMedia(messages).containsCurrentTurnImage === true;
|
|
54
54
|
}
|
|
55
|
+
export function repairIncompleteToolCalls(messages) {
|
|
56
|
+
if (!Array.isArray(messages) || messages.length === 0) {
|
|
57
|
+
return messages;
|
|
58
|
+
}
|
|
59
|
+
const toolCallIdsWithResponse = new Set();
|
|
60
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
61
|
+
const msg = messages[i];
|
|
62
|
+
if (msg?.role === "tool" && typeof msg.tool_call_id === "string") {
|
|
63
|
+
toolCallIdsWithResponse.add(msg.tool_call_id);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const result = [];
|
|
67
|
+
let changed = false;
|
|
68
|
+
for (const msg of messages) {
|
|
69
|
+
if (msg?.role === "assistant" && Array.isArray(msg.tool_calls)) {
|
|
70
|
+
const completeToolCalls = [];
|
|
71
|
+
const missingToolCallIds = [];
|
|
72
|
+
for (const tc of msg.tool_calls) {
|
|
73
|
+
const tcId = typeof tc?.id === "string" ? tc.id : "";
|
|
74
|
+
if (tcId && toolCallIdsWithResponse.has(tcId)) {
|
|
75
|
+
completeToolCalls.push(tc);
|
|
76
|
+
}
|
|
77
|
+
else if (tcId) {
|
|
78
|
+
missingToolCallIds.push(tcId);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (missingToolCallIds.length > 0) {
|
|
82
|
+
changed = true;
|
|
83
|
+
const repaired = {
|
|
84
|
+
...msg,
|
|
85
|
+
tool_calls: completeToolCalls.length > 0 ? completeToolCalls : undefined,
|
|
86
|
+
};
|
|
87
|
+
if (!repaired.tool_calls) {
|
|
88
|
+
delete repaired.tool_calls;
|
|
89
|
+
}
|
|
90
|
+
result.push(repaired);
|
|
91
|
+
for (const missingId of missingToolCallIds) {
|
|
92
|
+
result.push({
|
|
93
|
+
role: "tool",
|
|
94
|
+
tool_call_id: missingId,
|
|
95
|
+
content: '{"status":"tool_call_repaired_orphaned_tool_call"}',
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
result.push(msg);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
result.push(msg);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return changed ? result : messages;
|
|
108
|
+
}
|
|
@@ -1,25 +1,7 @@
|
|
|
1
|
+
import type { AdapterContext } from '../types/chat-envelope.js';
|
|
1
2
|
import type { ProcessedRequest, StandardizedRequest } from '../types/standardized.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export interface ChatProcessSessionInputEstimateResult {
|
|
8
|
-
tokens?: number;
|
|
9
|
-
scope?: string;
|
|
10
|
-
mode: 'session_reuse' | 'session_delta' | 'unavailable';
|
|
11
|
-
reason?: 'missing_scope' | 'missing_state' | 'missing_previous_usage' | 'tools_signature_changed' | 'parameters_signature_changed' | 'message_count_regressed' | 'boundary_mismatch';
|
|
12
|
-
previousMessageCount?: number;
|
|
13
|
-
appendedMessageCount?: number;
|
|
14
|
-
hasPreviousTokens?: boolean;
|
|
15
|
-
hasPreviousMessageCount?: boolean;
|
|
16
|
-
hasToolsSignature?: boolean;
|
|
17
|
-
hasParametersSignature?: boolean;
|
|
18
|
-
previousParametersSignatureDigest?: string;
|
|
19
|
-
currentParametersSignatureDigest?: string;
|
|
20
|
-
}
|
|
21
|
-
export declare function estimateChatProcessSessionInputTokens(metadata: SessionScopeMetadata, request: StandardizedRequest | ProcessedRequest): number | undefined;
|
|
22
|
-
export declare function estimateChatProcessSessionInputTokensDetailed(metadata: SessionScopeMetadata, request: StandardizedRequest | ProcessedRequest): ChatProcessSessionInputEstimateResult;
|
|
23
|
-
export declare function saveChatProcessSessionInputEstimate(metadata: SessionScopeMetadata, request: StandardizedRequest | ProcessedRequest, estimatedInputTokens: number): void;
|
|
24
|
-
export declare function saveChatProcessSessionActualUsage(metadata: SessionScopeMetadata, usageRaw: unknown, requestSnapshot?: ChatProcessSessionRequestSnapshot): void;
|
|
25
|
-
export {};
|
|
3
|
+
export declare function estimateSessionBoundTokens(request: StandardizedRequest | ProcessedRequest, metadata: Record<string, unknown> | undefined): number | undefined;
|
|
4
|
+
export declare function saveChatProcessSessionActualUsage(options: {
|
|
5
|
+
context: AdapterContext;
|
|
6
|
+
usage: Record<string, unknown> | undefined;
|
|
7
|
+
}): void;
|
|
@@ -1,246 +1,147 @@
|
|
|
1
1
|
import { loadRoutingInstructionStateSync, saveRoutingInstructionStateSync } from '../../../router/virtual-router/sticky-session-store.js';
|
|
2
2
|
import { countRequestTokens } from '../../../router/virtual-router/token-counter.js';
|
|
3
|
-
function
|
|
3
|
+
function createEmptyRoutingInstructionState() {
|
|
4
4
|
return {
|
|
5
|
-
forcedTarget: undefined,
|
|
6
|
-
stickyTarget: undefined,
|
|
7
|
-
preferTarget: undefined,
|
|
8
5
|
allowedProviders: new Set(),
|
|
9
6
|
disabledProviders: new Set(),
|
|
10
7
|
disabledKeys: new Map(),
|
|
11
|
-
disabledModels: new Map()
|
|
12
|
-
stopMessageSource: undefined,
|
|
13
|
-
stopMessageText: undefined,
|
|
14
|
-
stopMessageMaxRepeats: undefined,
|
|
15
|
-
stopMessageUsed: undefined,
|
|
16
|
-
stopMessageUpdatedAt: undefined,
|
|
17
|
-
stopMessageLastUsedAt: undefined,
|
|
18
|
-
stopMessageStageMode: undefined,
|
|
19
|
-
stopMessageAiMode: undefined,
|
|
20
|
-
stopMessageAiSeedPrompt: undefined,
|
|
21
|
-
stopMessageAiHistory: undefined,
|
|
22
|
-
preCommandSource: undefined,
|
|
23
|
-
preCommandScriptPath: undefined,
|
|
24
|
-
preCommandUpdatedAt: undefined,
|
|
25
|
-
chatProcessInputTokens: undefined,
|
|
26
|
-
chatProcessMessageCount: undefined,
|
|
27
|
-
chatProcessToolsSignature: undefined,
|
|
28
|
-
chatProcessParametersSignature: undefined,
|
|
29
|
-
chatProcessBoundarySignature: undefined,
|
|
30
|
-
chatProcessUpdatedAt: undefined
|
|
8
|
+
disabledModels: new Map()
|
|
31
9
|
};
|
|
32
10
|
}
|
|
33
|
-
function
|
|
34
|
-
const sessionId = typeof
|
|
11
|
+
function resolveSessionUsageScope(record) {
|
|
12
|
+
const sessionId = typeof record?.sessionId === 'string' ? record.sessionId.trim() : '';
|
|
35
13
|
if (sessionId) {
|
|
36
14
|
return `session:${sessionId}`;
|
|
37
15
|
}
|
|
38
|
-
const conversationId = typeof
|
|
16
|
+
const conversationId = typeof record?.conversationId === 'string' ? record.conversationId.trim() : '';
|
|
39
17
|
if (conversationId) {
|
|
40
18
|
return `conversation:${conversationId}`;
|
|
41
19
|
}
|
|
42
20
|
return undefined;
|
|
43
21
|
}
|
|
44
|
-
function
|
|
22
|
+
function loadState(scope) {
|
|
45
23
|
try {
|
|
46
|
-
return
|
|
24
|
+
return loadRoutingInstructionStateSync(scope);
|
|
47
25
|
}
|
|
48
26
|
catch {
|
|
49
|
-
return
|
|
27
|
+
return null;
|
|
50
28
|
}
|
|
51
29
|
}
|
|
52
|
-
function
|
|
53
|
-
if (!
|
|
30
|
+
function readRoundedToken(value) {
|
|
31
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
54
32
|
return undefined;
|
|
55
33
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
content: message.content ?? null,
|
|
59
|
-
tool_calls: Array.isArray(message.tool_calls) ? message.tool_calls : [],
|
|
60
|
-
tool_call_id: message.tool_call_id ?? null,
|
|
61
|
-
name: message.name ?? null
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
function coercePositiveInteger(value) {
|
|
65
|
-
return typeof value === 'number' && Number.isFinite(value) && value > 0
|
|
66
|
-
? Math.max(1, Math.round(value))
|
|
67
|
-
: undefined;
|
|
34
|
+
const rounded = Math.round(value);
|
|
35
|
+
return rounded > 0 ? rounded : undefined;
|
|
68
36
|
}
|
|
69
|
-
function
|
|
70
|
-
if (!
|
|
71
|
-
return
|
|
37
|
+
function buildSnapshot(scope, state) {
|
|
38
|
+
if (!state) {
|
|
39
|
+
return null;
|
|
72
40
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
41
|
+
const totalTokens = readRoundedToken(state.chatProcessLastTotalTokens);
|
|
42
|
+
const inputTokens = readRoundedToken(state.chatProcessLastInputTokens);
|
|
43
|
+
const messageCount = readRoundedToken(state.chatProcessLastMessageCount);
|
|
44
|
+
const updatedAtMs = readRoundedToken(state.chatProcessLastUpdatedAt);
|
|
45
|
+
if (totalTokens === undefined && inputTokens === undefined) {
|
|
46
|
+
return null;
|
|
77
47
|
}
|
|
78
|
-
return
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const previousMessageCount = typeof state.chatProcessMessageCount === 'number' &&
|
|
86
|
-
Number.isFinite(state.chatProcessMessageCount) &&
|
|
87
|
-
state.chatProcessMessageCount >= 0;
|
|
88
|
-
const toolsSignature = typeof state.chatProcessToolsSignature === 'string' && state.chatProcessToolsSignature.trim().length > 0;
|
|
89
|
-
const parametersSignature = typeof state.chatProcessParametersSignature === 'string' &&
|
|
90
|
-
state.chatProcessParametersSignature.trim().length > 0;
|
|
91
|
-
return previousTokens !== undefined && previousMessageCount && toolsSignature && parametersSignature;
|
|
92
|
-
}
|
|
93
|
-
function applyRequestSnapshotToState(state, request) {
|
|
94
|
-
if (!request || typeof request !== 'object') {
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
97
|
-
const messages = Array.isArray(request.messages) ? request.messages : null;
|
|
98
|
-
if (!messages) {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
state.chatProcessMessageCount = messages.length;
|
|
102
|
-
state.chatProcessToolsSignature = stableSignature(request.tools ?? null);
|
|
103
|
-
state.chatProcessParametersSignature = stableSignature(request.parameters ?? null);
|
|
104
|
-
state.chatProcessBoundarySignature = messageBoundarySignature(messages[messages.length - 1]);
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
export function estimateChatProcessSessionInputTokens(metadata, request) {
|
|
108
|
-
return estimateChatProcessSessionInputTokensDetailed(metadata, request).tokens;
|
|
48
|
+
return {
|
|
49
|
+
scope,
|
|
50
|
+
...(totalTokens !== undefined ? { totalTokens } : {}),
|
|
51
|
+
...(inputTokens !== undefined ? { inputTokens } : {}),
|
|
52
|
+
...(messageCount !== undefined ? { messageCount } : {}),
|
|
53
|
+
...(updatedAtMs !== undefined ? { updatedAtMs } : {})
|
|
54
|
+
};
|
|
109
55
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (previousTokens === undefined || previousMessageCount === undefined) {
|
|
134
|
-
return {
|
|
135
|
-
scope,
|
|
136
|
-
mode: 'unavailable',
|
|
137
|
-
reason: 'missing_previous_usage',
|
|
138
|
-
hasPreviousTokens: previousTokens !== undefined,
|
|
139
|
-
hasPreviousMessageCount: previousMessageCount !== undefined,
|
|
140
|
-
hasToolsSignature: Boolean(state.chatProcessToolsSignature),
|
|
141
|
-
hasParametersSignature: Boolean(state.chatProcessParametersSignature)
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
const currentToolsSignature = stableSignature(request.tools ?? null);
|
|
145
|
-
const currentParametersSignature = stableSignature(request.parameters ?? null);
|
|
146
|
-
if (state.chatProcessToolsSignature !== currentToolsSignature) {
|
|
147
|
-
return {
|
|
148
|
-
scope,
|
|
149
|
-
mode: 'unavailable',
|
|
150
|
-
reason: 'tools_signature_changed',
|
|
151
|
-
previousMessageCount,
|
|
152
|
-
hasPreviousTokens: true,
|
|
153
|
-
hasPreviousMessageCount: true
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
if (state.chatProcessParametersSignature !== currentParametersSignature) {
|
|
157
|
-
return {
|
|
158
|
-
scope,
|
|
159
|
-
mode: 'unavailable',
|
|
160
|
-
reason: 'parameters_signature_changed',
|
|
161
|
-
previousMessageCount,
|
|
162
|
-
hasPreviousTokens: true,
|
|
163
|
-
hasPreviousMessageCount: true,
|
|
164
|
-
previousParametersSignatureDigest: digestSignature(state.chatProcessParametersSignature),
|
|
165
|
-
currentParametersSignatureDigest: digestSignature(currentParametersSignature)
|
|
166
|
-
};
|
|
56
|
+
function normalizeUsage(usage) {
|
|
57
|
+
if (!usage || typeof usage !== 'object') {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const inputTokens = readRoundedToken(usage.input_tokens ??
|
|
61
|
+
usage.prompt_tokens ??
|
|
62
|
+
usage.inputTokens ??
|
|
63
|
+
usage.promptTokens ??
|
|
64
|
+
usage.request_tokens ??
|
|
65
|
+
usage.requestTokens);
|
|
66
|
+
const outputTokens = readRoundedToken(usage.output_tokens ??
|
|
67
|
+
usage.completion_tokens ??
|
|
68
|
+
usage.outputTokens ??
|
|
69
|
+
usage.completionTokens ??
|
|
70
|
+
usage.response_tokens ??
|
|
71
|
+
usage.responseTokens);
|
|
72
|
+
const totalTokens = readRoundedToken(usage.total_tokens ??
|
|
73
|
+
usage.totalTokens ??
|
|
74
|
+
((inputTokens ?? 0) + (outputTokens ?? 0) > 0
|
|
75
|
+
? (inputTokens ?? 0) + (outputTokens ?? 0)
|
|
76
|
+
: undefined));
|
|
77
|
+
if (totalTokens === undefined && inputTokens === undefined) {
|
|
78
|
+
return null;
|
|
167
79
|
}
|
|
80
|
+
return {
|
|
81
|
+
...(inputTokens !== undefined ? { inputTokens } : {}),
|
|
82
|
+
...(outputTokens !== undefined ? { outputTokens } : {}),
|
|
83
|
+
...(totalTokens !== undefined ? { totalTokens } : {})
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function estimateDeltaTokens(request, previousMessageCount) {
|
|
168
87
|
const messages = Array.isArray(request.messages) ? request.messages : [];
|
|
169
|
-
if (previousMessageCount > messages.length) {
|
|
170
|
-
return
|
|
171
|
-
scope,
|
|
172
|
-
mode: 'unavailable',
|
|
173
|
-
reason: 'message_count_regressed',
|
|
174
|
-
previousMessageCount
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
if (previousMessageCount > 0) {
|
|
178
|
-
const boundary = messageBoundarySignature(messages[previousMessageCount - 1]);
|
|
179
|
-
if ((state.chatProcessBoundarySignature || undefined) !== boundary) {
|
|
180
|
-
return {
|
|
181
|
-
scope,
|
|
182
|
-
mode: 'unavailable',
|
|
183
|
-
reason: 'boundary_mismatch',
|
|
184
|
-
previousMessageCount
|
|
185
|
-
};
|
|
186
|
-
}
|
|
88
|
+
if (previousMessageCount < 0 || previousMessageCount > messages.length) {
|
|
89
|
+
return undefined;
|
|
187
90
|
}
|
|
188
91
|
const appendedMessages = messages.slice(previousMessageCount);
|
|
189
92
|
if (appendedMessages.length === 0) {
|
|
190
|
-
return
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
mode: 'session_reuse',
|
|
194
|
-
previousMessageCount,
|
|
195
|
-
appendedMessageCount: 0
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
const delta = countRequestTokens({
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
return countRequestTokens({
|
|
199
96
|
model: request.model,
|
|
200
97
|
messages: appendedMessages,
|
|
201
|
-
tools: undefined,
|
|
202
98
|
parameters: {},
|
|
203
|
-
metadata: request.metadata ??
|
|
99
|
+
metadata: { originalEndpoint: request.metadata?.originalEndpoint ?? '/v1/chat/completions' }
|
|
204
100
|
});
|
|
205
|
-
return {
|
|
206
|
-
tokens: previousTokens + delta,
|
|
207
|
-
scope,
|
|
208
|
-
mode: 'session_delta',
|
|
209
|
-
previousMessageCount,
|
|
210
|
-
appendedMessageCount: appendedMessages.length
|
|
211
|
-
};
|
|
212
101
|
}
|
|
213
|
-
export function
|
|
214
|
-
const scope =
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return;
|
|
102
|
+
export function estimateSessionBoundTokens(request, metadata) {
|
|
103
|
+
const scope = resolveSessionUsageScope(metadata);
|
|
104
|
+
if (!scope) {
|
|
105
|
+
return undefined;
|
|
218
106
|
}
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
107
|
+
const snapshot = buildSnapshot(scope, loadState(scope));
|
|
108
|
+
if (!snapshot) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
const previousTotal = snapshot.totalTokens ?? snapshot.inputTokens;
|
|
112
|
+
const previousMessageCount = snapshot.messageCount;
|
|
113
|
+
if (previousTotal === undefined || previousMessageCount === undefined) {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const deltaTokens = estimateDeltaTokens(request, previousMessageCount);
|
|
117
|
+
if (deltaTokens === undefined) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
return Math.max(1, Math.round(previousTotal + deltaTokens));
|
|
228
121
|
}
|
|
229
|
-
export function saveChatProcessSessionActualUsage(
|
|
230
|
-
const scope =
|
|
231
|
-
if (!scope
|
|
122
|
+
export function saveChatProcessSessionActualUsage(options) {
|
|
123
|
+
const scope = resolveSessionUsageScope(options.context);
|
|
124
|
+
if (!scope) {
|
|
232
125
|
return;
|
|
233
126
|
}
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
if (actualInputTokens === undefined) {
|
|
127
|
+
const normalizedUsage = normalizeUsage(options.usage);
|
|
128
|
+
if (!normalizedUsage) {
|
|
237
129
|
return;
|
|
238
130
|
}
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
131
|
+
const capturedChatRequest = options.context.capturedChatRequest;
|
|
132
|
+
const messageCount = Array.isArray(capturedChatRequest?.messages)
|
|
133
|
+
? (capturedChatRequest.messages ?? []).length
|
|
134
|
+
: undefined;
|
|
135
|
+
const state = loadState(scope) ?? createEmptyRoutingInstructionState();
|
|
136
|
+
if (normalizedUsage.totalTokens !== undefined) {
|
|
137
|
+
state.chatProcessLastTotalTokens = normalizedUsage.totalTokens;
|
|
138
|
+
}
|
|
139
|
+
if (normalizedUsage.inputTokens !== undefined) {
|
|
140
|
+
state.chatProcessLastInputTokens = normalizedUsage.inputTokens;
|
|
141
|
+
}
|
|
142
|
+
if (typeof messageCount === 'number' && Number.isFinite(messageCount)) {
|
|
143
|
+
state.chatProcessLastMessageCount = Math.max(0, Math.round(messageCount));
|
|
242
144
|
}
|
|
243
|
-
state.
|
|
244
|
-
state.chatProcessUpdatedAt = Date.now();
|
|
145
|
+
state.chatProcessLastUpdatedAt = Date.now();
|
|
245
146
|
saveRoutingInstructionStateSync(scope, state);
|
|
246
147
|
}
|
|
@@ -15,11 +15,11 @@ import { runRespProcessStage3ServerToolOrchestration } from '../pipeline/stages/
|
|
|
15
15
|
import { runRespOutboundStage1ClientRemap } from '../pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js';
|
|
16
16
|
import { runRespOutboundStage2SseStream } from '../pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.js';
|
|
17
17
|
import { recordResponsesResponse } from '../../shared/responses-conversation-store.js';
|
|
18
|
-
import { saveChatProcessSessionActualUsage } from '../process/chat-process-session-usage.js';
|
|
19
18
|
import { ProviderProtocolError } from '../../provider-protocol-error.js';
|
|
20
19
|
import { readRuntimeMetadata } from '../../runtime-metadata.js';
|
|
21
20
|
import { commitClockReservation, resolveClockConfig } from '../../../servertool/clock/task-store.js';
|
|
22
21
|
import { detectProviderResponseShapeWithNative } from '../../../router/virtual-router/engine-selection/native-chat-process-servertool-orchestration-semantics.js';
|
|
22
|
+
import { saveChatProcessSessionActualUsage } from '../process/chat-process-session-usage.js';
|
|
23
23
|
const PROVIDER_RESPONSE_REGISTRY = {
|
|
24
24
|
'openai-chat': {
|
|
25
25
|
createFormatAdapter: () => new ChatFormatAdapter(),
|
|
@@ -398,18 +398,6 @@ export async function convertProviderResponse(options) {
|
|
|
398
398
|
});
|
|
399
399
|
applyModelOverride(clientPayload, displayModel);
|
|
400
400
|
stripInternalPolicyDebugFields(clientPayload);
|
|
401
|
-
try {
|
|
402
|
-
const usage = clientPayload && typeof clientPayload === 'object' && !Array.isArray(clientPayload)
|
|
403
|
-
? clientPayload.usage
|
|
404
|
-
: undefined;
|
|
405
|
-
saveChatProcessSessionActualUsage({
|
|
406
|
-
sessionId: typeof options.context.sessionId === 'string' ? options.context.sessionId : undefined,
|
|
407
|
-
conversationId: typeof options.context.conversationId === 'string' ? options.context.conversationId : undefined
|
|
408
|
-
}, usage, isJsonRecord(options.context.capturedChatRequest) ? options.context.capturedChatRequest : undefined);
|
|
409
|
-
}
|
|
410
|
-
catch {
|
|
411
|
-
// best-effort: usage backfill must not break response conversion
|
|
412
|
-
}
|
|
413
401
|
if (clientProtocol === 'openai-responses') {
|
|
414
402
|
try {
|
|
415
403
|
recordResponsesResponse({
|
|
@@ -464,6 +452,18 @@ export async function convertProviderResponse(options) {
|
|
|
464
452
|
});
|
|
465
453
|
// Commit scheduled-task delivery only after a successful client payload/stream is prepared.
|
|
466
454
|
await maybeCommitClockReservationFromContext(options.context);
|
|
455
|
+
try {
|
|
456
|
+
const usage = clientPayload && typeof clientPayload === 'object' && !Array.isArray(clientPayload)
|
|
457
|
+
? clientPayload.usage
|
|
458
|
+
: undefined;
|
|
459
|
+
saveChatProcessSessionActualUsage({
|
|
460
|
+
context: options.context,
|
|
461
|
+
usage
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
catch {
|
|
465
|
+
// best-effort: usage persistence must not break response delivery
|
|
466
|
+
}
|
|
467
467
|
if (outbound.stream) {
|
|
468
468
|
const usage = clientPayload && typeof clientPayload === 'object' && !Array.isArray(clientPayload)
|
|
469
469
|
? clientPayload.usage
|
|
@@ -142,6 +142,10 @@ export class OpenAIOpenAIPipelineCodec {
|
|
|
142
142
|
if (!Array.isArray(openaiPayload.tools) && Array.isArray(inboundPayload.tools)) {
|
|
143
143
|
openaiPayload.tools = inboundPayload.tools;
|
|
144
144
|
}
|
|
145
|
+
if (openaiPayload.tool_choice === undefined &&
|
|
146
|
+
inboundPayload.tool_choice !== undefined) {
|
|
147
|
+
openaiPayload.tool_choice = inboundPayload.tool_choice;
|
|
148
|
+
}
|
|
145
149
|
const filterContext = {
|
|
146
150
|
...context,
|
|
147
151
|
requestId,
|
|
@@ -10,7 +10,6 @@ export declare function buildChatRequestFromResponses(payload: Record<string, un
|
|
|
10
10
|
export declare function buildResponsesRequestFromChat(payload: Record<string, unknown>, ctx?: ResponsesRequestContext, extras?: {
|
|
11
11
|
bridgeHistory?: BridgeInputBuildResult;
|
|
12
12
|
systemInstruction?: string;
|
|
13
|
-
routeToolCallIdStyle?: 'fc' | 'preserve';
|
|
14
13
|
}): BuildResponsesRequestResult;
|
|
15
14
|
export { buildResponsesPayloadFromChat, extractRequestIdFromResponse } from './responses-openai-bridge/response-payload.js';
|
|
16
15
|
export { buildChatResponseFromResponses } from '../shared/responses-response-utils.js';
|