pi-smart-router 0.1.0 → 0.2.0
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/.pi/extensions/smart-router/delegation-runtime.ts +12 -2
- package/README.md +55 -17
- package/dist/api/explain/router-explain.d.ts +4 -1
- package/dist/api/explain/router-explain.d.ts.map +1 -1
- package/dist/api/explain/router-explain.js +9 -9
- package/dist/api/explain/router-explain.js.map +1 -1
- package/dist/config/defaults.d.ts +4 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +10 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/domain/delegation/delegation-context.d.ts +23 -1
- package/dist/domain/delegation/delegation-context.d.ts.map +1 -1
- package/dist/domain/delegation/delegation-context.js +93 -0
- package/dist/domain/delegation/delegation-context.js.map +1 -1
- package/dist/domain/pinning/cache-breakeven.d.ts +51 -0
- package/dist/domain/pinning/cache-breakeven.d.ts.map +1 -0
- package/dist/domain/pinning/cache-breakeven.js +124 -0
- package/dist/domain/pinning/cache-breakeven.js.map +1 -0
- package/dist/domain/pinning/saar-session-state.d.ts +36 -0
- package/dist/domain/pinning/saar-session-state.d.ts.map +1 -0
- package/dist/domain/pinning/saar-session-state.js +74 -0
- package/dist/domain/pinning/saar-session-state.js.map +1 -0
- package/dist/domain/pinning/session-pinner.d.ts +35 -3
- package/dist/domain/pinning/session-pinner.d.ts.map +1 -1
- package/dist/domain/pinning/session-pinner.js +149 -1
- package/dist/domain/pinning/session-pinner.js.map +1 -1
- package/dist/domain/pipeline/router-pipeline.d.ts +15 -1
- package/dist/domain/pipeline/router-pipeline.d.ts.map +1 -1
- package/dist/domain/pipeline/router-pipeline.js +118 -6
- package/dist/domain/pipeline/router-pipeline.js.map +1 -1
- package/dist/domain/routing/tool-history-guard.d.ts +21 -5
- package/dist/domain/routing/tool-history-guard.d.ts.map +1 -1
- package/dist/domain/routing/tool-history-guard.js +77 -10
- package/dist/domain/routing/tool-history-guard.js.map +1 -1
- package/dist/domain/types/entities.d.ts +48 -0
- package/dist/domain/types/entities.d.ts.map +1 -1
- package/dist/domain/types/index.d.ts +1 -1
- package/dist/domain/types/index.d.ts.map +1 -1
- package/dist/domain/types/schemas.d.ts +24 -0
- package/dist/domain/types/schemas.d.ts.map +1 -1
- package/dist/domain/types/schemas.js +54 -0
- package/dist/domain/types/schemas.js.map +1 -1
- package/dist/infra/gemini-provider.d.ts.map +1 -1
- package/dist/infra/gemini-provider.js +2 -1
- package/dist/infra/gemini-provider.js.map +1 -1
- package/dist/infrastructure/persistence/sqlite-store.d.ts.map +1 -1
- package/dist/infrastructure/persistence/sqlite-store.js +3 -0
- package/dist/infrastructure/persistence/sqlite-store.js.map +1 -1
- package/dist/infrastructure/telemetry/routing-telemetry.d.ts +30 -2
- package/dist/infrastructure/telemetry/routing-telemetry.d.ts.map +1 -1
- package/dist/infrastructure/telemetry/routing-telemetry.js +221 -3
- package/dist/infrastructure/telemetry/routing-telemetry.js.map +1 -1
- package/package.json +5 -4
- package/src/api/explain/router-explain.ts +14 -10
- package/src/config/defaults.ts +18 -1
- package/src/domain/delegation/delegation-context.ts +124 -0
- package/src/domain/pinning/cache-breakeven.ts +219 -0
- package/src/domain/pinning/saar-session-state.ts +93 -0
- package/src/domain/pinning/session-pinner.ts +244 -3
- package/src/domain/pipeline/router-pipeline.ts +159 -7
- package/src/domain/routing/tool-history-guard.ts +108 -10
- package/src/domain/types/entities.ts +54 -0
- package/src/domain/types/index.ts +4 -0
- package/src/domain/types/schemas.ts +69 -0
- package/src/infra/gemini-provider.ts +2 -1
- package/src/infrastructure/persistence/sqlite-store.ts +6 -0
- package/src/infrastructure/telemetry/routing-telemetry.ts +327 -7
|
@@ -16,7 +16,11 @@ import {
|
|
|
16
16
|
} from '../../domain/routing/context-fit.js';
|
|
17
17
|
import { CLUSTER_REASON_CODE_PREFIX } from '../../config/routing-clusters-loader.js';
|
|
18
18
|
import type { ClusterMatcher } from '../../domain/matching/cluster-matcher.js';
|
|
19
|
+
import { evaluateModelSwitchBreakeven } from '../../domain/pinning/session-pinner.js';
|
|
20
|
+
import { selectLowestCostModel } from '../../domain/pinning/sub-route-policy.js';
|
|
21
|
+
import type { SessionPinner } from '../../domain/pinning/session-pinner.js';
|
|
19
22
|
import type {
|
|
23
|
+
BreakevenObservability,
|
|
20
24
|
ClusterMatchTableEntry,
|
|
21
25
|
ContextFitObservability,
|
|
22
26
|
ContextFitRejectedEntry,
|
|
@@ -27,6 +31,9 @@ import type {
|
|
|
27
31
|
RoutingDecision,
|
|
28
32
|
RoutingRequest,
|
|
29
33
|
RoutingTelemetry,
|
|
34
|
+
SaarConfig,
|
|
35
|
+
SaarObservability,
|
|
36
|
+
Tier,
|
|
30
37
|
TierFeatureSummary,
|
|
31
38
|
TierSelectionObservability,
|
|
32
39
|
} from '../../domain/types/index.js';
|
|
@@ -47,6 +54,26 @@ export const HIGH_INTENSITY_STRUCTURAL = 'high_intensity_structural' as const;
|
|
|
47
54
|
export const P_SUCCESS_CHEAP = 'p_success_cheap' as const;
|
|
48
55
|
export const P_SUCCESS_UNCERTAIN = 'p_success_uncertain' as const;
|
|
49
56
|
|
|
57
|
+
export const BREAKEVEN_BLOCKED = 'breakeven_blocked' as const;
|
|
58
|
+
export const BREAKEVEN_PASS = 'breakeven_pass' as const;
|
|
59
|
+
export const SAAR_BUFFER_ACTIVE = 'saar_buffer_active' as const;
|
|
60
|
+
export const SAAR_HARD_LOCK = 'saar_hard_lock' as const;
|
|
61
|
+
|
|
62
|
+
const TURN_ENVELOPE_TIER_MAP: Readonly<Record<string, Tier | null>> = {
|
|
63
|
+
planning: 'frontier-cloud',
|
|
64
|
+
tool_result: 'economical-cloud',
|
|
65
|
+
subagent: 'economical-cloud',
|
|
66
|
+
main_loop: null,
|
|
67
|
+
unknown: null,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const SAAR_DECISION_REASON_CODES = new Set<string>([
|
|
71
|
+
SAAR_BUFFER_ACTIVE,
|
|
72
|
+
SAAR_HARD_LOCK,
|
|
73
|
+
'saar_tier_upgrade',
|
|
74
|
+
'saar_idle_reopen',
|
|
75
|
+
]);
|
|
76
|
+
|
|
50
77
|
const EXPECTED_COST_PREFIX = 'expected_cost_';
|
|
51
78
|
const EXPECTED_COST_DEFER_CODES = new Set<string>([
|
|
52
79
|
'expected_cost_price_delta_insufficient',
|
|
@@ -88,6 +115,8 @@ export interface TelemetryEmitterOptions {
|
|
|
88
115
|
readonly onRecord?: (record: RoutingTelemetry) => void;
|
|
89
116
|
readonly fleet?: readonly ModelProfile[];
|
|
90
117
|
readonly contextFitConfig?: ContextFitConfig;
|
|
118
|
+
readonly sessionPinner?: SessionPinner;
|
|
119
|
+
readonly saarConfig?: SaarConfig;
|
|
91
120
|
}
|
|
92
121
|
|
|
93
122
|
export interface ContextFitObservabilityInput {
|
|
@@ -467,6 +496,223 @@ export function buildTierSelectionObservability(
|
|
|
467
496
|
};
|
|
468
497
|
}
|
|
469
498
|
|
|
499
|
+
export interface PinEconomicsObservabilityInput {
|
|
500
|
+
readonly request: RoutingRequest;
|
|
501
|
+
readonly decision: RoutingDecision;
|
|
502
|
+
readonly fleet?: readonly ModelProfile[] | undefined;
|
|
503
|
+
readonly sessionPinner?: SessionPinner | undefined;
|
|
504
|
+
readonly saarConfig?: SaarConfig | undefined;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function resolveTurnEnvelopeTargetTier(request: RoutingRequest): Tier | null {
|
|
508
|
+
const turnType = request.turn_type ?? 'unknown';
|
|
509
|
+
return TURN_ENVELOPE_TIER_MAP[turnType] ?? null;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function isSaarPlanningBufferActive(
|
|
513
|
+
request: RoutingRequest,
|
|
514
|
+
sessionPinner: SessionPinner | undefined,
|
|
515
|
+
saarConfig: SaarConfig | undefined,
|
|
516
|
+
): boolean {
|
|
517
|
+
if (!saarConfig || !sessionPinner || request.turn_type !== 'planning') {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (!sessionPinner.getPin(request.session_id)) {
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const saarState = sessionPinner.getSaarState(request.session_id);
|
|
526
|
+
const turnIndex = saarState?.turn_index ?? 0;
|
|
527
|
+
|
|
528
|
+
return turnIndex < saarConfig.planning_turn_buffer;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function resolveSaarReasonCode(decision: RoutingDecision): string | null {
|
|
532
|
+
if (SAAR_DECISION_REASON_CODES.has(decision.reason_code)) {
|
|
533
|
+
return decision.reason_code;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
return null;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/** Build privacy-safe SAAR pin state for explain and telemetry (SP-126). */
|
|
540
|
+
export function buildSaarObservability(
|
|
541
|
+
input: PinEconomicsObservabilityInput,
|
|
542
|
+
): SaarObservability | null {
|
|
543
|
+
const { request, decision, sessionPinner, saarConfig } = input;
|
|
544
|
+
if (!saarConfig) {
|
|
545
|
+
return null;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const saarState = sessionPinner?.getSaarState(request.session_id) ?? null;
|
|
549
|
+
const pin = sessionPinner?.getPin(request.session_id) ?? null;
|
|
550
|
+
|
|
551
|
+
if (!pin && !saarState && !resolveSaarReasonCode(decision)) {
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const turnIndex = saarState?.turn_index ?? (pin ? 0 : null);
|
|
556
|
+
|
|
557
|
+
return {
|
|
558
|
+
buffer_active:
|
|
559
|
+
turnIndex !== null ? turnIndex < saarConfig.planning_turn_buffer : false,
|
|
560
|
+
hard_lock: saarState?.hard_lock ?? false,
|
|
561
|
+
turn_index_in_session: turnIndex,
|
|
562
|
+
planning_turn_buffer: saarConfig.planning_turn_buffer,
|
|
563
|
+
idle_timeout_seconds: saarConfig.idle_timeout_seconds,
|
|
564
|
+
saar_reason_code: resolveSaarReasonCode(decision),
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/** Build cache breakeven breakdown when a pin would switch tiers (SP-126). */
|
|
569
|
+
export function buildBreakevenObservability(
|
|
570
|
+
input: PinEconomicsObservabilityInput,
|
|
571
|
+
): BreakevenObservability | null {
|
|
572
|
+
const { request, sessionPinner, saarConfig, fleet } = input;
|
|
573
|
+
if (!fleet || !sessionPinner) {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const pin = sessionPinner.getPin(request.session_id);
|
|
578
|
+
if (!pin) {
|
|
579
|
+
return null;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const targetTier = resolveTurnEnvelopeTargetTier(request);
|
|
583
|
+
if (!targetTier) {
|
|
584
|
+
return null;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (isSaarPlanningBufferActive(request, sessionPinner, saarConfig)) {
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
const pinnedModel = fleet.find(
|
|
592
|
+
(model) => model.id === pin.pinned_model_id && model.healthy !== false,
|
|
593
|
+
);
|
|
594
|
+
const candidate = selectLowestCostModel(
|
|
595
|
+
fleet.filter((model) => model.tier === targetTier && model.healthy !== false),
|
|
596
|
+
);
|
|
597
|
+
|
|
598
|
+
if (!pinnedModel || !candidate || pinnedModel.id === candidate.id) {
|
|
599
|
+
return null;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const tokenEstimate =
|
|
603
|
+
request.estimated_input_tokens ?? request.prompt_text.length;
|
|
604
|
+
const breakeven = evaluateModelSwitchBreakeven(
|
|
605
|
+
pinnedModel,
|
|
606
|
+
candidate,
|
|
607
|
+
tokenEstimate,
|
|
608
|
+
tokenEstimate,
|
|
609
|
+
saarConfig,
|
|
610
|
+
);
|
|
611
|
+
|
|
612
|
+
return {
|
|
613
|
+
marginal_savings: breakeven.marginal_savings,
|
|
614
|
+
future_cache_value: breakeven.future_cache_value,
|
|
615
|
+
cache_reprime_cost: breakeven.cache_reprime_cost,
|
|
616
|
+
decision: breakeven.shouldSwitch ? 'pass' : 'blocked',
|
|
617
|
+
breakeven_reason_code: breakeven.shouldSwitch ? BREAKEVEN_PASS : BREAKEVEN_BLOCKED,
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function defaultBreakevenTelemetry(): Pick<
|
|
622
|
+
RoutingTelemetry,
|
|
623
|
+
| 'marginal_savings'
|
|
624
|
+
| 'future_cache_value'
|
|
625
|
+
| 'cache_reprime_cost'
|
|
626
|
+
| 'breakeven_decision'
|
|
627
|
+
| 'breakeven_reason_code'
|
|
628
|
+
> {
|
|
629
|
+
return {
|
|
630
|
+
marginal_savings: null,
|
|
631
|
+
future_cache_value: null,
|
|
632
|
+
cache_reprime_cost: null,
|
|
633
|
+
breakeven_decision: null,
|
|
634
|
+
breakeven_reason_code: null,
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
function defaultSaarTelemetry(): Pick<
|
|
639
|
+
RoutingTelemetry,
|
|
640
|
+
| 'saar_buffer_active'
|
|
641
|
+
| 'saar_hard_lock'
|
|
642
|
+
| 'turn_index_in_session'
|
|
643
|
+
| 'saar_reason_code'
|
|
644
|
+
> {
|
|
645
|
+
return {
|
|
646
|
+
saar_buffer_active: false,
|
|
647
|
+
saar_hard_lock: false,
|
|
648
|
+
turn_index_in_session: null,
|
|
649
|
+
saar_reason_code: null,
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/** Default breakeven telemetry scalars for tests and legacy store reads. */
|
|
654
|
+
export const DEFAULT_BREAKEVEN_TELEMETRY_FIELDS = defaultBreakevenTelemetry();
|
|
655
|
+
|
|
656
|
+
/** Default SAAR telemetry scalars for tests and legacy store reads. */
|
|
657
|
+
export const DEFAULT_SAAR_TELEMETRY_FIELDS = defaultSaarTelemetry();
|
|
658
|
+
|
|
659
|
+
function pinEconomicsTelemetryFromInput(
|
|
660
|
+
input: PinEconomicsObservabilityInput,
|
|
661
|
+
): ReturnType<typeof defaultBreakevenTelemetry> &
|
|
662
|
+
ReturnType<typeof defaultSaarTelemetry> {
|
|
663
|
+
const breakeven = buildBreakevenObservability(input);
|
|
664
|
+
const saar = buildSaarObservability(input);
|
|
665
|
+
|
|
666
|
+
return {
|
|
667
|
+
...(breakeven
|
|
668
|
+
? {
|
|
669
|
+
marginal_savings: breakeven.marginal_savings,
|
|
670
|
+
future_cache_value: breakeven.future_cache_value,
|
|
671
|
+
cache_reprime_cost: breakeven.cache_reprime_cost,
|
|
672
|
+
breakeven_decision: breakeven.decision,
|
|
673
|
+
breakeven_reason_code: breakeven.breakeven_reason_code,
|
|
674
|
+
}
|
|
675
|
+
: defaultBreakevenTelemetry()),
|
|
676
|
+
saar_buffer_active: saar?.buffer_active ?? false,
|
|
677
|
+
saar_hard_lock: saar?.hard_lock ?? false,
|
|
678
|
+
turn_index_in_session: saar?.turn_index_in_session ?? null,
|
|
679
|
+
saar_reason_code: saar?.saar_reason_code ?? null,
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/** Attach breakeven and SAAR observability to routing decision features (SP-126). */
|
|
684
|
+
export function enrichRoutingDecisionWithPinEconomics(
|
|
685
|
+
request: RoutingRequest,
|
|
686
|
+
decision: RoutingDecision,
|
|
687
|
+
options?: Omit<PinEconomicsObservabilityInput, 'request' | 'decision'>,
|
|
688
|
+
): RoutingDecision {
|
|
689
|
+
const input: PinEconomicsObservabilityInput = {
|
|
690
|
+
request,
|
|
691
|
+
decision,
|
|
692
|
+
...(options?.fleet !== undefined ? { fleet: options.fleet } : {}),
|
|
693
|
+
...(options?.sessionPinner !== undefined
|
|
694
|
+
? { sessionPinner: options.sessionPinner }
|
|
695
|
+
: {}),
|
|
696
|
+
...(options?.saarConfig !== undefined ? { saarConfig: options.saarConfig } : {}),
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
const breakeven = buildBreakevenObservability(input);
|
|
700
|
+
const saar = buildSaarObservability(input);
|
|
701
|
+
|
|
702
|
+
if (!breakeven && !saar) {
|
|
703
|
+
return decision;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
return {
|
|
707
|
+
...decision,
|
|
708
|
+
features: {
|
|
709
|
+
...(decision.features ?? emptyFeatureSidecar()),
|
|
710
|
+
...(breakeven ? { breakeven } : {}),
|
|
711
|
+
...(saar ? { saar } : {}),
|
|
712
|
+
},
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
|
|
470
716
|
function emptyFeatureSidecar() {
|
|
471
717
|
return {
|
|
472
718
|
triage: null,
|
|
@@ -508,6 +754,8 @@ export interface ExplainEnrichmentOptions {
|
|
|
508
754
|
readonly fleet?: readonly ModelProfile[];
|
|
509
755
|
readonly contextFitConfig?: ContextFitConfig;
|
|
510
756
|
readonly clusterMatcher?: ClusterMatcher;
|
|
757
|
+
readonly sessionPinner?: SessionPinner;
|
|
758
|
+
readonly saarConfig?: SaarConfig;
|
|
511
759
|
}
|
|
512
760
|
|
|
513
761
|
/** Attach context-fit and tier-selection observability for explain responses (SP-110, SP-113). */
|
|
@@ -532,7 +780,23 @@ export async function enrichRoutingDecisionForExplain(
|
|
|
532
780
|
}
|
|
533
781
|
}
|
|
534
782
|
|
|
535
|
-
return
|
|
783
|
+
return enrichRoutingDecisionWithPinEconomics(
|
|
784
|
+
request,
|
|
785
|
+
enrichRoutingDecisionWithTierSelection(withContextFit, clusterMatchTable),
|
|
786
|
+
pinEconomicsOptionsFromExplain(options),
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function pinEconomicsOptionsFromExplain(
|
|
791
|
+
options?: ExplainEnrichmentOptions,
|
|
792
|
+
): Omit<PinEconomicsObservabilityInput, 'request' | 'decision'> {
|
|
793
|
+
return {
|
|
794
|
+
...(options?.fleet !== undefined ? { fleet: options.fleet } : {}),
|
|
795
|
+
...(options?.sessionPinner !== undefined
|
|
796
|
+
? { sessionPinner: options.sessionPinner }
|
|
797
|
+
: {}),
|
|
798
|
+
...(options?.saarConfig !== undefined ? { saarConfig: options.saarConfig } : {}),
|
|
799
|
+
};
|
|
536
800
|
}
|
|
537
801
|
|
|
538
802
|
/** Attach context-fit observability to a routing decision features sidecar (SP-110). */
|
|
@@ -575,17 +839,32 @@ export function buildRoutingDecisionLogPayload(
|
|
|
575
839
|
delegate?: RoutingDecisionLogDelegate,
|
|
576
840
|
fleet?: readonly ModelProfile[],
|
|
577
841
|
contextFitConfig?: ContextFitConfig,
|
|
842
|
+
pinEconomics?: Omit<PinEconomicsObservabilityInput, 'request' | 'decision' | 'fleet'>,
|
|
578
843
|
): Record<string, unknown> {
|
|
579
|
-
const enriched =
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
844
|
+
const enriched = enrichRoutingDecisionWithPinEconomics(
|
|
845
|
+
request,
|
|
846
|
+
enrichRoutingDecisionWithTierSelection(
|
|
847
|
+
enrichRoutingDecisionWithContextFit(
|
|
848
|
+
request,
|
|
849
|
+
decision,
|
|
850
|
+
fleet,
|
|
851
|
+
contextFitConfig,
|
|
852
|
+
),
|
|
585
853
|
),
|
|
854
|
+
{
|
|
855
|
+
...(fleet !== undefined ? { fleet } : {}),
|
|
856
|
+
...(pinEconomics?.sessionPinner !== undefined
|
|
857
|
+
? { sessionPinner: pinEconomics.sessionPinner }
|
|
858
|
+
: {}),
|
|
859
|
+
...(pinEconomics?.saarConfig !== undefined
|
|
860
|
+
? { saarConfig: pinEconomics.saarConfig }
|
|
861
|
+
: {}),
|
|
862
|
+
},
|
|
586
863
|
);
|
|
587
864
|
|
|
588
865
|
const tierSelection = enriched.features?.tier_selection;
|
|
866
|
+
const breakeven = enriched.features?.breakeven;
|
|
867
|
+
const saar = enriched.features?.saar;
|
|
589
868
|
|
|
590
869
|
return {
|
|
591
870
|
request_id: enriched.request_id,
|
|
@@ -606,6 +885,25 @@ export function buildRoutingDecisionLogPayload(
|
|
|
606
885
|
p_success_cheap: tierSelection.p_success_cheap,
|
|
607
886
|
}
|
|
608
887
|
: null,
|
|
888
|
+
breakeven_summary: breakeven
|
|
889
|
+
? {
|
|
890
|
+
marginal_savings: breakeven.marginal_savings,
|
|
891
|
+
future_cache_value: breakeven.future_cache_value,
|
|
892
|
+
cache_reprime_cost: breakeven.cache_reprime_cost,
|
|
893
|
+
decision: breakeven.decision,
|
|
894
|
+
breakeven_reason_code: breakeven.breakeven_reason_code,
|
|
895
|
+
}
|
|
896
|
+
: null,
|
|
897
|
+
saar_summary: saar
|
|
898
|
+
? {
|
|
899
|
+
buffer_active: saar.buffer_active,
|
|
900
|
+
hard_lock: saar.hard_lock,
|
|
901
|
+
turn_index_in_session: saar.turn_index_in_session,
|
|
902
|
+
planning_turn_buffer: saar.planning_turn_buffer,
|
|
903
|
+
idle_timeout_seconds: saar.idle_timeout_seconds,
|
|
904
|
+
saar_reason_code: saar.saar_reason_code,
|
|
905
|
+
}
|
|
906
|
+
: null,
|
|
609
907
|
delegate,
|
|
610
908
|
};
|
|
611
909
|
}
|
|
@@ -728,6 +1026,8 @@ export class RoutingTelemetryEmitter {
|
|
|
728
1026
|
private readonly onRecord: ((record: RoutingTelemetry) => void) | undefined;
|
|
729
1027
|
private readonly fleet: readonly ModelProfile[] | undefined;
|
|
730
1028
|
private readonly contextFitConfig: ContextFitConfig | undefined;
|
|
1029
|
+
private readonly sessionPinner: SessionPinner | undefined;
|
|
1030
|
+
private readonly saarConfig: SaarConfig | undefined;
|
|
731
1031
|
|
|
732
1032
|
constructor(options?: TelemetryEmitterOptions) {
|
|
733
1033
|
this.maxEntries = options?.maxEntries ?? TELEMETRY_MAX_ENTRIES;
|
|
@@ -736,6 +1036,8 @@ export class RoutingTelemetryEmitter {
|
|
|
736
1036
|
this.onRecord = options?.onRecord;
|
|
737
1037
|
this.fleet = options?.fleet;
|
|
738
1038
|
this.contextFitConfig = options?.contextFitConfig;
|
|
1039
|
+
this.sessionPinner = options?.sessionPinner;
|
|
1040
|
+
this.saarConfig = options?.saarConfig;
|
|
739
1041
|
}
|
|
740
1042
|
|
|
741
1043
|
/**
|
|
@@ -778,6 +1080,15 @@ export class RoutingTelemetryEmitter {
|
|
|
778
1080
|
});
|
|
779
1081
|
const contextFitFields = contextFit ?? defaultContextFitTelemetry();
|
|
780
1082
|
const tierSelectionFields = tierSelectionTelemetryFromDecision(decision);
|
|
1083
|
+
const pinEconomicsFields = pinEconomicsTelemetryFromInput({
|
|
1084
|
+
request,
|
|
1085
|
+
decision,
|
|
1086
|
+
...(this.fleet !== undefined ? { fleet: this.fleet } : {}),
|
|
1087
|
+
...(this.sessionPinner !== undefined
|
|
1088
|
+
? { sessionPinner: this.sessionPinner }
|
|
1089
|
+
: {}),
|
|
1090
|
+
...(this.saarConfig !== undefined ? { saarConfig: this.saarConfig } : {}),
|
|
1091
|
+
});
|
|
781
1092
|
|
|
782
1093
|
const record: RoutingTelemetry = {
|
|
783
1094
|
timestamp: this.clock(),
|
|
@@ -804,6 +1115,15 @@ export class RoutingTelemetryEmitter {
|
|
|
804
1115
|
p_success_cheap: tierSelectionFields.p_success_cheap,
|
|
805
1116
|
local_eligible_reason: tierSelectionFields.local_eligible_reason,
|
|
806
1117
|
tier_selection_reason_code: tierSelectionFields.tier_selection_reason_code,
|
|
1118
|
+
marginal_savings: pinEconomicsFields.marginal_savings,
|
|
1119
|
+
future_cache_value: pinEconomicsFields.future_cache_value,
|
|
1120
|
+
cache_reprime_cost: pinEconomicsFields.cache_reprime_cost,
|
|
1121
|
+
breakeven_decision: pinEconomicsFields.breakeven_decision,
|
|
1122
|
+
breakeven_reason_code: pinEconomicsFields.breakeven_reason_code,
|
|
1123
|
+
saar_buffer_active: pinEconomicsFields.saar_buffer_active,
|
|
1124
|
+
saar_hard_lock: pinEconomicsFields.saar_hard_lock,
|
|
1125
|
+
turn_index_in_session: pinEconomicsFields.turn_index_in_session,
|
|
1126
|
+
saar_reason_code: pinEconomicsFields.saar_reason_code,
|
|
807
1127
|
};
|
|
808
1128
|
|
|
809
1129
|
this.entries.push(record);
|