@jsonstudio/llms 0.6.3214 → 0.6.3271

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/conversion/bridge-actions.js +37 -322
  2. package/dist/conversion/bridge-instructions.js +12 -109
  3. package/dist/conversion/codecs/anthropic-openai-codec.js +1 -1
  4. package/dist/conversion/compat/actions/deepseek-web-request.js +43 -110
  5. package/dist/conversion/compat/actions/deepseek-web-response.d.ts +3 -0
  6. package/dist/conversion/compat/actions/deepseek-web-response.js +150 -11
  7. package/dist/conversion/hub/operation-table/semantic-mappers/archive/chat-mapper.archive.d.ts +8 -0
  8. package/dist/conversion/hub/operation-table/semantic-mappers/archive/chat-mapper.archive.js +404 -0
  9. package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +5 -384
  10. package/dist/conversion/hub/response/response-runtime.d.ts +1 -0
  11. package/dist/conversion/hub/response/response-runtime.js +26 -0
  12. package/dist/conversion/hub/snapshot-recorder.js +2 -91
  13. package/dist/conversion/hub/tool-governance/engine.d.ts +1 -1
  14. package/dist/conversion/hub/tool-governance/engine.js +17 -127
  15. package/dist/conversion/shared/anthropic-message-utils.d.ts +3 -1
  16. package/dist/conversion/shared/anthropic-message-utils.js +23 -15
  17. package/dist/conversion/shared/openai-finalizer.d.ts +0 -3
  18. package/dist/conversion/shared/openai-finalizer.js +11 -169
  19. package/dist/conversion/shared/openai-message-normalize.js +11 -72
  20. package/dist/conversion/shared/tool-mapping.js +5 -0
  21. package/dist/native/router_hotpath_napi.node +0 -0
  22. package/dist/router/virtual-router/bootstrap/provider-normalization.js +11 -3
  23. package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.d.ts +20 -0
  24. package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js +71 -0
  25. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-governance-semantics.d.ts +8 -0
  26. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-governance-semantics.js +48 -0
  27. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.d.ts +1 -0
  28. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.js +30 -0
  29. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-semantic-mappers.d.ts +2 -0
  30. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-semantic-mappers.js +83 -0
  31. package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +11 -0
  32. package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.d.ts +2 -0
  33. package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.js +61 -0
  34. package/dist/router/virtual-router/engine-selection/native-snapshot-hooks.d.ts +1 -0
  35. package/dist/router/virtual-router/engine-selection/native-snapshot-hooks.js +40 -0
  36. package/dist/router/virtual-router/engine.js +58 -1
  37. package/dist/router/virtual-router/types.d.ts +1 -1
  38. package/package.json +1 -1
@@ -68,6 +68,40 @@ function parseBridgeHistoryOutput(raw) {
68
68
  return null;
69
69
  }
70
70
  }
