@jsonstudio/rcc 0.90.814 → 0.90.872
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/README.md +8 -0
- package/configsamples/provider-default/ali-coding-plan/config.v2.json +76 -0
- package/configsamples/provider-default/antigravity/config.v2.json +142 -0
- package/configsamples/provider-default/ark-coding-plan/config.v2.json +64 -0
- package/configsamples/provider-default/crs/config.v2.json +54 -0
- package/configsamples/provider-default/deepseek-web/config.v2.json +56 -0
- package/configsamples/provider-default/gemini/config.v2.json +43 -0
- package/configsamples/provider-default/gemini-cli/config.v2.json +45 -0
- package/configsamples/provider-default/gemini-native/config.v2.json +208 -0
- package/configsamples/provider-default/glm/config.v2.json +33 -0
- package/configsamples/provider-default/glm-anthropic/config.v2.json +29 -0
- package/configsamples/provider-default/kimi/config.v2.json +25 -0
- package/configsamples/provider-default/lmstudio/config.v2.json +79 -0
- package/configsamples/provider-default/lmstudio-proxy/config.v2.json +78 -0
- package/configsamples/provider-default/manifest.json +31 -0
- package/configsamples/provider-default/meituan/config.v2.json +20 -0
- package/configsamples/provider-default/mimo/config.v2.json +26 -0
- package/configsamples/provider-default/modelscope/config.v2.json +81 -0
- package/configsamples/provider-default/my-openai/config.v2.json +20 -0
- package/configsamples/provider-default/nvidia/config.v2.json +32 -0
- package/configsamples/provider-default/opencode-zen-free/config.v2.json +56 -0
- package/configsamples/provider-default/openrouter/config.v2.json +210 -0
- package/configsamples/provider-default/qwen/config.v2.json +38 -0
- package/configsamples/provider-default/qwenchat/config.v2.json +53 -0
- package/configsamples/provider-default/tab/config.v2.json +26 -0
- package/configsamples/provider-default/tabglm/config.v2.json +77 -0
- package/dist/build-info.js +2 -2
- package/dist/cli/commands/config.d.ts +5 -0
- package/dist/cli/commands/config.js +369 -1
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/examples.js +3 -0
- package/dist/cli/commands/examples.js.map +1 -1
- package/dist/cli/commands/init.js +25 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/launcher-kernel.js +122 -46
- package/dist/cli/commands/launcher-kernel.js.map +1 -1
- package/dist/cli/commands/start.js +60 -3
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/config/bundled-provider-pack.d.ts +20 -0
- package/dist/cli/config/bundled-provider-pack.js +146 -0
- package/dist/cli/config/bundled-provider-pack.js.map +1 -0
- package/dist/cli/register/status-config-commands.d.ts +2 -0
- package/dist/cli/register/status-config-commands.js.map +1 -1
- package/dist/cli.js +81 -28
- package/dist/cli.js.map +1 -1
- package/dist/debug/snapshot-store.js +2 -1
- package/dist/debug/snapshot-store.js.map +1 -1
- package/dist/index.js +23 -14
- package/dist/index.js.map +1 -1
- package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js +1 -1
- package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js.map +1 -1
- package/dist/manager/quota/provider-quota-center.js +1 -1
- package/dist/manager/quota/provider-quota-center.js.map +1 -1
- package/dist/manager/storage/file-store.js +10 -0
- package/dist/manager/storage/file-store.js.map +1 -1
- package/dist/modules/llmswitch/bridge/snapshot-recorder-runtime.js +18 -1
- package/dist/modules/llmswitch/bridge/snapshot-recorder-runtime.js.map +1 -1
- package/dist/modules/llmswitch/bridge/snapshot-recorder.js +132 -51
- package/dist/modules/llmswitch/bridge/snapshot-recorder.js.map +1 -1
- package/dist/provider-sdk/provider-runtime-inference.js +2 -2
- package/dist/provider-sdk/provider-runtime-inference.js.map +1 -1
- package/dist/providers/auth/deepseek-account-token-acquirer.js +32 -3
- package/dist/providers/auth/deepseek-account-token-acquirer.js.map +1 -1
- package/dist/providers/core/api/provider-types.d.ts +11 -0
- package/dist/providers/core/config/service-profiles.js +1 -1
- package/dist/providers/core/runtime/deepseek-http-provider.d.ts +2 -0
- package/dist/providers/core/runtime/deepseek-http-provider.js +31 -1
- package/dist/providers/core/runtime/deepseek-http-provider.js.map +1 -1
- package/dist/providers/core/runtime/qwenchat-http-provider-helpers.d.ts +3 -2
- package/dist/providers/core/runtime/qwenchat-http-provider-helpers.js +513 -96
- package/dist/providers/core/runtime/qwenchat-http-provider-helpers.js.map +1 -1
- package/dist/providers/core/runtime/standard-tool-text-harvest.d.ts +8 -0
- package/dist/providers/core/runtime/standard-tool-text-harvest.js +16 -0
- package/dist/providers/core/runtime/standard-tool-text-harvest.js.map +1 -0
- package/dist/providers/core/runtime/standard-tool-text-request-transform.d.ts +4 -1
- package/dist/providers/core/runtime/standard-tool-text-request-transform.js +121 -3
- package/dist/providers/core/runtime/standard-tool-text-request-transform.js.map +1 -1
- package/dist/providers/core/utils/snapshot-writer.js +5 -2
- package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
- package/dist/providers/profile/provider-profile-loader.js +52 -1
- package/dist/providers/profile/provider-profile-loader.js.map +1 -1
- package/dist/providers/profile/provider-profile.d.ts +3 -0
- package/dist/server/handlers/handler-response-utils.js +1 -0
- package/dist/server/handlers/handler-response-utils.js.map +1 -1
- package/dist/server/handlers/images-handler.d.ts +9 -0
- package/dist/server/handlers/images-handler.js +258 -0
- package/dist/server/handlers/images-handler.js.map +1 -0
- package/dist/server/handlers/types.d.ts +7 -0
- package/dist/server/runtime/http-server/antigravity-startup-tasks.d.ts +3 -0
- package/dist/server/runtime/http-server/antigravity-startup-tasks.js +16 -0
- package/dist/server/runtime/http-server/antigravity-startup-tasks.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/auth-handler.js +3 -18
- package/dist/server/runtime/http-server/daemon-admin/auth-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/providers-handler-utils.d.ts +7 -0
- package/dist/server/runtime/http-server/daemon-admin/providers-handler-utils.js +17 -0
- package/dist/server/runtime/http-server/daemon-admin/providers-handler-utils.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.js +50 -17
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin-routes.js +32 -2
- package/dist/server/runtime/http-server/daemon-admin-routes.js.map +1 -1
- package/dist/server/runtime/http-server/executor/provider-response-converter.js +42 -13
- package/dist/server/runtime/http-server/executor/provider-response-converter.js.map +1 -1
- package/dist/server/runtime/http-server/executor/provider-response-utils.js +41 -3
- package/dist/server/runtime/http-server/executor/provider-response-utils.js.map +1 -1
- package/dist/server/runtime/http-server/executor/usage-aggregator.js +7 -7
- package/dist/server/runtime/http-server/executor/usage-aggregator.js.map +1 -1
- package/dist/server/runtime/http-server/executor/usage-logger.d.ts +9 -0
- package/dist/server/runtime/http-server/executor/usage-logger.js +35 -2
- package/dist/server/runtime/http-server/executor/usage-logger.js.map +1 -1
- package/dist/server/runtime/http-server/executor-metadata.js +12 -4
- package/dist/server/runtime/http-server/executor-metadata.js.map +1 -1
- package/dist/server/runtime/http-server/executor-pipeline.js +24 -15
- package/dist/server/runtime/http-server/executor-pipeline.js.map +1 -1
- package/dist/server/runtime/http-server/executor-provider.d.ts +6 -1
- package/dist/server/runtime/http-server/executor-provider.js +137 -5
- package/dist/server/runtime/http-server/executor-provider.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-bootstrap.js +6 -0
- package/dist/server/runtime/http-server/http-server-bootstrap.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-lifecycle.js +23 -15
- package/dist/server/runtime/http-server/http-server-lifecycle.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-runtime-providers.js +14 -4
- package/dist/server/runtime/http-server/http-server-runtime-providers.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-runtime-setup.js +83 -1
- package/dist/server/runtime/http-server/http-server-runtime-setup.js.map +1 -1
- package/dist/server/runtime/http-server/hub-shadow-compare.js +2 -41
- package/dist/server/runtime/http-server/hub-shadow-compare.js.map +1 -1
- package/dist/server/runtime/http-server/provider-routing-scope.d.ts +9 -0
- package/dist/server/runtime/http-server/provider-routing-scope.js +20 -0
- package/dist/server/runtime/http-server/provider-routing-scope.js.map +1 -0
- package/dist/server/runtime/http-server/provider-traffic-governor.d.ts +67 -0
- package/dist/server/runtime/http-server/provider-traffic-governor.js +467 -0
- package/dist/server/runtime/http-server/provider-traffic-governor.js.map +1 -0
- package/dist/server/runtime/http-server/request-executor.d.ts +8 -0
- package/dist/server/runtime/http-server/request-executor.js +446 -21
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/server/runtime/http-server/routes.js +13 -0
- package/dist/server/runtime/http-server/routes.js.map +1 -1
- package/dist/server/runtime/http-server/session-client-registry.js +30 -4
- package/dist/server/runtime/http-server/session-client-registry.js.map +1 -1
- package/dist/server/runtime/http-server/session-client-route-utils.d.ts +7 -0
- package/dist/server/runtime/http-server/session-client-route-utils.js +38 -0
- package/dist/server/runtime/http-server/session-client-route-utils.js.map +1 -1
- package/dist/server/runtime/http-server/session-client-routes.js +12 -2
- package/dist/server/runtime/http-server/session-client-routes.js.map +1 -1
- package/dist/server/utils/request-id-manager.js +42 -5
- package/dist/server/utils/request-id-manager.js.map +1 -1
- package/dist/server/utils/stage-logger.d.ts +1 -0
- package/dist/server/utils/stage-logger.js +27 -0
- package/dist/server/utils/stage-logger.js.map +1 -1
- package/dist/utils/errorsamples.js +3 -1
- package/dist/utils/errorsamples.js.map +1 -1
- package/dist/utils/sensitive-redaction.d.ts +1 -0
- package/dist/utils/sensitive-redaction.js +122 -0
- package/dist/utils/sensitive-redaction.js.map +1 -0
- package/docs/INSTALLATION_AND_QUICKSTART.md +14 -1
- package/docs/PORTS.md +12 -0
- package/docs/lmstudio-tool-calling.md +25 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/qwenchat-web-request.d.ts +3 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/qwenchat-web-request.js +62 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-qwenchat-web.json +47 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/operation-table/operation-table-runner.js +68 -7
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper-from-chat.js +138 -3
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline-chat-process-request-utils.js +24 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline-execute-chat-process-entry.js +7 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline-execute-request-stage.js +7 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline-heavy-input-fastpath.d.ts +24 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline-heavy-input-fastpath.js +203 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline-route-and-outbound.js +17 -12
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-stage-timing.d.ts +11 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-stage-timing.js +82 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +47 -14
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +43 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/client-remap-protocol-switch.js +222 -19
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/policy/policy-engine.js +2 -2
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/process/chat-process-pending-tool-sync.js +24 -7
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/provider-response.js +90 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/snapshot-recorder.d.ts +1 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/snapshot-recorder.js +252 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge/utils.js +5 -3
- package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.js +44 -4
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/anthropic-message-utils-openai-request.d.ts +3 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/anthropic-message-utils-openai-request.js +20 -23
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-governor.js +68 -30
- package/node_modules/@jsonstudio/llms/dist/conversion/snapshot-utils.js +48 -8
- package/node_modules/@jsonstudio/llms/dist/native/router_hotpath_napi.node +0 -0
- package/node_modules/@jsonstudio/llms/dist/quota/quota-state.js +2 -2
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine/routing-state/store.js +35 -2
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.js +9 -9
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/sticky-session-store.js +104 -18
- package/node_modules/@jsonstudio/llms/dist/servertool/engine.js +79 -32
- package/node_modules/@jsonstudio/llms/dist/servertool/handlers/vision.js +49 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/pending-session.js +48 -2
- package/node_modules/@jsonstudio/llms/dist/servertool/server-side-tools.js +14 -1
- package/node_modules/@jsonstudio/llms/dist/servertool/types.d.ts +1 -0
- package/node_modules/@jsonstudio/llms/package.json +1 -1
- package/node_modules/ajv/dist/compile/jtd/serialize.js +9 -2
- package/node_modules/ajv/dist/compile/jtd/serialize.js.map +1 -1
- package/node_modules/ajv/dist/core.d.ts +1 -0
- package/node_modules/ajv/dist/core.js.map +1 -1
- package/node_modules/ajv/dist/vocabularies/validation/pattern.js +13 -4
- package/node_modules/ajv/dist/vocabularies/validation/pattern.js.map +1 -1
- package/node_modules/ajv/lib/compile/jtd/serialize.ts +13 -2
- package/node_modules/ajv/lib/core.ts +1 -0
- package/node_modules/ajv/lib/vocabularies/validation/pattern.ts +15 -4
- package/node_modules/ajv/package.json +2 -1
- package/package.json +15 -10
- package/scripts/ci/repo-sanity.mjs +23 -2
- package/scripts/ci/secrets-check.mjs +48 -0
- package/scripts/ci/silent-failure-audit.mjs +192 -0
- package/scripts/mock-provider/run-regressions.mjs +1 -0
- package/scripts/pack-mode.mjs +32 -36
- package/scripts/publish-rcc.mjs +38 -60
- package/scripts/tests/apply-patch-loop.mjs +1 -0
- package/scripts/tests/blackbox-rcc-vs-routecodex-antigravity.mjs +2 -0
- package/scripts/tools-dev/responses-debug-client/src/index.ts +8 -3
- package/scripts/verify-e2e-toolcall.mjs +1 -0
- package/scripts/verify-install-e2e.mjs +2 -1
|
@@ -13,6 +13,11 @@ import { resolveRccPath } from '../../runtime/user-data-paths.js';
|
|
|
13
13
|
function isObject(v) { return !!v && typeof v === 'object' && !Array.isArray(v); }
|
|
14
14
|
// Note: tool schema strict augmentation removed per alignment
|
|
15
15
|
function enforceChatBudget(chat, _modelId) { return chat; }
|
|
16
|
+
function logToolGovernorNonBlocking(stage, error) {
|
|
17
|
+
const message = error instanceof Error ? error.message : String(error ?? 'unknown');
|
|
18
|
+
// eslint-disable-next-line no-console
|
|
19
|
+
console.warn(`[tool-governor][non-blocking] stage=${stage} error=${message}`);
|
|
20
|
+
}
|
|
16
21
|
function tryWriteSnapshot(options, stage, data) {
|
|
17
22
|
try {
|
|
18
23
|
// 仅在 verbose 级别保存快照(环境变量)
|
|
@@ -37,7 +42,9 @@ function tryWriteSnapshot(options, stage, data) {
|
|
|
37
42
|
const payload = JSON.stringify(data, null, 2);
|
|
38
43
|
fs.writeFileSync(file, payload, 'utf-8');
|
|
39
44
|
}
|
|
40
|
-
catch {
|
|
45
|
+
catch (error) {
|
|
46
|
+
logToolGovernorNonBlocking(`snapshot_write:${stage}`, error);
|
|
47
|
+
}
|
|
41
48
|
}
|
|
42
49
|
/**
|
|
43
50
|
* Process OpenAI Chat request (messages/tools) with unified 标准 governance.
|
|
@@ -74,7 +81,9 @@ export function processChatRequestTools(request, opts) {
|
|
|
74
81
|
out.tools = augmentOpenAITools(tools);
|
|
75
82
|
}
|
|
76
83
|
}
|
|
77
|
-
catch {
|
|
84
|
+
catch (error) {
|
|
85
|
+
logToolGovernorNonBlocking('request_minimal_tool_shape_repair', error);
|
|
86
|
+
}
|
|
78
87
|
// 1) 移除工具 schema 严格化(与 统一标准,不在此处约束 tools 结构)
|
|
79
88
|
// NOTE: system guidance injection removed by design (align with parameter-level strategy)
|
|
80
89
|
try {
|
|
@@ -94,13 +103,16 @@ export function processChatRequestTools(request, opts) {
|
|
|
94
103
|
}
|
|
95
104
|
}
|
|
96
105
|
}
|
|
97
|
-
catch {
|
|
106
|
+
catch (error) {
|
|
107
|
+
logToolGovernorNonBlocking('request_tool_choice_policy', error);
|
|
108
|
+
}
|
|
98
109
|
// 4) Enforce payload budget (context bytes) with minimal loss policy
|
|
99
110
|
const modelId = typeof canonical?.model === 'string' ? String(canonical.model) : 'unknown';
|
|
100
111
|
const budgeted = enforceChatBudget(canonical, modelId);
|
|
101
112
|
return normalizeSpecialToolCallsOnRequest(budgeted);
|
|
102
113
|
}
|
|
103
|
-
catch {
|
|
114
|
+
catch (error) {
|
|
115
|
+
logToolGovernorNonBlocking('process_chat_request_tools', error);
|
|
104
116
|
return out;
|
|
105
117
|
}
|
|
106
118
|
}
|
|
@@ -150,19 +162,20 @@ export function normalizeApplyPatchToolCallsOnResponse(chat) {
|
|
|
150
162
|
// eslint-disable-next-line no-console
|
|
151
163
|
console.error(`\x1b[31m[apply_patch][precheck][response] validation_failed reason=${reason}${snippet ? ` args=${snippet}` : ''}\x1b[0m`);
|
|
152
164
|
}
|
|
153
|
-
catch {
|
|
154
|
-
|
|
165
|
+
catch (error) {
|
|
166
|
+
logToolGovernorNonBlocking('response_apply_patch_regression_capture', error);
|
|
155
167
|
}
|
|
156
168
|
}
|
|
157
169
|
}
|
|
158
|
-
catch {
|
|
159
|
-
|
|
170
|
+
catch (error) {
|
|
171
|
+
logToolGovernorNonBlocking('response_tool_call_normalize_item', error);
|
|
160
172
|
}
|
|
161
173
|
}
|
|
162
174
|
}
|
|
163
175
|
return out;
|
|
164
176
|
}
|
|
165
|
-
catch {
|
|
177
|
+
catch (error) {
|
|
178
|
+
logToolGovernorNonBlocking('normalize_apply_patch_tool_calls_on_response', error);
|
|
166
179
|
return chat;
|
|
167
180
|
}
|
|
168
181
|
}
|
|
@@ -232,8 +245,8 @@ function normalizeSpecialToolCallsOnRequest(request) {
|
|
|
232
245
|
// eslint-disable-next-line no-console
|
|
233
246
|
console.error(`\x1b[31m[apply_patch][precheck][request] validation_failed reason=${reason}${snippet ? ` args=${snippet}` : ''}\x1b[0m`);
|
|
234
247
|
}
|
|
235
|
-
catch {
|
|
236
|
-
|
|
248
|
+
catch (error) {
|
|
249
|
+
logToolGovernorNonBlocking('request_apply_patch_regression_capture', error);
|
|
237
250
|
}
|
|
238
251
|
}
|
|
239
252
|
continue;
|
|
@@ -253,7 +266,8 @@ function normalizeSpecialToolCallsOnRequest(request) {
|
|
|
253
266
|
try {
|
|
254
267
|
parsed = JSON.parse(argsStr);
|
|
255
268
|
}
|
|
256
|
-
catch {
|
|
269
|
+
catch (error) {
|
|
270
|
+
logToolGovernorNonBlocking('request_exec_command_parse_json', error);
|
|
257
271
|
parsed = parseLenient(argsStr);
|
|
258
272
|
}
|
|
259
273
|
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
@@ -262,15 +276,16 @@ function normalizeSpecialToolCallsOnRequest(request) {
|
|
|
262
276
|
try {
|
|
263
277
|
fn.arguments = JSON.stringify(next ?? {});
|
|
264
278
|
}
|
|
265
|
-
catch {
|
|
279
|
+
catch (error) {
|
|
280
|
+
logToolGovernorNonBlocking('request_exec_command_json_stringify', error);
|
|
266
281
|
fn.arguments = '{}';
|
|
267
282
|
}
|
|
268
283
|
}
|
|
269
284
|
}
|
|
270
285
|
}
|
|
271
286
|
}
|
|
272
|
-
catch {
|
|
273
|
-
|
|
287
|
+
catch (error) {
|
|
288
|
+
logToolGovernorNonBlocking('request_tool_call_normalize_item', error);
|
|
274
289
|
}
|
|
275
290
|
}
|
|
276
291
|
}
|
|
@@ -279,7 +294,8 @@ function normalizeSpecialToolCallsOnRequest(request) {
|
|
|
279
294
|
}
|
|
280
295
|
return out;
|
|
281
296
|
}
|
|
282
|
-
catch {
|
|
297
|
+
catch (error) {
|
|
298
|
+
logToolGovernorNonBlocking('normalize_special_tool_calls_on_request', error);
|
|
283
299
|
return request;
|
|
284
300
|
}
|
|
285
301
|
}
|
|
@@ -319,7 +335,8 @@ function enhanceResponseToolArguments(chat) {
|
|
|
319
335
|
out = out.replace(/(?<!\\)\(/g, '\\(').replace(/(?<!\\)\)/g, '\\)');
|
|
320
336
|
return out;
|
|
321
337
|
}
|
|
322
|
-
catch {
|
|
338
|
+
catch (error) {
|
|
339
|
+
logToolGovernorNonBlocking('enhance_response_tool_arguments_repair_find_meta', error);
|
|
323
340
|
return s;
|
|
324
341
|
}
|
|
325
342
|
};
|
|
@@ -337,7 +354,8 @@ function enhanceResponseToolArguments(chat) {
|
|
|
337
354
|
try {
|
|
338
355
|
parsed = JSON.parse(repaired);
|
|
339
356
|
}
|
|
340
|
-
catch {
|
|
357
|
+
catch (error) {
|
|
358
|
+
logToolGovernorNonBlocking('enhance_response_tool_arguments_parse_json', error);
|
|
341
359
|
parsed = parseLenient(repaired);
|
|
342
360
|
}
|
|
343
361
|
if (parsed && typeof parsed === 'object') {
|
|
@@ -367,7 +385,8 @@ function enhanceResponseToolArguments(chat) {
|
|
|
367
385
|
try {
|
|
368
386
|
finalStr = JSON.stringify(parsed);
|
|
369
387
|
}
|
|
370
|
-
catch {
|
|
388
|
+
catch (error) {
|
|
389
|
+
logToolGovernorNonBlocking('enhance_response_tool_arguments_json_stringify', error);
|
|
371
390
|
finalStr = repaired;
|
|
372
391
|
}
|
|
373
392
|
}
|
|
@@ -384,23 +403,31 @@ function enhanceResponseToolArguments(chat) {
|
|
|
384
403
|
if (fn)
|
|
385
404
|
fn.arguments = finalStr;
|
|
386
405
|
}
|
|
387
|
-
catch {
|
|
406
|
+
catch (error) {
|
|
407
|
+
logToolGovernorNonBlocking('enhance_response_tool_arguments_item', error);
|
|
408
|
+
}
|
|
388
409
|
}
|
|
389
410
|
// Ensure finish_reason/tool_calls invariant if missing (idempotent with canonicalizer)
|
|
390
411
|
try {
|
|
391
412
|
if (!ch.finish_reason)
|
|
392
413
|
ch.finish_reason = 'tool_calls';
|
|
393
414
|
}
|
|
394
|
-
catch {
|
|
415
|
+
catch (error) {
|
|
416
|
+
logToolGovernorNonBlocking('enhance_response_tool_arguments_finish_reason', error);
|
|
417
|
+
}
|
|
395
418
|
try {
|
|
396
|
-
if (msg && typeof msg === 'object' && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0)
|
|
419
|
+
if (msg && typeof msg === 'object' && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
|
|
397
420
|
msg.content = null;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
catch (error) {
|
|
424
|
+
logToolGovernorNonBlocking('enhance_response_tool_arguments_message_content', error);
|
|
398
425
|
}
|
|
399
|
-
catch { /* ignore */ }
|
|
400
426
|
}
|
|
401
427
|
return out;
|
|
402
428
|
}
|
|
403
|
-
catch {
|
|
429
|
+
catch (error) {
|
|
430
|
+
logToolGovernorNonBlocking('enhance_response_tool_arguments', error);
|
|
404
431
|
return chat;
|
|
405
432
|
}
|
|
406
433
|
}
|
|
@@ -412,7 +439,8 @@ export function processChatResponseTools(resp) {
|
|
|
412
439
|
const withPatch = normalizeApplyPatchToolCallsOnResponse(canon);
|
|
413
440
|
return enhanceResponseToolArguments(withPatch);
|
|
414
441
|
}
|
|
415
|
-
catch {
|
|
442
|
+
catch (error) {
|
|
443
|
+
logToolGovernorNonBlocking('process_chat_response_tools', error);
|
|
416
444
|
return resp;
|
|
417
445
|
}
|
|
418
446
|
}
|
|
@@ -432,21 +460,27 @@ export function governTools(payload, ctx) {
|
|
|
432
460
|
const opts = { snapshot: ctx?.snapshot || { enabled: true, endpoint: ep, requestId: ctx?.requestId } };
|
|
433
461
|
tryWriteSnapshot(opts, 'response_before_canonicalize', payload);
|
|
434
462
|
}
|
|
435
|
-
catch {
|
|
463
|
+
catch (error) {
|
|
464
|
+
logToolGovernorNonBlocking('govern_tools_snapshot_before_canonicalize', error);
|
|
465
|
+
}
|
|
436
466
|
let out = processChatResponseTools(payload);
|
|
437
467
|
// 变更后快照:响应侧 canonicalize 之后
|
|
438
468
|
try {
|
|
439
469
|
const opts = { snapshot: ctx?.snapshot || { enabled: true, endpoint: ep, requestId: ctx?.requestId } };
|
|
440
470
|
tryWriteSnapshot(opts, 'response_after_canonicalize', out);
|
|
441
471
|
}
|
|
442
|
-
catch {
|
|
472
|
+
catch (error) {
|
|
473
|
+
logToolGovernorNonBlocking('govern_tools_snapshot_after_canonicalize', error);
|
|
474
|
+
}
|
|
443
475
|
if (ep === 'responses' && ctx?.stream !== true && ctx?.produceRequiredAction !== false) {
|
|
444
476
|
// 变更前快照:构造 required_action 之前
|
|
445
477
|
try {
|
|
446
478
|
const opts = { snapshot: ctx?.snapshot || { enabled: true, endpoint: ep, requestId: ctx?.requestId } };
|
|
447
479
|
tryWriteSnapshot(opts, 'response_before_required_action', out);
|
|
448
480
|
}
|
|
449
|
-
catch {
|
|
481
|
+
catch (error) {
|
|
482
|
+
logToolGovernorNonBlocking('govern_tools_snapshot_before_required_action', error);
|
|
483
|
+
}
|
|
450
484
|
try {
|
|
451
485
|
const { buildResponsesPayloadFromChat } = require('../responses/responses-openai-bridge.js');
|
|
452
486
|
const res = buildResponsesPayloadFromChat(out, { requestId: ctx?.requestId });
|
|
@@ -454,10 +488,14 @@ export function governTools(payload, ctx) {
|
|
|
454
488
|
const opts = { snapshot: ctx?.snapshot || { enabled: true, endpoint: ep, requestId: ctx?.requestId } };
|
|
455
489
|
tryWriteSnapshot(opts, 'response_after_required_action', res);
|
|
456
490
|
}
|
|
457
|
-
catch {
|
|
491
|
+
catch (error) {
|
|
492
|
+
logToolGovernorNonBlocking('govern_tools_snapshot_after_required_action', error);
|
|
493
|
+
}
|
|
458
494
|
return res;
|
|
459
495
|
}
|
|
460
|
-
catch {
|
|
496
|
+
catch (error) {
|
|
497
|
+
logToolGovernorNonBlocking('govern_tools_required_action_bridge', error);
|
|
498
|
+
}
|
|
461
499
|
}
|
|
462
500
|
return out;
|
|
463
501
|
}
|
|
@@ -30,20 +30,60 @@ export async function recordSnapshot(options) {
|
|
|
30
30
|
// ignore hook errors
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
+
const MAX_SNAPSHOT_QUEUE_SIZE = 2048;
|
|
34
|
+
const SNAPSHOT_QUEUE_BATCH_SIZE = 64;
|
|
35
|
+
const SNAPSHOT_QUEUE = [];
|
|
36
|
+
let snapshotQueueDrainScheduled = false;
|
|
37
|
+
function scheduleSnapshotQueueDrain() {
|
|
38
|
+
if (snapshotQueueDrainScheduled) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
snapshotQueueDrainScheduled = true;
|
|
42
|
+
setImmediate(() => {
|
|
43
|
+
snapshotQueueDrainScheduled = false;
|
|
44
|
+
let processed = 0;
|
|
45
|
+
while (SNAPSHOT_QUEUE.length > 0 && processed < SNAPSHOT_QUEUE_BATCH_SIZE) {
|
|
46
|
+
const task = SNAPSHOT_QUEUE.shift();
|
|
47
|
+
if (!task) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
task();
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// snapshot write failures are non-blocking by design
|
|
55
|
+
}
|
|
56
|
+
processed += 1;
|
|
57
|
+
}
|
|
58
|
+
if (SNAPSHOT_QUEUE.length > 0) {
|
|
59
|
+
scheduleSnapshotQueueDrain();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function enqueueSnapshotTask(task) {
|
|
64
|
+
if (SNAPSHOT_QUEUE.length >= MAX_SNAPSHOT_QUEUE_SIZE) {
|
|
65
|
+
// keep newest writes; snapshot stream is best-effort and must not block request hot path
|
|
66
|
+
SNAPSHOT_QUEUE.shift();
|
|
67
|
+
}
|
|
68
|
+
SNAPSHOT_QUEUE.push(task);
|
|
69
|
+
scheduleSnapshotQueueDrain();
|
|
70
|
+
}
|
|
33
71
|
export function createSnapshotWriter(opts) {
|
|
34
72
|
if (!shouldRecordSnapshots()) {
|
|
35
73
|
return undefined;
|
|
36
74
|
}
|
|
37
75
|
const endpoint = opts.endpoint || '/v1/chat/completions';
|
|
38
76
|
return (stage, payload) => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
77
|
+
enqueueSnapshotTask(() => {
|
|
78
|
+
void recordSnapshot({
|
|
79
|
+
stage,
|
|
80
|
+
requestId: opts.requestId,
|
|
81
|
+
endpoint,
|
|
82
|
+
folderHint: opts.folderHint,
|
|
83
|
+
providerKey: opts.providerKey,
|
|
84
|
+
groupRequestId: opts.groupRequestId,
|
|
85
|
+
data: payload
|
|
86
|
+
});
|
|
47
87
|
});
|
|
48
88
|
};
|
|
49
89
|
}
|
|
Binary file
|
|
@@ -153,10 +153,10 @@ export function applyErrorEvent(state, event, nowMs = event.timestampMs ?? Date.
|
|
|
153
153
|
? COOLDOWN_SCHEDULE_FATAL_MS
|
|
154
154
|
: COOLDOWN_SCHEDULE_DEFAULT_MS;
|
|
155
155
|
const rawNextCount = sameErrorKey ? state.consecutiveErrorCount + 1 : 1;
|
|
156
|
-
const nextCount = rawNextCount
|
|
156
|
+
const nextCount = Math.min(rawNextCount, Math.max(1, schedule.length));
|
|
157
157
|
const cooldownMs = computeTransientKeepPoolCooldownMs(series, nextCount) ?? computeCooldownMsBySeries(series, nextCount);
|
|
158
158
|
const nextUntil = cooldownMs ? nowMs + cooldownMs : null;
|
|
159
|
-
const existingUntil = typeof state.cooldownUntil === 'number' ? state.cooldownUntil : null;
|
|
159
|
+
const existingUntil = sameErrorKey && typeof state.cooldownUntil === 'number' ? state.cooldownUntil : null;
|
|
160
160
|
const cooldownUntil = typeof nextUntil === 'number' && Number.isFinite(nextUntil)
|
|
161
161
|
? typeof existingUntil === 'number' && existingUntil > nextUntil
|
|
162
162
|
? existingUntil
|
package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine/routing-state/store.js
CHANGED
|
@@ -1,4 +1,36 @@
|
|
|
1
1
|
import { mergeStopMessageFromPersisted } from '../../stop-message-state-sync.js';
|
|
2
|
+
import { providerErrorCenter } from '../../error-center.js';
|
|
3
|
+
function formatError(error) {
|
|
4
|
+
if (error instanceof Error) {
|
|
5
|
+
return error.message;
|
|
6
|
+
}
|
|
7
|
+
return String(error);
|
|
8
|
+
}
|
|
9
|
+
function emitRoutingStateRefreshError(key, error) {
|
|
10
|
+
const errorMessage = formatError(error);
|
|
11
|
+
providerErrorCenter.emit({
|
|
12
|
+
code: 'STICKY_STATE_REFRESH_FAILED',
|
|
13
|
+
message: 'failed to refresh in-memory routing state from persisted sticky store',
|
|
14
|
+
stage: 'sticky_session.refresh',
|
|
15
|
+
timestamp: Date.now(),
|
|
16
|
+
runtime: {
|
|
17
|
+
requestId: 'routing-state-store',
|
|
18
|
+
providerProtocol: 'sticky-session-store',
|
|
19
|
+
providerType: 'internal'
|
|
20
|
+
},
|
|
21
|
+
details: {
|
|
22
|
+
operation: 'refresh_existing_state',
|
|
23
|
+
key,
|
|
24
|
+
error: errorMessage
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
try {
|
|
28
|
+
console.warn(`[routing-state-store] STICKY_STATE_REFRESH_FAILED key=${key} error=${errorMessage}`);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// no-op
|
|
32
|
+
}
|
|
33
|
+
}
|
|
2
34
|
function readToken(value) {
|
|
3
35
|
if (typeof value !== 'string') {
|
|
4
36
|
return '';
|
|
@@ -66,8 +98,9 @@ export function getRoutingInstructionState(stickyKey, routingInstructionState, r
|
|
|
66
98
|
existing.preCommandUpdatedAt = persisted.preCommandUpdatedAt;
|
|
67
99
|
}
|
|
68
100
|
}
|
|
69
|
-
catch {
|
|
70
|
-
//
|
|
101
|
+
catch (error) {
|
|
102
|
+
// 刷新失败不影响原有内存状态,但必须显式上报,禁止静默吞错
|
|
103
|
+
emitRoutingStateRefreshError(key, error);
|
|
71
104
|
}
|
|
72
105
|
return existing;
|
|
73
106
|
}
|
|
@@ -64,20 +64,20 @@ export class VirtualRouterEngine {
|
|
|
64
64
|
}
|
|
65
65
|
const parsed = JSON.parse(raw);
|
|
66
66
|
emitStopMessageMarkerParseLog(parseLog);
|
|
67
|
-
// Keep legacy observable behavior for callers/tests that inspect the request object
|
|
68
|
-
// after route(): instruction markers are stripped from forwarded payload structures.
|
|
69
67
|
cleanStopMessageMarkersInPlace(request);
|
|
70
68
|
const stopScope = parseLog?.stopScope || resolveStopMessageScope(metadata);
|
|
71
69
|
const stopState = stopScope ? this.getStopMessageState(metadata) : null;
|
|
72
70
|
const forceStopStatusLabel = Boolean(parseLog?.stopMessageTypes.length ||
|
|
73
71
|
parseLog?.scopedTypes.some((type) => type === 'stopMessageSet' || type === 'stopMessageMode' || type === 'stopMessageClear'));
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
72
|
+
if (metadata.__rt?.disableVirtualRouterHitLog !== true) {
|
|
73
|
+
emitVirtualRouterHitLog(parsed, {
|
|
74
|
+
requestId: metadata.requestId,
|
|
75
|
+
sessionId: resolveVirtualRouterLogSessionId(metadata),
|
|
76
|
+
stopScope,
|
|
77
|
+
stopState,
|
|
78
|
+
forceStopStatusLabel
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
81
|
return parsed;
|
|
82
82
|
}
|
|
83
83
|
getStopMessageState(metadata) {
|
|
@@ -1,8 +1,44 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import { serializeRoutingInstructionState, deserializeRoutingInstructionState } from './routing-instructions.js';
|
|
4
|
+
import { providerErrorCenter } from './error-center.js';
|
|
4
5
|
import { resolveRccPath } from '../../runtime/user-data-paths.js';
|
|
5
6
|
const pendingWrites = new Map();
|
|
7
|
+
const STICKY_RUNTIME_REQUEST_ID = 'sticky-session-store';
|
|
8
|
+
function isNodeErrorWithCode(error) {
|
|
9
|
+
return !!error && typeof error === 'object' && 'code' in error;
|
|
10
|
+
}
|
|
11
|
+
function shouldIgnoreUnlinkError(error) {
|
|
12
|
+
return isNodeErrorWithCode(error) && error.code === 'ENOENT';
|
|
13
|
+
}
|
|
14
|
+
function formatError(error) {
|
|
15
|
+
if (error instanceof Error) {
|
|
16
|
+
return error.message;
|
|
17
|
+
}
|
|
18
|
+
return String(error);
|
|
19
|
+
}
|
|
20
|
+
function emitStickyStoreError(code, stage, message, details) {
|
|
21
|
+
providerErrorCenter.emit({
|
|
22
|
+
code,
|
|
23
|
+
message,
|
|
24
|
+
stage,
|
|
25
|
+
timestamp: Date.now(),
|
|
26
|
+
runtime: {
|
|
27
|
+
requestId: STICKY_RUNTIME_REQUEST_ID,
|
|
28
|
+
providerProtocol: 'sticky-session-store',
|
|
29
|
+
providerType: 'internal'
|
|
30
|
+
},
|
|
31
|
+
details
|
|
32
|
+
});
|
|
33
|
+
try {
|
|
34
|
+
const op = typeof details.operation === 'string' ? details.operation : 'unknown';
|
|
35
|
+
const errMsg = typeof details.error === 'string' ? details.error : '';
|
|
36
|
+
console.warn(`[sticky-session-store] ${code} stage=${stage} op=${op}${errMsg ? ` error=${errMsg}` : ''}`);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// no-op
|
|
40
|
+
}
|
|
41
|
+
}
|
|
6
42
|
export class StickySessionKeyMissingError extends Error {
|
|
7
43
|
key;
|
|
8
44
|
constructor(key, message) {
|
|
@@ -78,9 +114,14 @@ function readPersistedStateFromFile(filepath) {
|
|
|
78
114
|
try {
|
|
79
115
|
parsed = JSON.parse(raw);
|
|
80
116
|
}
|
|
81
|
-
catch {
|
|
117
|
+
catch (parseError) {
|
|
82
118
|
const recovered = recoverPersistedJson(raw);
|
|
83
119
|
if (!recovered) {
|
|
120
|
+
emitStickyStoreError('STICKY_STATE_READ_FAILED', 'sticky_session.read', 'failed to parse persisted sticky state JSON', {
|
|
121
|
+
operation: 'read_parse_json',
|
|
122
|
+
filepath,
|
|
123
|
+
error: formatError(parseError)
|
|
124
|
+
});
|
|
84
125
|
return null;
|
|
85
126
|
}
|
|
86
127
|
parsed = recovered;
|
|
@@ -90,8 +131,12 @@ function readPersistedStateFromFile(filepath) {
|
|
|
90
131
|
: { version: 1, state: parsed };
|
|
91
132
|
atomicWriteFileSync(filepath, JSON.stringify(payload));
|
|
92
133
|
}
|
|
93
|
-
catch {
|
|
94
|
-
|
|
134
|
+
catch (rewriteError) {
|
|
135
|
+
emitStickyStoreError('STICKY_STATE_RECOVER_FAILED', 'sticky_session.recover', 'failed to rewrite recovered sticky state payload', {
|
|
136
|
+
operation: 'recover_rewrite',
|
|
137
|
+
filepath,
|
|
138
|
+
error: formatError(rewriteError)
|
|
139
|
+
});
|
|
95
140
|
}
|
|
96
141
|
}
|
|
97
142
|
const payload = parsed && typeof parsed.version === 'number'
|
|
@@ -102,7 +147,12 @@ function readPersistedStateFromFile(filepath) {
|
|
|
102
147
|
}
|
|
103
148
|
return deserializeRoutingInstructionState(payload);
|
|
104
149
|
}
|
|
105
|
-
catch {
|
|
150
|
+
catch (error) {
|
|
151
|
+
emitStickyStoreError('STICKY_STATE_READ_FAILED', 'sticky_session.read', 'failed to read sticky session state from disk', {
|
|
152
|
+
operation: 'read_file',
|
|
153
|
+
filepath,
|
|
154
|
+
error: formatError(error)
|
|
155
|
+
});
|
|
106
156
|
return null;
|
|
107
157
|
}
|
|
108
158
|
}
|
|
@@ -137,8 +187,14 @@ export function saveRoutingInstructionStateAsync(key, state) {
|
|
|
137
187
|
try {
|
|
138
188
|
await fs.promises.unlink(filepath);
|
|
139
189
|
}
|
|
140
|
-
catch {
|
|
141
|
-
|
|
190
|
+
catch (error) {
|
|
191
|
+
if (!shouldIgnoreUnlinkError(error)) {
|
|
192
|
+
emitStickyStoreError('STICKY_STATE_PERSIST_FAILED', 'sticky_session.persist', 'failed to unlink sticky session state file', {
|
|
193
|
+
operation: 'unlink',
|
|
194
|
+
filepath,
|
|
195
|
+
error: formatError(error)
|
|
196
|
+
});
|
|
197
|
+
}
|
|
142
198
|
}
|
|
143
199
|
});
|
|
144
200
|
}
|
|
@@ -154,14 +210,24 @@ export function saveRoutingInstructionStateAsync(key, state) {
|
|
|
154
210
|
try {
|
|
155
211
|
await fs.promises.mkdir(dir, { recursive: true });
|
|
156
212
|
}
|
|
157
|
-
catch {
|
|
158
|
-
|
|
213
|
+
catch (error) {
|
|
214
|
+
emitStickyStoreError('STICKY_STATE_PERSIST_FAILED', 'sticky_session.persist', 'failed to create sticky session state directory', {
|
|
215
|
+
operation: 'mkdir',
|
|
216
|
+
filepath,
|
|
217
|
+
dir,
|
|
218
|
+
error: formatError(error)
|
|
219
|
+
});
|
|
159
220
|
}
|
|
160
221
|
try {
|
|
161
222
|
await atomicWriteFile(filepath, JSON.stringify(payload));
|
|
162
223
|
}
|
|
163
|
-
catch {
|
|
164
|
-
|
|
224
|
+
catch (error) {
|
|
225
|
+
emitStickyStoreError('STICKY_STATE_PERSIST_FAILED', 'sticky_session.persist', 'failed to persist sticky session state file', {
|
|
226
|
+
operation: 'write',
|
|
227
|
+
filepath,
|
|
228
|
+
dir,
|
|
229
|
+
error: formatError(error)
|
|
230
|
+
});
|
|
165
231
|
}
|
|
166
232
|
});
|
|
167
233
|
}
|
|
@@ -179,8 +245,14 @@ export function saveRoutingInstructionStateSync(key, state) {
|
|
|
179
245
|
try {
|
|
180
246
|
fs.unlinkSync(filepath);
|
|
181
247
|
}
|
|
182
|
-
catch {
|
|
183
|
-
|
|
248
|
+
catch (error) {
|
|
249
|
+
if (!shouldIgnoreUnlinkError(error)) {
|
|
250
|
+
emitStickyStoreError('STICKY_STATE_PERSIST_FAILED', 'sticky_session.persist', 'failed to unlink sticky session state file', {
|
|
251
|
+
operation: 'unlinkSync',
|
|
252
|
+
filepath,
|
|
253
|
+
error: formatError(error)
|
|
254
|
+
});
|
|
255
|
+
}
|
|
184
256
|
}
|
|
185
257
|
}
|
|
186
258
|
return;
|
|
@@ -194,14 +266,24 @@ export function saveRoutingInstructionStateSync(key, state) {
|
|
|
194
266
|
try {
|
|
195
267
|
fs.mkdirSync(dir, { recursive: true });
|
|
196
268
|
}
|
|
197
|
-
catch {
|
|
198
|
-
|
|
269
|
+
catch (error) {
|
|
270
|
+
emitStickyStoreError('STICKY_STATE_PERSIST_FAILED', 'sticky_session.persist', 'failed to create sticky session state directory', {
|
|
271
|
+
operation: 'mkdirSync',
|
|
272
|
+
filepath,
|
|
273
|
+
dir,
|
|
274
|
+
error: formatError(error)
|
|
275
|
+
});
|
|
199
276
|
}
|
|
200
277
|
try {
|
|
201
278
|
atomicWriteFileSync(filepath, JSON.stringify(payload));
|
|
202
279
|
}
|
|
203
|
-
catch {
|
|
204
|
-
|
|
280
|
+
catch (error) {
|
|
281
|
+
emitStickyStoreError('STICKY_STATE_PERSIST_FAILED', 'sticky_session.persist', 'failed to persist sticky session state file', {
|
|
282
|
+
operation: 'writeSync',
|
|
283
|
+
filepath,
|
|
284
|
+
dir,
|
|
285
|
+
error: formatError(error)
|
|
286
|
+
});
|
|
205
287
|
}
|
|
206
288
|
}
|
|
207
289
|
}
|
|
@@ -209,8 +291,12 @@ function scheduleWrite(filepath, task) {
|
|
|
209
291
|
const previous = pendingWrites.get(filepath) ?? Promise.resolve();
|
|
210
292
|
const next = previous
|
|
211
293
|
.then(task)
|
|
212
|
-
.catch(() => {
|
|
213
|
-
|
|
294
|
+
.catch((error) => {
|
|
295
|
+
emitStickyStoreError('STICKY_STATE_PERSIST_FAILED', 'sticky_session.persist', 'unexpected sticky session async write task failure', {
|
|
296
|
+
operation: 'scheduleWrite',
|
|
297
|
+
filepath,
|
|
298
|
+
error: formatError(error)
|
|
299
|
+
});
|
|
214
300
|
})
|
|
215
301
|
.finally(() => {
|
|
216
302
|
if (pendingWrites.get(filepath) === next) {
|