@jsonstudio/llms 0.6.3685 → 0.6.3688

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 (65) hide show
  1. package/dist/conversion/compat/actions/antigravity-thought-signature-cache.js +2 -22
  2. package/dist/conversion/compat/actions/deepseek-web-response.js +7 -0
  3. package/dist/conversion/compat/actions/field-mapping.js +153 -2
  4. package/dist/conversion/compat/actions/lmstudio-responses-input-stringify.js +104 -3
  5. package/dist/conversion/hub/node-support.js +1 -1
  6. package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +1 -9
  7. package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +28 -35
  8. package/dist/conversion/hub/pipeline/hub-pipeline.js +121 -197
  9. package/dist/conversion/hub/pipeline/hub-stage-timing.d.ts +1 -0
  10. package/dist/conversion/hub/pipeline/hub-stage-timing.js +14 -8
  11. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.d.ts +4 -4
  12. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.js +37 -20
  13. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +7 -6
  14. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +41 -69
  15. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/context-capture-orchestration.d.ts +0 -3
  16. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/context-capture-orchestration.js +1 -2
  17. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/context-factories.js +0 -2
  18. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +0 -1
  19. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/responses-context-snapshot.d.ts +2 -3
  20. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/responses-context-snapshot.js +5 -18
  21. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/context-merge.d.ts +2 -1
  22. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/context-merge.js +16 -0
  23. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.d.ts +1 -1
  24. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +50 -27
  25. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.d.ts +0 -1
  26. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.js +1 -1
  27. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.d.ts +1 -1
  28. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.js +5 -9
  29. package/dist/conversion/hub/process/chat-process-continue-execution.js +3 -0
  30. package/dist/conversion/hub/process/chat-process-media.d.ts +2 -1
  31. package/dist/conversion/hub/process/chat-process-media.js +63 -9
  32. package/dist/conversion/hub/process/chat-process-session-usage.d.ts +6 -24
  33. package/dist/conversion/hub/process/chat-process-session-usage.js +101 -200
  34. package/dist/conversion/hub/response/provider-response.js +13 -13
  35. package/dist/conversion/hub/types/chat-envelope.d.ts +0 -1
  36. package/dist/conversion/pipeline/codecs/v2/openai-openai-pipeline.js +4 -0
  37. package/dist/conversion/responses/responses-openai-bridge.d.ts +0 -1
  38. package/dist/conversion/responses/responses-openai-bridge.js +34 -28
  39. package/dist/conversion/shared/anthropic-message-utils.js +1 -14
  40. package/dist/conversion/shared/reasoning-normalizer.js +22 -41
  41. package/dist/conversion/shared/responses-tool-utils.js +2 -3
  42. package/dist/conversion/shared/tool-governor.js +4 -2
  43. package/dist/native/router_hotpath_napi.node +0 -0
  44. package/dist/router/virtual-router/engine/routing-state/store.js +2 -21
  45. package/dist/router/virtual-router/engine-selection/native-chat-process-governed-filter-semantics.d.ts +0 -1
  46. package/dist/router/virtual-router/engine-selection/native-chat-process-governed-filter-semantics.js +0 -1
  47. package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.d.ts +0 -3
  48. package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.js +0 -72
  49. package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.d.ts +1 -1
  50. package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js +1 -1
  51. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-edge-stage-semantics.d.ts +2 -2
  52. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-edge-stage-semantics.js +96 -80
  53. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-inbound-outbound-semantics.d.ts +1 -0
  54. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-inbound-outbound-semantics.js +29 -0
  55. package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +2 -6
  56. package/dist/router/virtual-router/engine.js +6 -9
  57. package/dist/router/virtual-router/routing-instructions/state.js +27 -37
  58. package/dist/router/virtual-router/routing-instructions/types.d.ts +4 -6
  59. package/dist/router/virtual-router/token-estimator.js +0 -21
  60. package/dist/servertool/handlers/stop-message-auto.js +1 -11
  61. package/dist/tools/apply-patch/execution-capturer.d.ts +1 -1
  62. package/dist/tools/apply-patch/execution-capturer.js +2 -1
  63. package/dist/tools/apply-patch/regression-capturer.js +1 -2
  64. package/dist/tools/tool-registry.js +2 -1
  65. package/package.json +1 -1
@@ -15,7 +15,6 @@ import { ChatFormatAdapter } from "../format-adapters/chat-format-adapter.js";
15
15
  import { ChatSemanticMapper } from "../semantic-mappers/chat-mapper.js";
16
16
  import { createSnapshotRecorder } from "../snapshot-recorder.js";
17
17
  import { shouldRecordSnapshots } from "../../snapshot-utils.js";
18
- import { measureHubStage } from "./hub-stage-timing.js";
19
18
  import { runReqInboundStage1FormatParse } from "./stages/req_inbound/req_inbound_stage1_format_parse/index.js";
20
19
  import { runReqInboundStage2SemanticMap } from "./stages/req_inbound/req_inbound_stage2_semantic_map/index.js";
21
20
  import { runChatContextCapture, captureResponsesContextSnapshot, } from "./stages/req_inbound/req_inbound_stage3_context_capture/index.js";
@@ -28,14 +27,15 @@ import { runReqOutboundStage2FormatBuild } from "./stages/req_outbound/req_outbo
28
27
  import { runReqOutboundStage3Compat } from "./stages/req_outbound/req_outbound_stage3_compat/index.js";