71
+ function parseBridgeActionState(raw) {
72
+ try {
73
+ const parsed = JSON.parse(raw);
74
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
75
+ return null;
76
+ }
77
+ const row = parsed;
78
+ if (!Array.isArray(row.messages)) {
79
+ return null;
80
+ }
81
+ const output = {
82
+ messages: row.messages
83
+ };
84
+ if (row.requiredAction && typeof row.requiredAction === 'object' && !Array.isArray(row.requiredAction)) {
85
+ output.requiredAction = row.requiredAction;
86
+ }
87
+ if (Array.isArray(row.capturedToolResults)) {
88
+ output.capturedToolResults = row.capturedToolResults.filter((entry) => Boolean(entry) && typeof entry === 'object' && !Array.isArray(entry));
89
+ }
90
+ if (row.rawRequest && typeof row.rawRequest === 'object' && !Array.isArray(row.rawRequest)) {
91
+ output.rawRequest = row.rawRequest;
92
+ }
93
+ if (row.rawResponse && typeof row.rawResponse === 'object' && !Array.isArray(row.rawResponse)) {
94
+ output.rawResponse = row.rawResponse;
95
+ }
96
+ if (row.metadata && typeof row.metadata === 'object' && !Array.isArray(row.metadata)) {
97
+ output.metadata = row.metadata;
98
+ }
99
+ return output;
100
+ }
101
+ catch {
102
+ return null;
103
+ }
104
+ }
71
105
  function parseApplyBridgeNormalizeHistoryOutput(raw) {
72
106
  try {
73
107
  const parsed = JSON.parse(raw);
@@ -673,6 +707,43 @@ export function applyBridgeEnsureSystemInstructionWithNative(input) {
673
707
  return fail(reason);
674
708
  }
675
709
  }
710
+ export function runBridgeActionPipelineWithNative(input) {
711
+ const capability = 'runBridgeActionPipelineJson';
712
+ const fail = (reason) => failNativeRequired(capability, reason);
713
+ if (isNativeDisabledByEnv()) {
714
+ return fail('native disabled');
715
+ }
716
+ const fn = readNativeFunction(capability);
717
+ if (!fn) {
718
+ return fail();
719
+ }
720
+ const payloadJson = safeStringify({
721
+ stage: input.stage,
722
+ actions: input.actions,
723
+ protocol: input.protocol,
724
+ moduleType: input.moduleType,
725
+ requestId: input.requestId,
726
+ state: input.state
727
+ });
728
+ if (!payloadJson) {
729
+ return fail('json stringify failed');
730
+ }
731
+ try {
732
+ const raw = fn(payloadJson);
733
+ if (typeof raw !== 'string' || !raw) {
734
+ return fail('empty result');
735
+ }
736
+ const parsed = parseBridgeActionState(raw);
737
+ if (!parsed) {
738
+ return null;
739
+ }
740
+ return parsed;
741
+ }
742
+ catch (error) {
743
+ const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
744
+ return fail(reason);
745
+ }
746
+ }
676
747
  export function normalizeMessageReasoningToolsWithNative(message, idPrefix) {
677
748
  const capability = 'normalizeMessageReasoningToolsJson';
678
749
  const fail = (reason) => failNativeRequired(capability, reason);
@@ -20,3 +20,11 @@ export declare function governRequestWithNative(input: {
20
20
  request: Record<string, unknown>;
21
21
  summary: Record<string, unknown>;
22
22
  };
23
+ export declare function governResponseWithNative(input: {
24
+ payload: Record<string, unknown>;
25
+ protocol?: string;
26
+ registry?: NativeToolGovernanceRegistry;
27
+ }): {
28
+ payload: Record<string, unknown>;
29
+ summary: Record<string, unknown>;
30
+ };
@@ -152,3 +152,51 @@ export function governRequestWithNative(input) {
152
152
  return fail(reason);
153
153
  }
154
154
  }
155
+ export function governResponseWithNative(input) {
156
+ const capability = 'governToolNameResponseJson';
157
+ const fail = (reason) => failNativeRequired(capability, reason);
158
+ if (isNativeDisabledByEnv()) {
159
+ return fail('native disabled');
160
+ }
161
+ const fn = readNativeFunction(capability);
162
+ if (!fn) {
163
+ return fail();
164
+ }
165
+ const normalizedInput = {
166
+ ...input,
167
+ registry: normalizeRegistryForNative(input.registry)
168
+ };
169
+ const inputJson = safeStringify(normalizedInput);
170
+ if (!inputJson) {
171
+ return fail('json stringify failed');
172
+ }
173
+ try {
174
+ const raw = fn(inputJson);
175
+ const errorReason = readNativeErrorReason(raw);
176
+ if (errorReason) {
177
+ return fail(errorReason);
178
+ }
179
+ if (typeof raw !== 'string' || !raw) {
180
+ return fail('empty result');
181
+ }
182
+ const parsed = JSON.parse(raw);
183
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
184
+ return fail('invalid payload');
185
+ }
186
+ const row = parsed;
187
+ if (!row.payload || typeof row.payload !== 'object' || Array.isArray(row.payload)) {
188
+ return fail('invalid response payload');
189
+ }
190
+ if (!row.summary || typeof row.summary !== 'object' || Array.isArray(row.summary)) {
191
+ return fail('invalid summary payload');
192
+ }
193
+ return {
194
+ payload: row.payload,
195
+ summary: row.summary
196
+ };
197
+ }
198
+ catch (error) {
199
+ const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
200
+ return fail(reason);
201
+ }
202
+ }
@@ -29,6 +29,7 @@ export declare function resolveReqInboundServerToolFollowupSnapshotWithNative(ad
29
29
  export declare function augmentReqInboundContextSnapshotWithNative(context: Record<string, unknown>, fallbackSnapshot: Record<string, unknown>): Record<string, unknown>;
30
30
  export declare function normalizeReqInboundToolCallIdStyleWithNative(value: unknown): 'fc' | 'preserve' | undefined;
31
31
  export declare function mapReqInboundBridgeToolsToChatWithNative(rawTools: unknown): Array<Record<string, unknown>>;
32
+ export declare function mapChatToolsToBridgeWithNative(rawTools: unknown): Array<Record<string, unknown>>;
32
33
  export declare function captureReqInboundResponsesContextSnapshotWithNative(input: {
33
34
  rawRequest: Record<string, unknown>;
34
35
  requestId?: string;
@@ -339,6 +339,36 @@ export function mapReqInboundBridgeToolsToChatWithNative(rawTools) {
339
339
  return fail(reason);
340
340
  }
341
341
  }
342
+ export function mapChatToolsToBridgeWithNative(rawTools) {
343
+ const capability = 'mapChatToolsToBridgeJson';
344
+ const fail = (reason) => failNativeRequired(capability, reason);
345
+ if (isNativeDisabledByEnv()) {
346
+ return fail('native disabled');
347
+ }
348
+ const fn = readNativeFunction(capability);
349
+ if (!fn) {
350
+ return fail();
351
+ }
352
+ const payloadJson = safeStringify(Array.isArray(rawTools) ? rawTools : []);
353
+ if (!payloadJson) {
354
+ return fail('json stringify failed');
355
+ }
356
+ try {
357
+ const raw = fn(payloadJson);
358
+ if (typeof raw !== 'string' || !raw) {
359
+ return fail('empty result');
360
+ }
361
+ const parsed = parseArray(raw);
362
+ if (!parsed) {
363
+ return fail('invalid payload');
364
+ }
365
+ return parsed.filter((entry) => Boolean(entry) && typeof entry === 'object' && !Array.isArray(entry));
366
+ }
367
+ catch (error) {
368
+ const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
369
+ return fail(reason);
370
+ }
371
+ }
342
372
  export function captureReqInboundResponsesContextSnapshotWithNative(input) {
343
373
  const capability = 'captureReqInboundResponsesContextSnapshotJson';
344
374
  const fail = (reason) => failNativeRequired(capability, reason);
@@ -0,0 +1,2 @@
1
+ export declare function mapOpenaiChatToChatWithNative(payload: Record<string, unknown> | null | undefined, adapterContext: Record<string, unknown> | null | undefined): Record<string, unknown>;
2
+ export declare function mapOpenaiChatFromChatWithNative(chatEnvelope: Record<string, unknown> | null | undefined, adapterContext: Record<string, unknown> | null | undefined): Record<string, unknown>;
@@ -0,0 +1,83 @@
1
+ import { failNativeRequired, isNativeDisabledByEnv } from './native-router-hotpath-policy.js';
2
+ import { loadNativeRouterHotpathBindingForInternalUse } from './native-router-hotpath.js';
3
+ function readNativeFunction(name) {
4
+ const binding = loadNativeRouterHotpathBindingForInternalUse();
5
+ const fn = binding?.[name];
6
+ return typeof fn === 'function' ? fn : null;
7
+ }
8
+ function safeStringify(value) {
9
+ try {
10
+ return JSON.stringify(value);
11
+ }
12
+ catch {
13
+ return undefined;
14
+ }
15
+ }
16
+ function parseRecord(raw) {
17
+ try {
18
+ const parsed = JSON.parse(raw);
19
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
20
+ return null;
21
+ }
22
+ return parsed;
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ export function mapOpenaiChatToChatWithNative(payload, adapterContext) {
29
+ const capability = 'mapOpenaiChatToChatJson';
30
+ const fail = (reason) => failNativeRequired(capability, reason);
31
+ if (isNativeDisabledByEnv()) {
32
+ return fail('native disabled');
33
+ }
34
+ const fn = readNativeFunction(capability);
35
+ if (!fn) {
36
+ return fail();
37
+ }
38
+ const payloadJson = safeStringify(payload ?? {});
39
+ const contextJson = safeStringify(adapterContext ?? {});
40
+ if (!payloadJson || !contextJson) {
41
+ return fail('json stringify failed');
42
+ }
43
+ try {
44
+ const raw = fn(payloadJson, contextJson);
45
+ if (typeof raw !== 'string' || !raw) {
46
+ return fail('empty result');
47
+ }
48
+ const parsed = parseRecord(raw);
49
+ return parsed ?? fail('invalid payload');
50
+ }
51
+ catch (error) {
52
+ const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
53
+ return fail(reason);
54
+ }
55
+ }
56
+ export function mapOpenaiChatFromChatWithNative(chatEnvelope, adapterContext) {
57
+ const capability = 'mapOpenaiChatFromChatJson';
58
+ const fail = (reason) => failNativeRequired(capability, reason);
59
+ if (isNativeDisabledByEnv()) {
60
+ return fail('native disabled');
61
+ }
62
+ const fn = readNativeFunction(capability);
63
+ if (!fn) {
64
+ return fail();
65
+ }
66
+ const chatJson = safeStringify(chatEnvelope ?? {});
67
+ const contextJson = safeStringify(adapterContext ?? {});
68
+ if (!chatJson || !contextJson) {
69
+ return fail('json stringify failed');
70
+ }
71
+ try {
72
+ const raw = fn(chatJson, contextJson);
73
+ if (typeof raw !== 'string' || !raw) {
74
+ return fail('empty result');
75
+ }
76
+ const parsed = parseRecord(raw);
77
+ return parsed ?? fail('invalid payload');
78
+ }
79
+ catch (error) {
80
+ const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
81
+ return fail(reason);
82
+ }
83
+ }
@@ -29,6 +29,7 @@ const REQUIRED_NATIVE_EXPORTS = [
29
29
  'augmentContextSnapshotJson',
30
30
  'annotatePassthroughGovernanceSkipJson',
31
31
  'buildAnthropicToolAliasMapJson',
32
+ 'buildAnthropicResponseFromChatJson',
32
33
  'buildChatNodeResultMetadataJson',
33
34
  'buildProcessedRequestFromChatResponseJson',
34
35
  'applyChatProcessedRequestJson',
@@ -63,6 +64,9 @@ const REQUIRED_NATIVE_EXPORTS = [
63
64
  'collectToolOutputsJson',
64
65
  'buildReqInboundToolOutputSnapshotJson',
65
66
  'mapBridgeToolsToChatJson',
67
+ 'mapOpenaiChatToChatJson',
68
+ 'mapOpenaiChatFromChatJson',
69
+ 'mapChatToolsToBridgeJson',
66
70
  'captureReqInboundResponsesContextSnapshotJson',
67
71
  'computeQuotaBucketsJson',
68
72
  'deserializeStopMessageStateJson',
@@ -103,11 +107,15 @@ const REQUIRED_NATIVE_EXPORTS = [
103
107
  'enforceChatBudgetJson',
104
108
  'resolveBudgetForModelJson',
105
109
  'finalizeGovernedRequestJson',
110
+ 'governResponseJson',
111
+ 'governToolNameResponseJson',
106
112
  'findLastUserMessageIndexJson',
107
113
  'injectContinueExecutionDirectiveJson',
108
114
  'injectTimeTagIntoMessagesJson',
109
115
  'injectMcpToolsForChatJson',
110
116
  'injectMcpToolsForResponsesJson',
117
+ 'mapOpenaiChatToChatJson',
118
+ 'mapOpenaiChatFromChatJson',
111
119
  'isStopMessageStateActiveJson',
112
120
  'isContextLengthExceededSignalJson',
113
121
  'isCompactionRequestJson',
@@ -137,6 +145,7 @@ const REQUIRED_NATIVE_EXPORTS = [
137
145
  'normalizeToolSessionMessagesJson',
138
146
  'updateToolSessionHistoryJson',
139
147
  'normalizeContextCaptureLabelJson',
148
+ 'normalizeSnapshotStagePayloadJson',
140
149
  'normalizeContextToolsJson',
141
150
  'normalizeDueInjectTextJson',
142
151
  'normalizeProviderProtocolTokenJson',
@@ -202,9 +211,11 @@ const REQUIRED_NATIVE_EXPORTS = [
202
211
  'resolveSseStreamModeJson',
203
212
  'resolveSseProtocolFromMetadataJson',
204
213
  'repairArgumentsToStringJsonishJson',
214
+ 'runBridgeActionPipelineJson',
205
215
  'sanitizeChatCompletionLikeJson',
206
216
  'sanitizeFormatEnvelopeJson',
207
217
  'sanitizeReasoningTaggedTextJson',
218
+ 'ensureBridgeInstructionsJson',
208
219
  'sanitizeResponsesFunctionNameJson',
209
220
  'shouldRecordSnapshotsJson',
210
221
  'writeSnapshotViaHooksJson',
@@ -4,7 +4,9 @@ export declare function extractToolCallsFromReasoningTextWithNative(text: string
4
4
  cleanedText: string;
5
5
  toolCalls: Array<Record<string, unknown>>;
6
6
  };
7
+ export declare function mapChatToolsToBridgeWithNative(rawTools: unknown): Array<Record<string, unknown>>;
7
8
  export declare function sanitizeReasoningTaggedTextWithNative(text: string): string;
9
+ export declare function ensureBridgeInstructionsWithNative(payload: Record<string, unknown>): Record<string, unknown>;
8
10
  export declare function deriveToolCallKeyWithNative(call: Record<string, unknown> | null | undefined): string | null;
9
11
  export declare function buildProviderProtocolErrorWithNative(input: {
10
12
  message: string;
@@ -80,6 +80,10 @@ function parseToolCallLiteArray(raw) {
80
80
  }
81
81
  return out;
82
82
  }
83
+ function parseArray(raw) {
84
+ const parsed = parseJson(raw);
85
+ return Array.isArray(parsed) ? parsed : null;
86
+ }
83
87
  export function parseLenientJsonishWithNative(value) {
84
88
  const capability = 'parseLenientJsonishJson';
85
89
  const fail = (reason) => failNativeRequired(capability, reason);
@@ -156,6 +160,36 @@ export function extractToolCallsFromReasoningTextWithNative(text, idPrefix) {
156
160
  return fail(reason);
157
161
  }
158
162
  }
163
+ export function mapChatToolsToBridgeWithNative(rawTools) {
164
+ const capability = 'mapChatToolsToBridgeJson';
165
+ const fail = (reason) => failNativeRequired(capability, reason);
166
+ if (isNativeDisabledByEnv()) {
167
+ return fail('native disabled');
168
+ }
169
+ const fn = readNativeFunction(capability);
170
+ if (!fn) {
171
+ return fail();
172
+ }
173
+ const payloadJson = safeStringify(Array.isArray(rawTools) ? rawTools : []);
174
+ if (!payloadJson) {
175
+ return fail('json stringify failed');
176
+ }
177
+ try {
178
+ const raw = fn(payloadJson);
179
+ if (typeof raw !== 'string' || !raw) {
180
+ return fail('empty result');
181
+ }
182
+ const parsed = parseArray(raw);
183
+ if (!parsed) {
184
+ return fail('invalid payload');
185
+ }
186
+ return parsed.filter((entry) => !!entry && typeof entry === 'object' && !Array.isArray(entry));
187
+ }
188
+ catch (error) {
189
+ const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
190
+ return fail(reason);
191
+ }
192
+ }
159
193
  export function sanitizeReasoningTaggedTextWithNative(text) {
160
194
  const capability = 'sanitizeReasoningTaggedTextJson';
161
195
  const fail = (reason) => failNativeRequired(capability, reason);
@@ -178,6 +212,33 @@ export function sanitizeReasoningTaggedTextWithNative(text) {
178
212
  return fail(reason);
179
213
  }
180
214
  }
215
+ export function ensureBridgeInstructionsWithNative(payload) {
216
+ const capability = 'ensureBridgeInstructionsJson';
217
+ const fail = (reason) => failNativeRequired(capability, reason);
218
+ if (isNativeDisabledByEnv()) {
219
+ return fail('native disabled');
220
+ }
221
+ const fn = readNativeFunction(capability);
222
+ if (!fn) {
223
+ return fail();
224
+ }
225
+ const payloadJson = safeStringify(payload ?? {});
226
+ if (!payloadJson) {
227
+ return fail('json stringify failed');
228
+ }
229
+ try {
230
+ const raw = fn(payloadJson);
231
+ if (typeof raw !== 'string' || !raw) {
232
+ return fail('empty result');
233
+ }
234
+ const parsed = parseRecord(raw);
235
+ return parsed ?? fail('invalid payload');
236
+ }
237
+ catch (error) {
238
+ const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
239
+ return fail(reason);
240
+ }
241
+ }
181
242
  export function deriveToolCallKeyWithNative(call) {
182
243
  const capability = 'deriveToolCallKeyJson';
183
244
  const fail = (reason) => failNativeRequired(capability, reason);
@@ -1,2 +1,3 @@
1
1
  export declare function shouldRecordSnapshotsWithNative(): boolean;
2
2
  export declare function writeSnapshotViaHooksWithNative(options: Record<string, unknown>): void;
3
+ export declare function normalizeSnapshotStagePayloadWithNative(stage: string, payload: unknown): unknown;
@@ -22,6 +22,14 @@ function parseBoolean(raw) {
22
22
  return null;
23
23
  }
24
24
  }
25
+ function parseJsonValue(raw) {
26
+ try {
27
+ return JSON.parse(raw);
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
25
33
  export function shouldRecordSnapshotsWithNative() {
26
34
  const capability = 'shouldRecordSnapshotsJson';
27
35
  const fail = (reason) => failNativeRequired(capability, reason);
@@ -67,3 +75,35 @@ export function writeSnapshotViaHooksWithNative(options) {
67
75
  return fail(reason);
68
76
  }
69
77
  }
78
+ export function normalizeSnapshotStagePayloadWithNative(stage, payload) {
79
+ if (payload === undefined || payload === null) {
80
+ return null;
81
+ }
82
+ const capability = 'normalizeSnapshotStagePayloadJson';
83
+ const fail = (reason) => failNativeRequired(capability, reason);
84
+ if (isNativeDisabledByEnv()) {
85
+ return fail('native disabled');
86
+ }
87
+ const fn = readNativeFunction(capability);
88
+ if (!fn) {
89
+ return fail();
90
+ }
91
+ const payloadJson = safeStringify(payload);
92
+ if (!payloadJson) {
93
+ // Preserve non-JSON payloads (e.g. circular structures).
94
+ return payload;
95
+ }
96
+ const stageToken = typeof stage === 'string' ? stage : '';
97
+ try {
98
+ const raw = fn(stageToken, payloadJson);
99
+ if (typeof raw !== 'string' || !raw) {
100
+ return fail('empty result');
101
+ }
102
+ const parsed = parseJsonValue(raw);
103
+ return parsed === null ? fail('invalid payload') : parsed;
104
+ }
105
+ catch (error) {
106
+ const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
107
+ return fail(reason);
108
+ }
109
+ }
@@ -6,6 +6,8 @@ import { cleanRoutingInstructionMarkersWithNative, parseRoutingInstructionKindsW
6
6
  import { getLatestUserTextFromResponsesContext, hasLatestUserRoutingInstructionMarker, hasRoutingInstructionMarkerInResponsesContext } from './engine-legacy/helpers.js';
7
7
  import { ProviderRegistry } from './provider-registry.js';
8
8
  import { resolveStopMessageScope } from './engine/routing-state/store.js';
9
+ import { loadRoutingInstructionStateSync } from './sticky-session-store.js';
10
+ import { mergeStopMessageFromPersisted } from './stop-message-state-sync.js';
9
11
  export class VirtualRouterEngine {
10
12
  nativeProxy;
11
13
  registry;
@@ -80,7 +82,9 @@ export class VirtualRouterEngine {
80
82
  }
81
83
  getStopMessageState(metadata) {
82
84
  const raw = this.nativeProxy.getStopMessageState(JSON.stringify(metadata));
83
- return JSON.parse(raw);
85
+ const snapshot = JSON.parse(raw);
86
+ const scope = resolveStopMessageScope(metadata);
87
+ return mergeStopMessageSnapshotWithPersisted(snapshot, scope);
84
88
  }
85
89
  getPreCommandState(metadata) {
86
90
  const raw = this.nativeProxy.getPreCommandState(JSON.stringify(metadata));
@@ -114,6 +118,59 @@ function normalizeNativeVirtualRouterError(error) {
114
118
  }
115
119
  return error instanceof Error ? error : new Error(message || 'Virtual router error');
116
120
  }
121
+ function mergeStopMessageSnapshotWithPersisted(snapshot, scope) {
122
+ if (!scope) {
123
+ return snapshot;
124
+ }
125
+ let persisted = null;
126
+ try {
127
+ persisted = loadRoutingInstructionStateSync(scope);
128
+ }
129
+ catch {
130
+ return snapshot;
131
+ }
132
+ if (!persisted) {
133
+ return snapshot;
134
+ }
135
+ const persistedText = typeof persisted.stopMessageText === 'string' ? persisted.stopMessageText.trim() : '';
136
+ if (!snapshot && !persistedText) {
137
+ return snapshot;
138
+ }
139
+ const existing = {
140
+ stopMessageSource: snapshot?.stopMessageSource,
141
+ stopMessageText: snapshot?.stopMessageText,
142
+ stopMessageMaxRepeats: snapshot?.stopMessageMaxRepeats,
143
+ stopMessageUsed: snapshot?.stopMessageUsed,
144
+ stopMessageUpdatedAt: snapshot?.stopMessageUpdatedAt,
145
+ stopMessageLastUsedAt: snapshot?.stopMessageLastUsedAt,
146
+ stopMessageStageMode: snapshot?.stopMessageStageMode,
147
+ stopMessageAiMode: snapshot?.stopMessageAiMode,
148
+ stopMessageAiSeedPrompt: snapshot?.stopMessageAiSeedPrompt,
149
+ stopMessageAiHistory: snapshot?.stopMessageAiHistory
150
+ };
151
+ const merged = mergeStopMessageFromPersisted(existing, persisted);
152
+ const base = snapshot ?? {
153
+ stopMessageMaxRepeats: typeof merged.stopMessageMaxRepeats === 'number' && Number.isFinite(merged.stopMessageMaxRepeats)
154
+ ? merged.stopMessageMaxRepeats
155
+ : 0
156
+ };
157
+ const mergedMaxRepeats = typeof merged.stopMessageMaxRepeats === 'number' && Number.isFinite(merged.stopMessageMaxRepeats)
158
+ ? merged.stopMessageMaxRepeats
159
+ : base.stopMessageMaxRepeats;
160
+ return {
161
+ ...base,
162
+ stopMessageSource: merged.stopMessageSource,
163
+ stopMessageText: merged.stopMessageText,
164
+ stopMessageMaxRepeats: mergedMaxRepeats,
165
+ stopMessageUsed: merged.stopMessageUsed,
166
+ stopMessageUpdatedAt: merged.stopMessageUpdatedAt,
167
+ stopMessageLastUsedAt: merged.stopMessageLastUsedAt,
168
+ stopMessageStageMode: merged.stopMessageStageMode,
169
+ stopMessageAiMode: merged.stopMessageAiMode,
170
+ stopMessageAiSeedPrompt: merged.stopMessageAiSeedPrompt,
171
+ stopMessageAiHistory: merged.stopMessageAiHistory
172
+ };
173
+ }
117
174
  function extractNativeErrorMessage(error) {
118
175
  if (typeof error === 'string') {
119
176
  return error;
@@ -46,7 +46,7 @@ export interface ProviderAuthConfig {
46
46
  }
47
47
  export interface DeepSeekCompatRuntimeOptions {
48
48
  strictToolRequired?: boolean;
49
- textToolFallback?: boolean;
49
+ toolProtocol?: 'native' | 'text';
50
50
  }
51
51
  export interface ProviderProfile {
52
52
  providerKey: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsonstudio/llms",
3
- "version": "0.6.3214",
3
+ "version": "0.6.3271",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",