@jsonstudio/llms 0.6.3551 → 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.
Files changed (66) hide show
  1. package/dist/conversion/compat/actions/antigravity-thought-signature-cache.js +4 -115
  2. package/dist/conversion/compat/actions/auto-thinking.js +3 -2
  3. package/dist/conversion/compat/actions/deepseek-web-response.js +15 -49
  4. package/dist/conversion/compat/actions/gemini-cli-request.d.ts +2 -0
  5. package/dist/conversion/compat/actions/gemini-cli-request.js +1 -1
  6. package/dist/conversion/compat/actions/glm-history-image-trim.js +3 -37
  7. package/dist/conversion/compat/actions/glm-image-content.js +3 -32
  8. package/dist/conversion/compat/actions/glm-native-compat.d.ts +6 -0
  9. package/dist/conversion/compat/actions/glm-native-compat.js +34 -0
  10. package/dist/conversion/compat/actions/glm-vision-prompt.js +3 -76
  11. package/dist/conversion/compat/actions/glm-web-search.js +10 -43
  12. package/dist/conversion/compat/actions/iflow-kimi-cli-defaults.js +4 -53
  13. package/dist/conversion/compat/actions/iflow-kimi-history-media-placeholder.js +5 -141
  14. package/dist/conversion/compat/actions/iflow-kimi-thinking-reasoning-fill.js +7 -28
  15. package/dist/conversion/compat/actions/iflow-native-compat.d.ts +6 -0
  16. package/dist/conversion/compat/actions/iflow-native-compat.js +36 -0
  17. package/dist/conversion/compat/actions/iflow-response-body-unwrap.js +4 -119
  18. package/dist/conversion/compat/actions/iflow-web-search.js +14 -55
  19. package/dist/conversion/hub/operation-table/semantic-mappers/archive/chat-mapper.archive.js +5 -0
  20. package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +31 -18
  21. package/dist/conversion/hub/pipeline/hub-pipeline.js +163 -163
  22. package/dist/conversion/hub/pipeline/hub-stage-timing.d.ts +6 -0
  23. package/dist/conversion/hub/pipeline/hub-stage-timing.js +178 -0
  24. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.d.ts +4 -4
  25. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.js +33 -14
  26. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +7 -6
  27. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +41 -23
  28. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +44 -1
  29. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.js +4 -1
  30. package/dist/conversion/hub/process/chat-process-continue-execution.js +5 -4
  31. package/dist/conversion/hub/process/chat-process-governance-orchestration.js +3 -1
  32. package/dist/conversion/hub/process/chat-process-media.d.ts +3 -1
  33. package/dist/conversion/hub/process/chat-process-media.js +92 -2
  34. package/dist/conversion/hub/process/chat-process-session-usage.d.ts +7 -0
  35. package/dist/conversion/hub/process/chat-process-session-usage.js +147 -0
  36. package/dist/conversion/hub/response/provider-response.js +13 -0
  37. package/dist/conversion/responses/responses-openai-bridge/response-payload.js +0 -12
  38. package/dist/conversion/responses/responses-openai-bridge/types.d.ts +1 -9
  39. package/dist/conversion/responses/responses-openai-bridge.js +77 -44
  40. package/dist/conversion/shared/reasoning-normalizer.js +42 -0
  41. package/dist/conversion/shared/responses-tool-utils.js +2 -3
  42. package/dist/native/router_hotpath_napi.node +0 -0
  43. package/dist/router/virtual-router/bootstrap/profile-builder.js +1 -0
  44. package/dist/router/virtual-router/bootstrap/provider-normalization.d.ts +1 -0
  45. package/dist/router/virtual-router/bootstrap/provider-normalization.js +6 -0
  46. package/dist/router/virtual-router/bootstrap.js +1 -6
  47. package/dist/router/virtual-router/engine-legacy.js +43 -0
  48. package/dist/router/virtual-router/engine-logging.d.ts +3 -0
  49. package/dist/router/virtual-router/engine-logging.js +29 -3
  50. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-edge-stage-semantics.d.ts +2 -2
  51. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-edge-stage-semantics.js +96 -80
  52. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-req-process-semantics.d.ts +1 -0
  53. package/dist/router/virtual-router/engine.js +34 -22
  54. package/dist/router/virtual-router/provider-registry.js +1 -0
  55. package/dist/router/virtual-router/routing-instructions/state.js +35 -3
  56. package/dist/router/virtual-router/routing-instructions/types.d.ts +4 -0
  57. package/dist/router/virtual-router/types.d.ts +7 -0
  58. package/dist/servertool/engine.js +3 -34
  59. package/dist/servertool/handlers/followup-request-builder.js +0 -6
  60. package/dist/servertool/handlers/gemini-empty-reply-continue.js +3 -274
  61. package/dist/servertool/handlers/stop-message-auto/runtime-utils.d.ts +0 -3
  62. package/dist/servertool/handlers/stop-message-auto/runtime-utils.js +0 -29
  63. package/dist/servertool/handlers/stop-message-auto.js +2 -10
  64. package/dist/servertool/handlers/vision.js +4 -1
  65. package/dist/servertool/server-side-tools.js +66 -3
  66. package/package.json +1 -1