29
28
  import { extractSessionIdentifiersFromMetadata } from "./session-identifiers.js";
30
29
  import { computeRequestTokens } from "../../../router/virtual-router/token-estimator.js";
30
+ import { estimateSessionBoundTokens } from "../process/chat-process-session-usage.js";
31
31
  import { annotatePassthroughGovernanceSkipWithNative, attachPassthroughProviderInputAuditWithNative, buildPassthroughAuditWithNative, applyOutboundStreamPreferenceWithNative, normalizeHubEndpointWithNative, extractAdapterContextMetadataFieldsWithNative, resolveApplyPatchToolModeFromToolsWithNative, resolveHubClientProtocolWithNative, resolveHubPolicyOverrideFromMetadataWithNative, resolveHubProviderProtocolWithNative, resolveOutboundStreamIntentWithNative, resolveHubShadowCompareConfigWithNative, resolveActiveProcessModeWithNative, findMappableSemanticsKeysWithNative, resolveHubSseProtocolFromMetadataWithNative, resolveStopMessageRouterMetadataWithNative, runHubPipelineOrchestrationWithNative, } from "../../../router/virtual-router/engine-selection/native-hub-pipeline-orchestration-semantics.js";
32
32
  import { normalizeAliasMapWithNative, resolveAliasMapFromRespSemanticsWithNative, } from "../../../router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js";
33
33
  import { isCompactionRequest } from "../../compaction-detect.js";
34
34
  import { applyHubProviderOutboundPolicy, recordHubPolicyObservation, setHubPolicyRuntimePolicy, } from "../policy/policy-engine.js";
35
35
  import { applyProviderOutboundToolSurface, } from "../tool-surface/tool-surface-engine.js";
36
36
  import { cloneRuntimeMetadata, ensureRuntimeMetadata, readRuntimeMetadata, } from "../../runtime-metadata.js";