@@ -0,0 +1,178 @@
1
+ const truthy = new Set(['1', 'true', 'yes', 'on']);
2
+ const falsy = new Set(['0', 'false', 'no', 'off']);
3
+ const REQUEST_TIMELINES = new Map();
4
+ const REQUEST_TIMELINE_TTL_MS = 30 * 60 * 1000;
5
+ const REQUEST_TIMELINE_MAX = 4096;
6
+ const DEFAULT_HUB_STAGE_LOG_MIN_MS = 25;
7
+ function resolveBool(raw, fallback) {
8
+ if (raw === undefined) {
9
+ return fallback;
10
+ }
11
+ const normalized = String(raw).trim().toLowerCase();
12
+ if (truthy.has(normalized)) {
13
+ return true;
14
+ }
15
+ if (falsy.has(normalized)) {
16
+ return false;
17
+ }
18
+ return fallback;
19
+ }
20
+ function isHubStageTimingEnabled() {
21
+ const explicit = process.env.ROUTECODEX_STAGE_TIMING ??
22
+ process.env.RCC_STAGE_TIMING ??
23
+ process.env.ROUTECODEX_HUB_STAGE_TIMING ??
24
+ process.env.RCC_HUB_STAGE_TIMING ??
25
+ process.env.ROUTECODEX_BUILD_MODE ??
26
+ process.env.RCC_BUILD_MODE ??
27
+ process.env.BUILD_MODE ??
28
+ process.env.LLMSWITCH_BUILD_MODE;
29
+ if (explicit !== undefined) {
30
+ return resolveBool(explicit, true);
31
+ }
32
+ return true;
33
+ }
34
+ function isHubStageTimingVerboseEnabled() {
35
+ const explicit = process.env.ROUTECODEX_STAGE_TIMING_VERBOSE ??
36
+ process.env.RCC_STAGE_TIMING_VERBOSE ??
37
+ process.env.ROUTECODEX_HUB_STAGE_TIMING_VERBOSE ??
38
+ process.env.RCC_HUB_STAGE_TIMING_VERBOSE;
39
+ if (explicit !== undefined) {
40
+ return resolveBool(explicit, false);
41
+ }
42
+ return false;
43
+ }
44
+ function resolveHubStageTimingMinMs() {
45
+ const raw = process.env.ROUTECODEX_STAGE_TIMING_MIN_MS ??
46
+ process.env.RCC_STAGE_TIMING_MIN_MS ??
47
+ process.env.ROUTECODEX_HUB_STAGE_TIMING_MIN_MS ??
48
+ process.env.RCC_HUB_STAGE_TIMING_MIN_MS;
49
+ const parsed = Number(raw);
50
+ if (Number.isFinite(parsed) && parsed >= 0) {
51
+ return parsed;
52
+ }
53
+ return DEFAULT_HUB_STAGE_LOG_MIN_MS;
54
+ }
55
+ function prune(nowMs) {
56
+ for (const [key, timeline] of REQUEST_TIMELINES.entries()) {
57
+ if (nowMs - timeline.lastAtMs >= REQUEST_TIMELINE_TTL_MS) {
58
+ REQUEST_TIMELINES.delete(key);
59
+ }
60
+ }
61
+ while (REQUEST_TIMELINES.size > REQUEST_TIMELINE_MAX) {
62
+ const oldestKey = REQUEST_TIMELINES.keys().next().value;
63
+ if (!oldestKey) {
64
+ break;
65
+ }
66
+ REQUEST_TIMELINES.delete(oldestKey);
67
+ }
68
+ }
69
+ function touchTiming(requestId) {
70
+ const nowMs = Date.now();
71
+ prune(nowMs);
72
+ const existing = REQUEST_TIMELINES.get(requestId);
73
+ if (!existing) {
74
+ REQUEST_TIMELINES.set(requestId, {
75
+ startedAtMs: nowMs,
76
+ lastAtMs: nowMs
77
+ });
78
+ return;
79
+ }
80
+ existing.lastAtMs = nowMs;
81
+ }
82
+ function advanceTiming(requestId) {
83
+ const nowMs = Date.now();
84
+ prune(nowMs);
85
+ const existing = REQUEST_TIMELINES.get(requestId);
86
+ if (!existing) {
87
+ REQUEST_TIMELINES.set(requestId, {
88
+ startedAtMs: nowMs,
89
+ lastAtMs: nowMs
90
+ });
91
+ return {
92
+ label: ' t+0ms Δ0ms',
93
+ totalMs: 0,
94
+ deltaMs: 0
95
+ };
96
+ }
97
+ const totalMs = Math.max(0, Math.round(nowMs - existing.startedAtMs));
98
+ const deltaMs = Math.max(0, Math.round(nowMs - existing.lastAtMs));
99
+ existing.lastAtMs = nowMs;
100
+ return {
101
+ label: ` t+${totalMs}ms Δ${deltaMs}ms`,
102
+ totalMs,
103
+ deltaMs
104
+ };
105
+ }
106
+ function renderDetails(details) {
107
+ if (!details || Object.keys(details).length === 0) {
108
+ return '';
109
+ }
110
+ try {
111
+ return ` ${JSON.stringify(details)}`;
112
+ }
113
+ catch {
114
+ return '';
115
+ }
116
+ }
117
+ export function logHubStageTiming(requestId, stage, phase, details) {
118
+ if (!isHubStageTimingEnabled() || !requestId || !stage) {
119
+ return;
120
+ }
121
+ if (phase === 'start') {
122
+ touchTiming(requestId);
123
+ }
124
+ if (phase === 'start' && !isHubStageTimingVerboseEnabled()) {
125
+ return;
126
+ }
127
+ const timing = advanceTiming(requestId);
128
+ if (phase !== 'error') {
129
+ const forceLog = details?.forceLog === true;
130
+ if (forceLog) {
131
+ const detailSuffix = renderDetails(details);
132
+ const line = `[hub.detail][${requestId}] ${stage}.${phase}${timing.label}${detailSuffix}`;
133
+ console.log(line);
134
+ return;
135
+ }
136
+ const thresholdMs = resolveHubStageTimingMinMs();
137
+ const elapsedMs = typeof details?.elapsedMs === 'number'
138
+ ? details.elapsedMs
139
+ : typeof details?.nativeMs === 'number'
140
+ ? details.nativeMs
141
+ : undefined;
142
+ if (elapsedMs !== undefined && elapsedMs < thresholdMs) {
143
+ return;
144
+ }
145
+ if (timing.deltaMs < thresholdMs) {
146
+ return;
147
+ }
148
+ }
149
+ const detailSuffix = renderDetails(details);
150
+ const line = `[hub.detail][${requestId}] ${stage}.${phase}${timing.label}${detailSuffix}`;
151
+ if (phase === 'error') {
152
+ console.error(line);
153
+ return;
154
+ }
155
+ console.log(line);
156
+ }
157
+ export async function measureHubStage(requestId, stage, fn, options) {
158
+ const startedAt = Date.now();
159
+ logHubStageTiming(requestId, stage, 'start', options?.startDetails);
160
+ try {
161
+ const value = await fn();
162
+ const elapsedMs = Math.max(0, Date.now() - startedAt);
163
+ logHubStageTiming(requestId, stage, 'completed', {
164
+ elapsedMs,
165
+ ...(options?.mapCompletedDetails?.(value) ?? {})
166
+ });
167
+ return value;
168
+ }
169
+ catch (error) {
170
+ const mapped = options?.mapErrorDetails?.(error);
171
+ const message = error instanceof Error ? error.message : String(error ?? 'unknown');
172
+ logHubStageTiming(requestId, stage, 'error', mapped ?? {
173
+ elapsedMs: Math.max(0, Date.now() - startedAt),
174
+ message
175
+ });
176
+ throw error;
177
+ }
178
+ }
@@ -1,7 +1,7 @@
1
- import type { AdapterContext } from '../../../../types/chat-envelope.js';
2
- import type { FormatEnvelope } from '../../../../types/format-envelope.js';
3
- import type { JsonObject } from '../../../../types/json.js';
4
- import type { StageRecorder } from '../../../../format-adapters/index.js';
1
+ import type { AdapterContext } from "../../../../types/chat-envelope.js";
2
+ import type { FormatEnvelope } from "../../../../types/format-envelope.js";
3
+ import type { JsonObject } from "../../../../types/json.js";
4
+ import type { StageRecorder } from "../../../../format-adapters/index.js";
5
5
  export interface ReqInboundStage1FormatParseOptions {
6
6
  rawRequest: JsonObject;
7
7
  adapterContext: AdapterContext;
@@ -1,42 +1,61 @@
1
- import { recordStage } from '../../../stages/utils.js';
2
- import { sanitizeReqInboundFormatEnvelopeWithNative } from '../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.js';
3
- import { parseReqInboundFormatEnvelopeWithNative } from '../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-edge-stage-semantics.js';
4
- import { normalizeReasoningInAnthropicPayload, normalizeReasoningInChatPayload, normalizeReasoningInGeminiPayload, normalizeReasoningInResponsesPayload } from '../../../../../shared/reasoning-normalizer.js';
1
+ import { recordStage } from "../../../stages/utils.js";
2
+ import { sanitizeReqInboundFormatEnvelopeWithNative } from "../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.js";
3
+ import { parseReqInboundFormatEnvelopeWithNative } from "../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-edge-stage-semantics.js";
4
+ import { normalizeReasoningInAnthropicPayload, normalizeReasoningInChatPayload, normalizeReasoningInGeminiPayload, normalizeReasoningInResponsesPayload, } from "../../../../../shared/reasoning-normalizer.js";
5
+ import { logHubStageTiming } from "../../../hub-stage-timing.js";
5
6
  function resolveProtocolToken(adapterContext) {
6
- const candidate = typeof adapterContext.providerProtocol === 'string' && adapterContext.providerProtocol.trim().length
7
+ const candidate = typeof adapterContext.providerProtocol === "string" &&
8
+ adapterContext.providerProtocol.trim().length
7
9
  ? adapterContext.providerProtocol.trim().toLowerCase()
8
- : '';
9
- if (candidate === 'openai-chat' || candidate === 'openai-responses' || candidate === 'anthropic-messages' || candidate === 'gemini-chat') {
10
+ : "";
11
+ if (candidate === "openai-chat" ||
12
+ candidate === "openai-responses" ||
13
+ candidate === "anthropic-messages" ||
14
+ candidate === "gemini-chat") {
10
15
  return candidate;
11
16
  }
12
- return 'openai-chat';
17
+ return "openai-chat";
13
18
  }
14
19
  function applyReasoningNormalization(rawRequest, protocol) {
15
- if (protocol === 'openai-responses') {
20
+ if (protocol === "openai-responses") {
16
21
  normalizeReasoningInResponsesPayload(rawRequest, {
17
22
  includeInput: true,
18
- includeInstructions: true
23
+ includeInstructions: true,
19
24
  });
20
25
  return;
21
26
  }
22
- if (protocol === 'anthropic-messages') {
27
+ if (protocol === "anthropic-messages") {
23
28
  normalizeReasoningInAnthropicPayload(rawRequest);
24
29
  return;
25
30
  }
26
- if (protocol === 'gemini-chat') {
31
+ if (protocol === "gemini-chat") {
27
32
  normalizeReasoningInGeminiPayload(rawRequest);
28
33
  return;
29
34
  }
30
35
  normalizeReasoningInChatPayload(rawRequest);
31
36
  }
32
37
  export async function runReqInboundStage1FormatParse(options) {
38
+ const requestId = options.adapterContext.requestId || "unknown";
33
39
  const protocol = resolveProtocolToken(options.adapterContext);
40
+ logHubStageTiming(requestId, "req_inbound.stage1_reasoning_normalize", "start", { protocol });
41
+ const normalizeStart = Date.now();
34
42
  applyReasoningNormalization(options.rawRequest, protocol);
43
+ logHubStageTiming(requestId, "req_inbound.stage1_reasoning_normalize", "completed", { elapsedMs: Date.now() - normalizeStart, protocol });
44
+ logHubStageTiming(requestId, "req_inbound.stage1_native_parse", "start");
45
+ const parseStart = Date.now();
35
46
  const envelopeRaw = parseReqInboundFormatEnvelopeWithNative({
36
47
  rawRequest: options.rawRequest,
37
- protocol
48
+ protocol,
38
49
  });
50
+ logHubStageTiming(requestId, "req_inbound.stage1_native_parse", "completed", {
51
+ elapsedMs: Date.now() - parseStart,
52
+ });
53
+ logHubStageTiming(requestId, "req_inbound.stage1_sanitize", "start");
54
+ const sanitizeStart = Date.now();
39
55
  const envelope = sanitizeReqInboundFormatEnvelopeWithNative(envelopeRaw);
40
- recordStage(options.stageRecorder, 'chat_process.req.stage1.format_parse', envelope);
56
+ logHubStageTiming(requestId, "req_inbound.stage1_sanitize", "completed", {
57
+ elapsedMs: Date.now() - sanitizeStart,
58
+ });
59
+ recordStage(options.stageRecorder, "chat_process.req.stage1.format_parse", envelope);
41
60
  return envelope;
42
61
  }
@@ -1,12 +1,12 @@
1
- import type { AdapterContext, ChatEnvelope } from '../../../../types/chat-envelope.js';
2
- import type { FormatEnvelope } from '../../../../types/format-envelope.js';
3
- import { type JsonObject } from '../../../../types/json.js';
4
- import type { SemanticMapper, StageRecorder } from '../../../../format-adapters/index.js';
5
- import type { StandardizedRequest } from '../../../../types/standardized.js';
1
+ import type { AdapterContext, ChatEnvelope } from "../../../../types/chat-envelope.js";
2
+ import type { FormatEnvelope } from "../../../../types/format-envelope.js";
3
+ import { type JsonObject } from "../../../../types/json.js";
4
+ import type { SemanticMapper, StageRecorder } from "../../../../format-adapters/index.js";
5
+ import type { StandardizedRequest } from "../../../../types/standardized.js";
6
6
  export interface ReqInboundStage2SemanticMapOptions {
7
7
  adapterContext: AdapterContext;
8
8
  formatEnvelope: FormatEnvelope<JsonObject>;
9
- semanticMapper: Pick<SemanticMapper, 'toChat'>;
9
+ semanticMapper: Pick<SemanticMapper, "toChat">;
10
10
  /**
11
11
  * Mappable cross-protocol semantics (e.g. /v1/responses submit resume) must be
12
12
  * lifted into chat semantics before entering chat_process.
@@ -19,5 +19,6 @@ export interface ReqInboundStage2SemanticMapOptions {
19
19
  export interface ReqInboundStage2SemanticMapResult {
20
20
  chatEnvelope: ChatEnvelope;
21
21
  standardizedRequest: StandardizedRequest;
22
+ responsesContext?: JsonObject;
22
23
  }
23
24
  export declare function runReqInboundStage2SemanticMap(options: ReqInboundStage2SemanticMapOptions): Promise<ReqInboundStage2SemanticMapResult>;
@@ -1,13 +1,18 @@
1
- import { isJsonObject, jsonClone } from '../../../../types/json.js';
2
- import { applyHubOperationTableInbound } from '../../../../operation-table/operation-table-runner.js';
3
- import { recordStage } from '../../../stages/utils.js';
4
- import { liftReqInboundSemantics } from './semantic-lift.js';
5
- import { validateChatEnvelopeWithNative } from '../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-edge-stage-semantics.js';
6
- import { chatEnvelopeToStandardizedWithNative } from '../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.js';
1
+ import { isJsonObject, jsonClone, } from "../../../../types/json.js";
2
+ import { applyHubOperationTableInbound } from "../../../../operation-table/operation-table-runner.js";
3
+ import { recordStage } from "../../../stages/utils.js";
4
+ import { liftReqInboundSemantics } from "./semantic-lift.js";
5
+ import { validateChatEnvelopeWithNative } from "../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-edge-stage-semantics.js";
6
+ import { chatEnvelopeToStandardizedWithNative } from "../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.js";
7
+ import { logHubStageTiming } from "../../../hub-stage-timing.js";
7
8
  export async function runReqInboundStage2SemanticMap(options) {
9
+ const requestId = options.adapterContext.requestId || "unknown";
10
+ logHubStageTiming(requestId, "req_inbound.stage2_semantic_mapper_toChat", "start");
11
+ const toChatStart = Date.now();
8
12
  const chatEnvelope = await options.semanticMapper.toChat(options.formatEnvelope, options.adapterContext);
13
+ logHubStageTiming(requestId, "req_inbound.stage2_semantic_mapper_toChat", "completed", { elapsedMs: Date.now() - toChatStart });
9
14
  const preservedResponsesContext = (() => {
10
- if (!chatEnvelope.semantics || typeof chatEnvelope.semantics !== 'object') {
15
+ if (!chatEnvelope.semantics || typeof chatEnvelope.semantics !== "object") {
11
16
  return undefined;
12
17
  }
13
18
  const semantics = chatEnvelope.semantics;
@@ -22,7 +27,7 @@ export async function runReqInboundStage2SemanticMap(options) {
22
27
  applyHubOperationTableInbound({
23
28
  formatEnvelope: options.formatEnvelope,
24
29
  chatEnvelope,
25
- adapterContext: options.adapterContext
30
+ adapterContext: options.adapterContext,
26
31
  });
27
32
  // Semantic Gate (request): before entering chat_process, lift any mappable protocol semantics
28
33
  // into ChatEnvelope.semantics. Do not persist these in metadata.
@@ -30,12 +35,14 @@ export async function runReqInboundStage2SemanticMap(options) {
30
35
  chatEnvelope,
31
36
  formatEnvelope: options.formatEnvelope,
32
37
  adapterContext: options.adapterContext,
33
- responsesResume: options.responsesResume
38
+ responsesResume: options.responsesResume,
34
39
  });
35
40
  if (preservedResponsesContext) {
36
41
  const currentSemantics = chatEnvelope.semantics;
37
- if (!currentSemantics || typeof currentSemantics !== 'object') {
38
- chatEnvelope.semantics = { responses: { context: jsonClone(preservedResponsesContext) } };
42
+ if (!currentSemantics || typeof currentSemantics !== "object") {
43
+ chatEnvelope.semantics = {
44
+ responses: { context: jsonClone(preservedResponsesContext) },
45
+ };
39
46
  }
40
47
  else {
41
48
  const semantics = currentSemantics;
@@ -47,28 +54,31 @@ export async function runReqInboundStage2SemanticMap(options) {
47
54
  ...semantics,
48
55
  responses: {
49
56
  ...responsesNode,
50
- context: jsonClone(preservedResponsesContext)
51
- }
57
+ context: jsonClone(preservedResponsesContext),
58
+ },
52
59
  };
53
60
  }
54
61
  }
55
62
  }
56
63
  validateChatEnvelopeWithNative(chatEnvelope, {
57
- stage: 'req_inbound',
58
- direction: 'request'
64
+ stage: "req_inbound",
65
+ direction: "request",
59
66
  });
60
- recordStage(options.stageRecorder, 'chat_process.req.stage2.semantic_map', chatEnvelope);
67
+ recordStage(options.stageRecorder, "chat_process.req.stage2.semantic_map", chatEnvelope);
68
+ logHubStageTiming(requestId, "req_inbound.stage2_to_standardized", "start");
69
+ const stdStart = Date.now();
61
70
  const standardizedRequest = chatEnvelopeToStandardizedWithNative({
62
71
  chatEnvelope: chatEnvelope,
63
72
  adapterContext: options.adapterContext,
64
73
  endpoint: options.adapterContext.entryEndpoint,
65
- requestId: options.adapterContext.requestId
74
+ requestId: options.adapterContext.requestId,
66
75
  });
76
+ logHubStageTiming(requestId, "req_inbound.stage2_to_standardized", "completed", { elapsedMs: Date.now() - stdStart });
67
77
  // Ensure responses semantics (context) survive into standardized request for VirtualRouter parsing.
68
- if (chatEnvelope.semantics && typeof chatEnvelope.semantics === 'object') {
78
+ if (chatEnvelope.semantics && typeof chatEnvelope.semantics === "object") {
69
79
  const envelopeSemantics = chatEnvelope.semantics;
70
80
  const existing = standardizedRequest.semantics;
71
- if (!existing || typeof existing !== 'object') {
81
+ if (!existing || typeof existing !== "object") {
72
82
  standardizedRequest.semantics = jsonClone(envelopeSemantics);
73
83
  }
74
84
  else {
@@ -81,15 +91,23 @@ export async function runReqInboundStage2SemanticMap(options) {
81
91
  : undefined;
82
92
  if (envelopeContext) {
83
93
  const nextResponses = {
84
- ...(isJsonObject(existingObj.responses) ? existingObj.responses : {}),
85
- context: jsonClone(envelopeContext)
94
+ ...(isJsonObject(existingObj.responses)
95
+ ? existingObj.responses
96
+ : {}),
97
+ context: jsonClone(envelopeContext),
86
98
  };
87
99
  standardizedRequest.semantics = {
88
100
  ...existingObj,
89
- responses: nextResponses
101
+ responses: nextResponses,
90
102
  };
91
103
  }
92
104
  }
93
105
  }
94
- return { chatEnvelope, standardizedRequest };
106
+ return {
107
+ chatEnvelope,
108
+ standardizedRequest,
109
+ ...(preservedResponsesContext
110
+ ? { responsesContext: preservedResponsesContext }
111
+ : {}),
112
+ };
95
113
  }
@@ -3,33 +3,76 @@ import { recordStage } from '../../../stages/utils.js';
3
3
  import { applyContextSnapshotToChatEnvelope, applyToolCallIdStyleMetadata } from './context-merge.js';
4
4
  import { shouldAttachReqOutboundContextSnapshotWithNative, standardizedToChatEnvelopeWithNative } from '../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-req-outbound-semantics.js';
5
5
  import { validateChatEnvelopeWithNative } from '../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-edge-stage-semantics.js';
6
+ import { logHubStageTiming } from '../../../hub-stage-timing.js';
6
7
  export async function runReqOutboundStage1SemanticMap(options) {
8
+ const requestId = options.adapterContext.requestId || 'unknown';
9
+ const forceDetailLog = String(process.env.ROUTECODEX_HUB_STAGE_TIMING_DETAIL || '')
10
+ .trim()
11
+ .toLowerCase() === '1';
12
+ logHubStageTiming(requestId, 'req_outbound.stage1_native_to_chat_envelope', 'start');
13
+ const toChatStart = Date.now();
7
14
  const chatEnvelope = standardizedToChatEnvelopeWithNative({
8
15
  request: options.request,
9
16
  adapterContext: options.adapterContext
10
17
  });
18
+ logHubStageTiming(requestId, 'req_outbound.stage1_native_to_chat_envelope', 'completed', {
19
+ elapsedMs: Date.now() - toChatStart,
20
+ forceLog: forceDetailLog
21
+ });
11
22
  applyToolCallIdStyleMetadata(chatEnvelope, options.adapterContext, options.contextSnapshot);
12
23
  const shouldAttachContextSnapshot = shouldAttachReqOutboundContextSnapshotWithNative(Boolean(options.contextSnapshot), options.contextMetadataKey);
13
24
  if (shouldAttachContextSnapshot && options.contextSnapshot && options.contextMetadataKey) {
25
+ logHubStageTiming(requestId, 'req_outbound.stage1_context_merge', 'start');
26
+ const contextMergeStart = Date.now();
14
27
  const snapshot = options.contextSnapshot;
15
- chatEnvelope.metadata[options.contextMetadataKey] = snapshot;
28
+ if (options.contextMetadataKey !== 'responsesContext') {
29
+ chatEnvelope.metadata[options.contextMetadataKey] = snapshot;
30
+ }
16
31
  applyContextSnapshotToChatEnvelope(chatEnvelope, snapshot);
32
+ logHubStageTiming(requestId, 'req_outbound.stage1_context_merge', 'completed', {
33
+ elapsedMs: Date.now() - contextMergeStart,
34
+ forceLog: forceDetailLog
35
+ });
17
36
  }
37
+ logHubStageTiming(requestId, 'req_outbound.stage1_validate_chat_envelope', 'start');
38
+ const validateStart = Date.now();
18
39
  validateChatEnvelopeWithNative(chatEnvelope, {
19
40
  stage: 'req_outbound',
20
41
  direction: 'request'
21
42
  });
43
+ logHubStageTiming(requestId, 'req_outbound.stage1_validate_chat_envelope', 'completed', {
44
+ elapsedMs: Date.now() - validateStart,
45
+ forceLog: forceDetailLog
46
+ });
47
+ logHubStageTiming(requestId, 'req_outbound.stage1_operation_table_pre_map', 'start');
48
+ const preMapStart = Date.now();
22
49
  await applyHubOperationTableOutboundPreMap({
23
50
  protocol: options.adapterContext.providerProtocol,
24
51
  chatEnvelope,
25
52
  adapterContext: options.adapterContext
26
53
  });
54
+ logHubStageTiming(requestId, 'req_outbound.stage1_operation_table_pre_map', 'completed', {
55
+ elapsedMs: Date.now() - preMapStart,
56
+ forceLog: forceDetailLog
57
+ });
58
+ logHubStageTiming(requestId, 'req_outbound.stage1_mapper_from_chat', 'start');
59
+ const fromChatStart = Date.now();
27
60
  const formatEnvelope = (await options.semanticMapper.fromChat(chatEnvelope, options.adapterContext));
61
+ logHubStageTiming(requestId, 'req_outbound.stage1_mapper_from_chat', 'completed', {
62
+ elapsedMs: Date.now() - fromChatStart,
63
+ forceLog: forceDetailLog
64
+ });
65
+ logHubStageTiming(requestId, 'req_outbound.stage1_operation_table_post_map', 'start');
66
+ const postMapStart = Date.now();
28
67
  applyHubOperationTableOutboundPostMap({
29
68
  chatEnvelope,
30
69
  formatEnvelope,
31
70
  adapterContext: options.adapterContext
32
71
  });
72
+ logHubStageTiming(requestId, 'req_outbound.stage1_operation_table_post_map', 'completed', {
73
+ elapsedMs: Date.now() - postMapStart,
74
+ forceLog: forceDetailLog
75
+ });
33
76
  recordStage(options.stageRecorder, 'chat_process.req.stage6.outbound.semantic_map', chatEnvelope);
34
77
  return { chatEnvelope, formatEnvelope };
35
78
  }
@@ -2,6 +2,7 @@ import { recordStage } from '../../../stages/utils.js';
2
2
  import { captureApplyPatchExecutionFailuresFromProcessedRequest } from '../../../../../../tools/apply-patch/execution-capturer.js';
3
3
  import { applyReqProcessToolGovernanceWithNative } from '../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-req-process-semantics.js';
4
4
  import { maybeInjectClockRemindersAndApplyDirectives } from '../../../../process/chat-process-clock-reminders.js';
5
+ import { resolveHasActiveStopMessageForContinueExecution } from '../../../../process/chat-process-continue-execution.js';
5
6
  function isRecord(value) {
6
7
  return !!value && typeof value === 'object' && !Array.isArray(value);
7
8
  }
@@ -28,12 +29,14 @@ function parseNodeResult(value) {
28
29
  return value;
29
30
  }
30
31
  export async function runReqProcessStage1ToolGovernance(options) {
32
+ const hasActiveStopMessageForContinueExecution = resolveHasActiveStopMessageForContinueExecution(options.metadata);
31
33
  const nativeResult = applyReqProcessToolGovernanceWithNative({
32
34
  request: options.request,
33
35
  rawPayload: options.rawPayload,
34
36
  metadata: options.metadata,
35
37
  entryEndpoint: options.entryEndpoint,
36
- requestId: options.requestId
38
+ requestId: options.requestId,
39
+ hasActiveStopMessageForContinueExecution
37
40
  });
38
41
  let processedRequest = parseProcessedRequest(nativeResult.processedRequest);
39
42
  const nodeResult = parseNodeResult(nativeResult.nodeResult);
@@ -1,7 +1,7 @@
1
1
  import { readRuntimeMetadata } from '../../runtime-metadata.js';
2
2
  import { loadRoutingInstructionStateSync } from '../../../router/virtual-router/sticky-session-store.js';
3
3
  import { logContinueExecution } from '../../../servertool/continue-execution/log.js';
4
- import { buildContinueExecutionOperationsWithNative, injectContinueExecutionDirectiveWithNative, planContinueExecutionOperationsWithNative, resolveHasActiveStopMessageForContinueExecutionWithNative, resolveStopMessageSessionScopeWithNative } from '../../../router/virtual-router/engine-selection/native-chat-process-servertool-orchestration-semantics.js';
4
+ import { buildContinueExecutionOperationsWithNative, injectContinueExecutionDirectiveWithNative, planContinueExecutionOperationsWithNative, isStopMessageStateActiveWithNative, resolveStopMessageSessionScopeWithNative } from '../../../router/virtual-router/engine-selection/native-chat-process-servertool-orchestration-semantics.js';
5
5
  import { isClientInjectReady } from './client-inject-readiness.js';
6
6
  const CONTINUE_EXECUTION_INJECTION_MARKER = '[routecodex:continue_execution_injection]';
7
7
  const CONTINUE_EXECUTION_INJECTION_TEXT = '继续执行';
@@ -59,10 +59,11 @@ export function injectContinueExecutionDirectiveIntoUserMessage(request, metadat
59
59
  };
60
60
  }
61
61
  function hasActiveStopMessageStateForContinueExecution(metadata) {
62
- const rt = (readRuntimeMetadata(metadata) ?? {});
63
- const runtimeState = rt?.stopMessageState;
62
+ if (!isClientInjectReady(metadata)) {
63
+ return false;
64
+ }
64
65
  const persistedState = resolvePersistedStopMessageState(metadata);
65
- return resolveHasActiveStopMessageForContinueExecutionWithNative(runtimeState, persistedState);
66
+ return isStopMessageStateActiveWithNative(persistedState);
66
67
  }
67
68
  export function resolveHasActiveStopMessageForContinueExecution(metadata) {
68
69
  return hasActiveStopMessageStateForContinueExecution(metadata);
@@ -1,6 +1,7 @@
1
1
  import { applyReqProcessToolGovernanceWithNative } from '../../../router/virtual-router/engine-selection/native-hub-pipeline-req-process-semantics.js';
2
2
  import { maybeInjectClockRemindersAndApplyDirectives } from './chat-process-clock-reminders.js';
3
3
  import { finalizeGovernedRequest } from './chat-process-governance-finalize.js';
4
+ import { resolveHasActiveStopMessageForContinueExecution } from './chat-process-continue-execution.js';
4
5
  function isRecord(value) {
5
6
  return !!value && typeof value === 'object' && !Array.isArray(value);
6
7
  }
@@ -32,7 +33,8 @@ export async function applyRequestToolGovernance(request, context, governanceEng
32
33
  rawPayload: context.rawPayload ?? request,
33
34
  metadata: context.metadata,
34
35
  entryEndpoint: context.entryEndpoint,
35
- requestId: context.requestId
36
+ requestId: context.requestId,
37
+ hasActiveStopMessageForContinueExecution: resolveHasActiveStopMessageForContinueExecution(context.metadata)
36
38
  });
37
39
  const governedRequest = parseGovernedRequest(nativeResult.processedRequest);
38
40
  const requestAfterInject = await maybeInjectClockRemindersAndApplyDirectives(governedRequest, context.metadata, context.requestId);
@@ -1,3 +1,5 @@
1
- import type { StandardizedMessage } from '../types/standardized.js';
1
+ import type { StandardizedMessage } from "../types/standardized.js";
2
2
  export declare function stripHistoricalImageAttachments(messages: StandardizedMessage[]): StandardizedMessage[];
3
+ export declare function stripHistoricalVisualToolOutputs(messages: StandardizedMessage[]): StandardizedMessage[];
3
4
  export declare function containsImageAttachment(messages: StandardizedMessage[]): boolean;
5
+ export declare function repairIncompleteToolCalls(messages: StandardizedMessage[]): StandardizedMessage[];