37
- import { containsImageAttachment, stripHistoricalImageAttachments, stripHistoricalVisualToolOutputs, } from "../process/chat-process-media.js";
38
- import { estimateChatProcessSessionInputTokensDetailed, saveChatProcessSessionInputEstimate, } from "../process/chat-process-session-usage.js";
37
+ import { containsImageAttachment, stripHistoricalImageAttachments, stripHistoricalVisualToolOutputs, repairIncompleteToolCalls, } from "../process/chat-process-media.js";
38
+ import { measureHubStage, logHubStageTiming } from "./hub-stage-timing.js";
39
39
  function isTruthyEnv(value) {
40
40
  const v = typeof value === "string" ? value.trim().toLowerCase() : "";
41
41
  return v === "1" || v === "true" || v === "yes" || v === "on";
@@ -59,7 +59,7 @@ function resolveApplyPatchToolModeFromEnv() {
59
59
  function applyChatProcessEntryMediaCleanup(request) {
60
60
  return {
61
61
  ...request,
62
- messages: stripHistoricalVisualToolOutputs(stripHistoricalImageAttachments(request.messages)),
62
+ messages: repairIncompleteToolCalls(stripHistoricalVisualToolOutputs(stripHistoricalImageAttachments(request.messages))),
63
63
  };
64
64
  }
65
65
  function readResponsesResumeFromMetadata(metadata) {
@@ -410,6 +410,23 @@ export class HubPipeline {
410
410
  async executeRequestStagePipeline(normalized, hooks) {
411
411
  const semanticMapper = hooks.createSemanticMapper();
412
412
  const rawRequest = this.asJsonObject(normalized.payload);
413
+ // Detect applyPatchToolMode (runtime/tooling hint). Client tool schemas are captured as chat semantics
414
+ // in req_inbound_stage2_semantic_map; they must not be stored in metadata.
415
+ try {
416
+ const toolsRaw = Array.isArray(rawRequest?.tools)
417
+ ? rawRequest.tools
418
+ : null;
419
+ const applyPatchToolMode = resolveApplyPatchToolModeFromEnv() ??
420
+ resolveApplyPatchToolModeFromTools(toolsRaw);
421
+ if (applyPatchToolMode) {
422
+ normalized.metadata = normalized.metadata || {};
423
+ const rt = ensureRuntimeMetadata(normalized.metadata);
424
+ rt.applyPatchToolMode = applyPatchToolMode;
425
+ }
426
+ }
427
+ catch {
428
+ // best-effort: do not block request handling due to tool scan failures
429
+ }
413
430
  if (isCompactionRequest(rawRequest)) {
414
431
  normalized.metadata = normalized.metadata || {};
415
432
  const rt = ensureRuntimeMetadata(normalized.metadata);
@@ -431,13 +448,13 @@ export class HubPipeline {
431
448
  stageRecorder: inboundRecorder,
432
449
  requestId: normalized.id,
433
450
  });
434
- const formatEnvelope = await measureHubStage(normalized.id, "request_stage.req_inbound.format_parse", () => runReqInboundStage1FormatParse({
451
+ const formatEnvelope = await measureHubStage(normalized.id, "req_inbound.stage1_format_parse", () => runReqInboundStage1FormatParse({
435
452
  rawRequest,
436
453
  adapterContext: inboundAdapterContext,
437
454
  stageRecorder: inboundRecorder,
438
455
  }));
439
456
  const responsesResumeFromMetadata = readResponsesResumeFromMetadata(normalized.metadata);
440
- const inboundStage2 = await measureHubStage(normalized.id, "request_stage.req_inbound.semantic_map", () => runReqInboundStage2SemanticMap({
457
+ const inboundStage2 = await measureHubStage(normalized.id, "req_inbound.stage2_semantic_map", () => runReqInboundStage2SemanticMap({
441
458
  adapterContext: inboundAdapterContext,
442
459
  formatEnvelope,
443
460
  semanticMapper,
@@ -452,13 +469,29 @@ export class HubPipeline {
452
469
  Object.prototype.hasOwnProperty.call(normalized.metadata, "responsesResume")) {
453
470
  delete normalized.metadata.responsesResume;
454
471
  }
455
- const contextSnapshot = await measureHubStage(normalized.id, "request_stage.req_inbound.context_capture", () => hooks.captureContext({
456
- rawRequest,
457
- adapterContext: inboundAdapterContext,
458
- chatEnvelope: inboundStage2.chatEnvelope,
459
- stageRecorder: inboundRecorder,
460
- }));
472
+ const contextSnapshot = await measureHubStage(normalized.id, "req_inbound.stage3_context_capture", () => {
473
+ if (inboundStage2.responsesContext) {
474
+ return inboundStage2.responsesContext;
475
+ }
476
+ return hooks.captureContext({
477
+ rawRequest,
478
+ adapterContext: inboundAdapterContext,
479
+ stageRecorder: inboundRecorder,
480
+ });
481
+ });
461
482
  let standardizedRequest = applyChatProcessEntryMediaCleanup(inboundStage2.standardizedRequest);
483
+ try {
484
+ const rt = readRuntimeMetadata(normalized.metadata);
485
+ const mode = String(rt?.applyPatchToolMode || "")
486
+ .trim()
487
+ .toLowerCase();
488
+ if (mode === "freeform" || mode === "schema") {
489
+ standardizedRequest.metadata.applyPatchToolMode = mode;
490
+ }
491
+ }
492
+ catch {
493
+ // best-effort: do not block request handling due to metadata propagation failures
494
+ }
462
495
  const activeProcessMode = resolveActiveProcessMode(normalized.processMode, standardizedRequest.messages);
463
496
  if (activeProcessMode !== normalized.processMode) {
464
497
  normalized.processMode = activeProcessMode;
@@ -504,13 +537,12 @@ export class HubPipeline {
504
537
  let processedRequest;
505
538
  if (activeProcessMode !== "passthrough") {
506
539
  assertNoMappableSemanticsInMetadata(metaBase, "chat_process.request.entry");
507
- const processResult = await measureHubStage(normalized.id, "request_stage.req_process.tool_governance", () => runReqProcessStage1ToolGovernance({
540
+ const processResult = await measureHubStage(normalized.id, "req_process.stage1_tool_governance", () => runReqProcessStage1ToolGovernance({
508
541
  request: standardizedRequest,
509
542
  rawPayload: rawRequest,
510
543
  metadata: metaBase,
511
544
  entryEndpoint: normalized.entryEndpoint,
512
545
  requestId: normalized.id,
513
- applyPatchToolMode: normalized.applyPatchToolMode,
514
546
  stageRecorder: inboundRecorder,
515
547
  }));
516
548
  processedRequest = processResult.processedRequest;
@@ -546,58 +578,16 @@ export class HubPipeline {
546
578
  }
547
579
  }
548
580
  let workingRequest = syncResponsesContextFromCanonicalMessages(processedRequest ?? standardizedRequest);
549
- const sessionIdentifiers = extractSessionIdentifiersFromMetadata(normalized.metadata);
550
- if (sessionIdentifiers.sessionId &&
551
- normalized.metadata &&
552
- typeof normalized.metadata === "object") {
553
- normalized.metadata.sessionId =
554
- sessionIdentifiers.sessionId;
555
- }
556
- if (sessionIdentifiers.conversationId &&
557
- normalized.metadata &&
558
- typeof normalized.metadata === "object") {
559
- normalized.metadata.conversationId =
560
- sessionIdentifiers.conversationId;
561
- }
562
581
  // 使用与 VirtualRouter 一致的 tiktoken 计数逻辑,对标准化请求进行一次
563
582
  // 上下文 token 估算,供后续 usage 归一化与统计使用。
564
583
  try {
565
- const sessionEstimate = await measureHubStage(normalized.id, "request_stage.req_process.token_estimate.session_delta", () => estimateChatProcessSessionInputTokensDetailed({
566
- sessionId: sessionIdentifiers.sessionId,
567
- conversationId: sessionIdentifiers.conversationId,
568
- }, workingRequest), {
569
- mapCompletedDetails: (value) => ({
570
- forceLog: value.mode === "unavailable" ||
571
- value.mode === "session_reuse" ||
572
- value.mode === "session_delta",
573
- scope: value.scope,
574
- mode: value.mode,
575
- reason: value.reason,
576
- previousMessageCount: value.previousMessageCount,
577
- appendedMessageCount: value.appendedMessageCount,
578
- hasPreviousTokens: value.hasPreviousTokens,
579
- hasPreviousMessageCount: value.hasPreviousMessageCount,
580
- hasToolsSignature: value.hasToolsSignature,
581
- hasParametersSignature: value.hasParametersSignature,
582
- previousParametersSignatureDigest: value.previousParametersSignatureDigest,
583
- currentParametersSignatureDigest: value.currentParametersSignatureDigest,
584
- }),
585
- });
586
- const estimatedTokens = typeof sessionEstimate.tokens === "number" &&
587
- Number.isFinite(sessionEstimate.tokens) &&
588
- sessionEstimate.tokens > 0
589
- ? sessionEstimate.tokens
590
- : await measureHubStage(normalized.id, "request_stage.req_process.token_estimate.full_count", () => computeRequestTokens(workingRequest, ""));
584
+ const estimatedTokens = estimateSessionBoundTokens(workingRequest, normalized.metadata) ?? computeRequestTokens(workingRequest, "");
591
585
  if (typeof estimatedTokens === "number" &&
592
586
  Number.isFinite(estimatedTokens) &&
593
587
  estimatedTokens > 0) {
594
588
  normalized.metadata = normalized.metadata || {};
595
589
  normalized.metadata.estimatedInputTokens =
596
590
  estimatedTokens;
597
- saveChatProcessSessionInputEstimate({
598
- sessionId: sessionIdentifiers.sessionId,
599
- conversationId: sessionIdentifiers.conversationId,
600
- }, workingRequest, estimatedTokens);
601
591
  }
602
592
  }
603
593
  catch {
@@ -611,6 +601,22 @@ export class HubPipeline {
611
601
  const hasImageAttachment = containsImageAttachment((workingRequest.messages ?? []));
612
602
  const serverToolRequired = stdMetadata?.webSearchEnabled === true ||
613
603
  stdMetadata?.serverToolRequired === true;
604
+ const sessionIdentifiers = extractSessionIdentifiersFromMetadata(normalized.metadata);
605
+ // 将从 metadata / clientHeaders 中解析出的会话标识同步回 normalized.metadata,
606
+ // 便于后续 AdapterContext(响应侧 servertool)也能访问到相同的 sessionId /
607
+ // conversationId,用于 sticky-session 相关逻辑(例如 stopMessage)。
608
+ if (sessionIdentifiers.sessionId &&
609
+ normalized.metadata &&
610
+ typeof normalized.metadata === "object") {
611
+ normalized.metadata.sessionId =
612
+ sessionIdentifiers.sessionId;
613
+ }
614
+ if (sessionIdentifiers.conversationId &&
615
+ normalized.metadata &&
616
+ typeof normalized.metadata === "object") {
617
+ normalized.metadata.conversationId =
618
+ sessionIdentifiers.conversationId;
619
+ }
614
620
  const disableStickyRoutes = readRuntimeMetadata(normalized.metadata)?.disableStickyRoutes === true;
615
621
  const stopMessageRouterMetadata = resolveStopMessageRouterMetadata(normalized.metadata);
616
622
  const estimatedInputTokens = (() => {
@@ -641,15 +647,15 @@ export class HubPipeline {
641
647
  : {}),
642
648
  ...stopMessageRouterMetadata,
643
649
  };
644
- const routing = await measureHubStage(normalized.id, "request_stage.req_process.route_select", () => runReqProcessStage2RouteSelect({
650
+ logHubStageTiming(normalized.id, "req_process.stage2_route_select", "start");
651
+ const routing = runReqProcessStage2RouteSelect({
645
652
  routerEngine: this.routerEngine,
646
653
  request: workingRequest,
647
654
  metadataInput,
648
655
  normalizedMetadata: normalized.metadata,
649
656
  stageRecorder: inboundRecorder,
650
- }));
651
- this.routerEngine.getStopMessageState(metadataInput);
652
- this.routerEngine.getPreCommandState(metadataInput);
657
+ });
658
+ logHubStageTiming(normalized.id, "req_process.stage2_route_select", "completed");
653
659
  // Emit virtual router hit log for debugging (orange [virtual-router] ...)
654
660
  try {
655
661
  const routeName = routing.decision?.routeName;
@@ -715,7 +721,7 @@ export class HubPipeline {
715
721
  const outboundContextSnapshot = protocolSwitch
716
722
  ? undefined
717
723
  : contextSnapshot;
718
- const outboundStage1 = await measureHubStage(normalized.id, "request_stage.req_outbound.semantic_map", () => runReqOutboundStage1SemanticMap({
724
+ const outboundStage1 = await measureHubStage(normalized.id, "req_outbound.stage1_semantic_map", () => runReqOutboundStage1SemanticMap({
719
725
  request: workingRequest,
720
726
  adapterContext: outboundAdapterContext,
721
727
  semanticMapper: outboundSemanticMapper,
@@ -723,11 +729,11 @@ export class HubPipeline {
723
729
  contextMetadataKey: outboundContextMetadataKey,
724
730
  stageRecorder: outboundRecorder,
725
731
  }));
726
- let formattedPayload = await measureHubStage(normalized.id, "request_stage.req_outbound.format_build", () => runReqOutboundStage2FormatBuild({
732
+ let formattedPayload = await measureHubStage(normalized.id, "req_outbound.stage2_format_build", () => runReqOutboundStage2FormatBuild({
727
733
  formatEnvelope: outboundStage1.formatEnvelope,
728
734
  stageRecorder: outboundRecorder,
729
735
  }));
730
- formattedPayload = await measureHubStage(normalized.id, "request_stage.req_outbound.compat", () => runReqOutboundStage3Compat({
736
+ formattedPayload = await measureHubStage(normalized.id, "req_outbound.stage3_compat", () => runReqOutboundStage3Compat({
731
737
  payload: formattedPayload,
732
738
  adapterContext: outboundAdapterContext,
733
739
  stageRecorder: outboundRecorder,
@@ -774,7 +780,7 @@ export class HubPipeline {
774
780
  stageRecorder: outboundRecorder,
775
781
  requestId: normalized.id,
776
782
  });
777
- providerPayload = (await measureHubStage(normalized.id, "request_stage.req_outbound.provider_policy", () => applyHubProviderOutboundPolicy({
783
+ providerPayload = applyHubProviderOutboundPolicy({
778
784
  policy: effectivePolicy,
779
785
  providerProtocol: outboundProtocol,
780
786
  compatibilityProfile: typeof outboundAdapterContext.compatibilityProfile === "string"
@@ -783,14 +789,14 @@ export class HubPipeline {
783
789
  payload: formattedPayload,
784
790
  stageRecorder: outboundRecorder,
785
791
  requestId: normalized.id,
786
- })));
787
- providerPayload = (await measureHubStage(normalized.id, "request_stage.req_outbound.tool_surface", () => applyProviderOutboundToolSurface({
792
+ });
793
+ providerPayload = applyProviderOutboundToolSurface({
788
794
  config: this.config.toolSurface,
789
795
  providerProtocol: outboundProtocol,
790
796
  payload: providerPayload,
791
797
  stageRecorder: outboundRecorder,
792
798
  requestId: normalized.id,
793
- })));
799
+ });
794
800
  providerPayload = maybeApplyDirectBuiltinWebSearchTool(providerPayload, outboundAdapterContext, outboundProtocol);
795
801
  recordHubPolicyObservation({
796
802
  policy: effectivePolicy,
@@ -1033,6 +1039,18 @@ export class HubPipeline {
1033
1039
  catch {
1034
1040
  // best-effort; validation happens below
1035
1041
  }
1042
+ try {
1043
+ const rt = readRuntimeMetadata(metaBase);
1044
+ const mode = String(rt?.applyPatchToolMode || "")
1045
+ .trim()
1046
+ .toLowerCase();
1047
+ if (mode === "freeform" || mode === "schema") {
1048
+ standardizedRequest.metadata.applyPatchToolMode = mode;
1049
+ }
1050
+ }
1051
+ catch {
1052
+ // ignore
1053
+ }
1036
1054
  const adapterContext = this.buildAdapterContext(normalized);
1037
1055
  const stageRecorder = this.maybeCreateStageRecorder(adapterContext, normalized.entryEndpoint, {
1038
1056
  disableSnapshots: normalized.disableSnapshots === true,
@@ -1040,15 +1058,14 @@ export class HubPipeline {
1040
1058
  let processedRequest;
1041
1059
  if (activeProcessMode !== "passthrough") {
1042
1060
  assertNoMappableSemanticsInMetadata(metaBase, "chat_process.request.entry");
1043
- const processResult = await measureHubStage(normalized.id, "chat_entry.req_process.tool_governance", () => runReqProcessStage1ToolGovernance({
1061
+ const processResult = await runReqProcessStage1ToolGovernance({
1044
1062
  request: standardizedRequest,
1045
1063
  rawPayload,
1046
1064
  metadata: metaBase,
1047
1065
  entryEndpoint: normalized.entryEndpoint,
1048
1066
  requestId: normalized.id,
1049
- applyPatchToolMode: normalized.applyPatchToolMode,
1050
1067
  stageRecorder,
1051
- }));
1068
+ });
1052
1069
  processedRequest = processResult.processedRequest;
1053
1070
  // Surface request-side clock reservation into pipeline metadata so response conversion
1054
1071
  // can commit delivery only after a successful response is produced.
@@ -1082,57 +1099,15 @@ export class HubPipeline {
1082
1099
  }
1083
1100
  }
1084
1101
  let workingRequest = syncResponsesContextFromCanonicalMessages(processedRequest ?? standardizedRequest);
1085
- const sessionIdentifiers = extractSessionIdentifiersFromMetadata(normalized.metadata);
1086
- if (sessionIdentifiers.sessionId &&
1087
- normalized.metadata &&
1088
- typeof normalized.metadata === "object") {
1089
- normalized.metadata.sessionId =
1090
- sessionIdentifiers.sessionId;
1091
- }
1092
- if (sessionIdentifiers.conversationId &&
1093
- normalized.metadata &&
1094
- typeof normalized.metadata === "object") {
1095
- normalized.metadata.conversationId =
1096
- sessionIdentifiers.conversationId;
1097
- }
1098
1102
  // Token estimate for stats/diagnostics (best-effort).
1099
1103
  try {
1100
- const sessionEstimate = await measureHubStage(normalized.id, "chat_entry.req_process.token_estimate.session_delta", () => estimateChatProcessSessionInputTokensDetailed({
1101
- sessionId: sessionIdentifiers.sessionId,
1102
- conversationId: sessionIdentifiers.conversationId,
1103
- }, workingRequest), {
1104
- mapCompletedDetails: (value) => ({
1105
- forceLog: value.mode === "unavailable" ||
1106
- value.mode === "session_reuse" ||
1107
- value.mode === "session_delta",
1108
- scope: value.scope,
1109
- mode: value.mode,
1110
- reason: value.reason,
1111
- previousMessageCount: value.previousMessageCount,
1112
- appendedMessageCount: value.appendedMessageCount,
1113
- hasPreviousTokens: value.hasPreviousTokens,
1114
- hasPreviousMessageCount: value.hasPreviousMessageCount,
1115
- hasToolsSignature: value.hasToolsSignature,
1116
- hasParametersSignature: value.hasParametersSignature,
1117
- previousParametersSignatureDigest: value.previousParametersSignatureDigest,
1118
- currentParametersSignatureDigest: value.currentParametersSignatureDigest,
1119
- }),
1120
- });
1121
- const estimatedTokens = typeof sessionEstimate.tokens === "number" &&
1122
- Number.isFinite(sessionEstimate.tokens) &&
1123
- sessionEstimate.tokens > 0
1124
- ? sessionEstimate.tokens
1125
- : await measureHubStage(normalized.id, "chat_entry.req_process.token_estimate.full_count", () => computeRequestTokens(workingRequest, ""));
1104
+ const estimatedTokens = estimateSessionBoundTokens(workingRequest, normalized.metadata) ?? computeRequestTokens(workingRequest, "");
1126
1105
  if (typeof estimatedTokens === "number" &&
1127
1106
  Number.isFinite(estimatedTokens) &&
1128
1107
  estimatedTokens > 0) {
1129
1108
  normalized.metadata = normalized.metadata || {};
1130
1109
  normalized.metadata.estimatedInputTokens =
1131
1110
  estimatedTokens;
1132
- saveChatProcessSessionInputEstimate({
1133
- sessionId: sessionIdentifiers.sessionId,
1134
- conversationId: sessionIdentifiers.conversationId,
1135
- }, workingRequest, estimatedTokens);
1136
1111
  }
1137
1112
  }
1138
1113
  catch {
@@ -1146,6 +1121,19 @@ export class HubPipeline {
1146
1121
  const hasImageAttachment = containsImageAttachment((workingRequest.messages ?? []));
1147
1122
  const serverToolRequired = stdMetadata?.webSearchEnabled === true ||
1148
1123
  stdMetadata?.serverToolRequired === true;
1124
+ const sessionIdentifiers = extractSessionIdentifiersFromMetadata(normalized.metadata);
1125
+ if (sessionIdentifiers.sessionId &&
1126
+ normalized.metadata &&
1127
+ typeof normalized.metadata === "object") {
1128
+ normalized.metadata.sessionId =
1129
+ sessionIdentifiers.sessionId;
1130
+ }
1131
+ if (sessionIdentifiers.conversationId &&
1132
+ normalized.metadata &&
1133
+ typeof normalized.metadata === "object") {
1134
+ normalized.metadata.conversationId =
1135
+ sessionIdentifiers.conversationId;
1136
+ }
1149
1137
  const disableStickyRoutes = readRuntimeMetadata(normalized.metadata)?.disableStickyRoutes === true;
1150
1138
  const stopMessageRouterMetadata = resolveStopMessageRouterMetadata(normalized.metadata);
1151
1139
  const metadataInput = {
@@ -1168,15 +1156,13 @@ export class HubPipeline {
1168
1156
  : {}),
1169
1157
  ...stopMessageRouterMetadata,
1170
1158
  };
1171
- const routing = await measureHubStage(normalized.id, "chat_entry.req_process.route_select", () => runReqProcessStage2RouteSelect({
1159
+ const routing = runReqProcessStage2RouteSelect({
1172
1160
  routerEngine: this.routerEngine,
1173
1161
  request: workingRequest,
1174
1162
  metadataInput,
1175
1163
  normalizedMetadata: normalized.metadata,
1176
1164
  stageRecorder,
1177
- }));
1178
- this.routerEngine.getStopMessageState(metadataInput);
1179
- this.routerEngine.getPreCommandState(metadataInput);
1165
+ });
1180
1166
  // Emit virtual router hit log for debugging (same as inbound path).
1181
1167
  try {
1182
1168
  const routeName = routing.decision?.routeName;
@@ -1235,7 +1221,7 @@ export class HubPipeline {
1235
1221
  ? outboundHooks.contextMetadataKey
1236
1222
  : hooks.contextMetadataKey;
1237
1223
  const outboundContextSnapshot = undefined;
1238
- const outboundStage1 = await measureHubStage(normalized.id, "chat_entry.req_outbound.semantic_map", () => runReqOutboundStage1SemanticMap({
1224
+ const outboundStage1 = await measureHubStage(normalized.id, "req_outbound.stage1_semantic_map", () => runReqOutboundStage1SemanticMap({
1239
1225
  request: workingRequest,
1240
1226
  adapterContext: outboundAdapterContext,
1241
1227
  semanticMapper: outboundSemanticMapper,
@@ -1243,11 +1229,11 @@ export class HubPipeline {
1243
1229
  contextMetadataKey: outboundContextMetadataKey,
1244
1230
  stageRecorder: outboundRecorder,
1245
1231
  }));
1246
- let formattedPayload = await measureHubStage(normalized.id, "chat_entry.req_outbound.format_build", () => runReqOutboundStage2FormatBuild({
1232
+ let formattedPayload = await measureHubStage(normalized.id, "req_outbound.stage2_format_build", () => runReqOutboundStage2FormatBuild({
1247
1233
  formatEnvelope: outboundStage1.formatEnvelope,
1248
1234
  stageRecorder: outboundRecorder,
1249
1235
  }));
1250
- formattedPayload = await measureHubStage(normalized.id, "chat_entry.req_outbound.compat", () => runReqOutboundStage3Compat({
1236
+ formattedPayload = await measureHubStage(normalized.id, "req_outbound.stage3_compat", () => runReqOutboundStage3Compat({
1251
1237
  payload: formattedPayload,
1252
1238
  adapterContext: outboundAdapterContext,
1253
1239
  stageRecorder: outboundRecorder,
@@ -1264,7 +1250,7 @@ export class HubPipeline {
1264
1250
  stageRecorder: outboundRecorder,
1265
1251
  requestId: normalized.id,
1266
1252
  });
1267
- providerPayload = (await measureHubStage(normalized.id, "chat_entry.req_outbound.provider_policy", () => applyHubProviderOutboundPolicy({
1253
+ providerPayload = applyHubProviderOutboundPolicy({
1268
1254
  policy: effectivePolicy,
1269
1255
  providerProtocol: outboundProtocol,
1270
1256
  compatibilityProfile: typeof outboundAdapterContext.compatibilityProfile === "string"
@@ -1273,14 +1259,14 @@ export class HubPipeline {
1273
1259
  payload: formattedPayload,
1274
1260
  stageRecorder: outboundRecorder,
1275
1261
  requestId: normalized.id,
1276
- })));
1277
- providerPayload = (await measureHubStage(normalized.id, "chat_entry.req_outbound.tool_surface", () => applyProviderOutboundToolSurface({
1262
+ });
1263
+ providerPayload = applyProviderOutboundToolSurface({
1278
1264
  config: this.config.toolSurface,
1279
1265
  providerProtocol: outboundProtocol,
1280
1266
  payload: providerPayload,
1281
1267
  stageRecorder: outboundRecorder,
1282
1268
  requestId: normalized.id,
1283
- })));
1269
+ });
1284
1270
  providerPayload = maybeApplyDirectBuiltinWebSearchTool(providerPayload, outboundAdapterContext, outboundProtocol);
1285
1271
  recordHubPolicyObservation({
1286
1272
  policy: effectivePolicy,
@@ -1354,27 +1340,16 @@ export class HubPipeline {
1354
1340
  };
1355
1341
  }
1356
1342
  async execute(request) {
1357
- const requestId = request && typeof request === "object" && typeof request.id === "string" && request.id.trim()
1358
- ? request.id.trim()
1359
- : `req_${Date.now()}`;
1360
- const normalized = await measureHubStage(requestId, "execute.normalize_request", () => this.normalizeRequest(request), {
1361
- mapCompletedDetails: (value) => ({
1362
- providerProtocol: value.providerProtocol,
1363
- direction: value.direction,
1364
- stage: value.stage,
1365
- processMode: value.processMode,
1366
- hubEntryMode: value.hubEntryMode ?? null
1367
- })
1368
- });
1343
+ const normalized = await this.normalizeRequest(request);
1369
1344
  if (normalized.direction === "request" &&
1370
1345
  normalized.hubEntryMode === "chat_process") {
1371
- return await measureHubStage(normalized.id, "execute.chat_process_entry", () => this.executeChatProcessEntryPipeline(normalized));
1346
+ return await this.executeChatProcessEntryPipeline(normalized);
1372
1347
  }
1373
1348
  const hooks = this.resolveProtocolHooks(normalized.providerProtocol);
1374
1349
  if (!hooks) {
1375
1350
  throw new Error(`Unsupported provider protocol for hub pipeline: ${normalized.providerProtocol}`);
1376
1351
  }
1377
- return await measureHubStage(normalized.id, "execute.request_stage_pipeline", () => this.executeRequestStagePipeline(normalized, hooks));
1352
+ return await this.executeRequestStagePipeline(normalized, hooks);
1378
1353
  }
1379
1354
  captureAnthropicAliasMap(normalized, adapterContext, chatEnvelope) {
1380
1355
  if (!this.shouldCaptureAnthropicAlias(normalized.entryEndpoint)) {
@@ -1490,9 +1465,7 @@ export class HubPipeline {
1490
1465
  : normalized.stream === false
1491
1466
  ? "disable"
1492
1467
  : "auto";
1493
- const targetToolCallIdStyle = normalizeReqInboundToolCallIdStyleWithNative(target?.responsesConfig
1494
- ?.toolCallIdStyle);
1495
- const toolCallIdStyle = targetToolCallIdStyle ?? normalized.toolCallIdStyle;
1468
+ const toolCallIdStyle = normalizeReqInboundToolCallIdStyleWithNative(metadata.toolCallIdStyle);
1496
1469
  const adapterContext = {
1497
1470
  requestId: normalized.id,
1498
1471
  entryEndpoint: normalized.entryEndpoint || "/v1/chat/completions",
@@ -1502,9 +1475,6 @@ export class HubPipeline {
1502
1475
  profileId,
1503
1476
  streamingHint,
1504
1477
  toolCallIdStyle,
1505
- ...(normalized.applyPatchToolMode
1506
- ? { applyPatchToolMode: normalized.applyPatchToolMode }
1507
- : {}),
1508
1478
  ...(compatibilityProfile ? { compatibilityProfile } : {}),
1509
1479
  };
1510
1480
  const targetDeepseek = isJsonObject(target?.deepseek)
@@ -1732,9 +1702,6 @@ export class HubPipeline {
1732
1702
  : endpoint;
1733
1703
  const providerProtocol = resolveProviderProtocol(metadataRecord.providerProtocol);
1734
1704
  const processMode = metadataRecord.processMode === "passthrough" ? "passthrough" : "chat";
1735
- if (Object.prototype.hasOwnProperty.call(metadataRecord, "processMode")) {
1736
- delete metadataRecord.processMode;
1737
- }
1738
1705
  const direction = metadataRecord.direction === "response" ? "response" : "request";
1739
1706
  const stage = metadataRecord.stage === "outbound" ? "outbound" : "inbound";
1740
1707
  const resolvedReadable = this.unwrapReadable(request.payload);
@@ -1743,36 +1710,16 @@ export class HubPipeline {
1743
1710
  (request.payload &&
1744
1711
  typeof request.payload === "object" &&
1745
1712
  request.payload.stream));
1746
- let payload = await measureHubStage(id, "normalize.materialize_payload", () => this.materializePayload(request.payload, {
1713
+ let payload = await this.materializePayload(request.payload, {
1747
1714
  requestId: id,
1748
1715
  entryEndpoint,
1749
1716
  providerProtocol,
1750
1717
  metadata: metadataRecord,
1751
- }, resolvedReadable), {
1752
- startDetails: {
1753
- hasReadable: Boolean(resolvedReadable),
1754
- providerProtocol,
1755
- entryEndpoint
1756
- }
1757
- });
1718
+ }, resolvedReadable);
1758
1719
  const routeHint = typeof metadataRecord.routeHint === "string"
1759
1720
  ? metadataRecord.routeHint
1760
1721
  : undefined;
1761
- if (Object.prototype.hasOwnProperty.call(metadataRecord, "routeHint")) {
1762
- delete metadataRecord.routeHint;
1763
- }
1764
- const toolCallIdStyle = normalizeReqInboundToolCallIdStyleWithNative(metadataRecord.toolCallIdStyle);
1765
- if (Object.prototype.hasOwnProperty.call(metadataRecord, "toolCallIdStyle")) {
1766
- delete metadataRecord.toolCallIdStyle;
1767
- }
1768
- const applyPatchToolMode = resolveApplyPatchToolModeFromEnv() ??
1769
- resolveApplyPatchToolModeFromTools(Array.isArray(payload.tools)
1770
- ? (payload.tools ?? null)
1771
- : null);
1772
- if (Object.prototype.hasOwnProperty.call(metadataRecord, "applyPatchToolMode")) {
1773
- delete metadataRecord.applyPatchToolMode;
1774
- }
1775
- const orchestrationResult = await measureHubStage(id, "normalize.native_orchestration", () => runHubPipelineOrchestrationWithNative({
1722
+ const orchestrationResult = runHubPipelineOrchestrationWithNative({
1776
1723
  requestId: id,
1777
1724
  endpoint,
1778
1725
  entryEndpoint,
@@ -1791,20 +1738,6 @@ export class HubPipeline {
1791
1738
  processMode,
1792
1739
  direction,
1793
1740
  stage,
1794
- }), {
1795
- startDetails: {
1796
- providerProtocol,
1797
- processMode,
1798
- direction,
1799
- stage,
1800
- stream
1801
- },
1802
- mapCompletedDetails: (value) => ({
1803
- success: value.success,
1804
- hasPayload: Boolean(value.payload),
1805
- hasMetadata: Boolean(value.metadata),
1806
- errorCode: value.error?.code
1807
- })
1808
1741
  });
1809
1742
  if (!orchestrationResult.success) {
1810
1743
  const code = orchestrationResult.error &&
@@ -1820,23 +1753,16 @@ export class HubPipeline {
1820
1753
  if (orchestrationResult.payload) {
1821
1754
  payload = orchestrationResult.payload;
1822
1755
  }
1823
- const orchestrationMetadata = {
1824
- ...(orchestrationResult.metadata ?? {}),
1825
- };
1826
- if (Object.prototype.hasOwnProperty.call(orchestrationMetadata, "processMode")) {
1827
- delete orchestrationMetadata.processMode;
1828
- }
1829
- if (Object.prototype.hasOwnProperty.call(orchestrationMetadata, "routeHint")) {
1830
- delete orchestrationMetadata.routeHint;
1831
- }
1832
1756
  const normalizedMetadata = {
1833
1757
  ...metadataRecord,
1834
1758
  entryEndpoint,
1835
1759
  providerProtocol,
1760
+ processMode,
1836
1761
  direction,
1837
1762
  stage,
1838
1763
  stream,
1839
- ...orchestrationMetadata,
1764
+ ...(routeHint ? { routeHint } : {}),
1765
+ ...(orchestrationResult.metadata ?? {}),
1840
1766
  };
1841
1767
  return {
1842
1768
  id,
@@ -1853,8 +1779,6 @@ export class HubPipeline {
1853
1779
  stage,
1854
1780
  stream,
1855
1781
  routeHint,
1856
- ...(toolCallIdStyle ? { toolCallIdStyle } : {}),
1857
- ...(applyPatchToolMode ? { applyPatchToolMode } : {}),
1858
1782
  ...(hubEntryMode ? { hubEntryMode } : {}),
1859
1783
  };
1860
1784
  }
@@ -1,3 +1,4 @@
1
+ export declare function isHubStageTimingDetailEnabled(): boolean;
1
2
  export declare function logHubStageTiming(requestId: string, stage: string, phase: 'start' | 'completed' | 'error', details?: Record<string, unknown>): void;
2
3
  export declare function measureHubStage<T>(requestId: string, stage: string, fn: () => Promise<T> | T, options?: {
3
4
  startDetails?: Record<string, unknown>;