@mupt-ai/dari-router 0.1.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.
Files changed (179) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +100 -0
  3. package/dist/anonymous_actions.d.ts +55 -0
  4. package/dist/anonymous_actions.js +277 -0
  5. package/dist/anonymous_actions.js.map +1 -0
  6. package/dist/auto_router.d.ts +10 -0
  7. package/dist/auto_router.js +56 -0
  8. package/dist/auto_router.js.map +1 -0
  9. package/dist/cache_behavior.d.ts +14 -0
  10. package/dist/cache_behavior.js +112 -0
  11. package/dist/cache_behavior.js.map +1 -0
  12. package/dist/cache_scope.d.ts +5 -0
  13. package/dist/cache_scope.js +49 -0
  14. package/dist/cache_scope.js.map +1 -0
  15. package/dist/cache_switch_decision.d.ts +24 -0
  16. package/dist/cache_switch_decision.js +21 -0
  17. package/dist/cache_switch_decision.js.map +1 -0
  18. package/dist/candidate_pruning.d.ts +45 -0
  19. package/dist/candidate_pruning.js +154 -0
  20. package/dist/candidate_pruning.js.map +1 -0
  21. package/dist/candidate_resolution.d.ts +41 -0
  22. package/dist/candidate_resolution.js +111 -0
  23. package/dist/candidate_resolution.js.map +1 -0
  24. package/dist/compatibility.d.ts +22 -0
  25. package/dist/compatibility.js +76 -0
  26. package/dist/compatibility.js.map +1 -0
  27. package/dist/continuation_state.d.ts +36 -0
  28. package/dist/continuation_state.js +249 -0
  29. package/dist/continuation_state.js.map +1 -0
  30. package/dist/cost.d.ts +31 -0
  31. package/dist/cost.js +314 -0
  32. package/dist/cost.js.map +1 -0
  33. package/dist/dari_policy.d.ts +34 -0
  34. package/dist/dari_policy.js +267 -0
  35. package/dist/dari_policy.js.map +1 -0
  36. package/dist/errors.d.ts +7 -0
  37. package/dist/errors.js +14 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/fingerprint.d.ts +13 -0
  40. package/dist/fingerprint.js +130 -0
  41. package/dist/fingerprint.js.map +1 -0
  42. package/dist/fixed_turn_cost_config.d.ts +9 -0
  43. package/dist/fixed_turn_cost_config.js +22 -0
  44. package/dist/fixed_turn_cost_config.js.map +1 -0
  45. package/dist/framework_error.d.ts +8 -0
  46. package/dist/framework_error.js +24 -0
  47. package/dist/framework_error.js.map +1 -0
  48. package/dist/framework_lifecycle.d.ts +11 -0
  49. package/dist/framework_lifecycle.js +57 -0
  50. package/dist/framework_lifecycle.js.map +1 -0
  51. package/dist/framework_models.d.ts +3 -0
  52. package/dist/framework_models.js +120 -0
  53. package/dist/framework_models.js.map +1 -0
  54. package/dist/framework_router.d.ts +2 -0
  55. package/dist/framework_router.js +384 -0
  56. package/dist/framework_router.js.map +1 -0
  57. package/dist/framework_streaming.d.ts +26 -0
  58. package/dist/framework_streaming.js +486 -0
  59. package/dist/framework_streaming.js.map +1 -0
  60. package/dist/framework_types.d.ts +272 -0
  61. package/dist/framework_types.js +5 -0
  62. package/dist/framework_types.js.map +1 -0
  63. package/dist/framework_validation.d.ts +7 -0
  64. package/dist/framework_validation.js +169 -0
  65. package/dist/framework_validation.js.map +1 -0
  66. package/dist/index.d.ts +35 -0
  67. package/dist/index.js +38 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/json.d.ts +10 -0
  70. package/dist/json.js +29 -0
  71. package/dist/json.js.map +1 -0
  72. package/dist/model_ids.d.ts +4 -0
  73. package/dist/model_ids.js +26 -0
  74. package/dist/model_ids.js.map +1 -0
  75. package/dist/pi_context.d.ts +4 -0
  76. package/dist/pi_context.js +206 -0
  77. package/dist/pi_context.js.map +1 -0
  78. package/dist/pi_options.d.ts +3 -0
  79. package/dist/pi_options.js +240 -0
  80. package/dist/pi_options.js.map +1 -0
  81. package/dist/pi_output.d.ts +4 -0
  82. package/dist/pi_output.js +328 -0
  83. package/dist/pi_output.js.map +1 -0
  84. package/dist/pi_reasoning_signature.d.ts +10 -0
  85. package/dist/pi_reasoning_signature.js +33 -0
  86. package/dist/pi_reasoning_signature.js.map +1 -0
  87. package/dist/pi_runtime.d.ts +3 -0
  88. package/dist/pi_runtime.js +155 -0
  89. package/dist/pi_runtime.js.map +1 -0
  90. package/dist/pi_types.d.ts +35 -0
  91. package/dist/pi_types.js +2 -0
  92. package/dist/pi_types.js.map +1 -0
  93. package/dist/portable_reasoning_state.d.ts +7 -0
  94. package/dist/portable_reasoning_state.js +81 -0
  95. package/dist/portable_reasoning_state.js.map +1 -0
  96. package/dist/previous_decision.d.ts +13 -0
  97. package/dist/previous_decision.js +82 -0
  98. package/dist/previous_decision.js.map +1 -0
  99. package/dist/prompts.d.ts +3 -0
  100. package/dist/prompts.js +65 -0
  101. package/dist/prompts.js.map +1 -0
  102. package/dist/protocol_anthropic.d.ts +18 -0
  103. package/dist/protocol_anthropic.js +443 -0
  104. package/dist/protocol_anthropic.js.map +1 -0
  105. package/dist/protocol_openai_chat.d.ts +25 -0
  106. package/dist/protocol_openai_chat.js +503 -0
  107. package/dist/protocol_openai_chat.js.map +1 -0
  108. package/dist/protocol_validation.d.ts +23 -0
  109. package/dist/protocol_validation.js +134 -0
  110. package/dist/protocol_validation.js.map +1 -0
  111. package/dist/route.d.ts +105 -0
  112. package/dist/route.js +226 -0
  113. package/dist/route.js.map +1 -0
  114. package/dist/routing_history.d.ts +7 -0
  115. package/dist/routing_history.js +132 -0
  116. package/dist/routing_history.js.map +1 -0
  117. package/dist/selector_input.d.ts +42 -0
  118. package/dist/selector_input.js +153 -0
  119. package/dist/selector_input.js.map +1 -0
  120. package/dist/selector_parse.d.ts +13 -0
  121. package/dist/selector_parse.js +95 -0
  122. package/dist/selector_parse.js.map +1 -0
  123. package/dist/selector_request.d.ts +26 -0
  124. package/dist/selector_request.js +85 -0
  125. package/dist/selector_request.js.map +1 -0
  126. package/dist/selector_truncation.d.ts +2 -0
  127. package/dist/selector_truncation.js +48 -0
  128. package/dist/selector_truncation.js.map +1 -0
  129. package/dist/selector_wire.d.ts +10 -0
  130. package/dist/selector_wire.js +113 -0
  131. package/dist/selector_wire.js.map +1 -0
  132. package/dist/types.d.ts +152 -0
  133. package/dist/types.js +14 -0
  134. package/dist/types.js.map +1 -0
  135. package/package.json +64 -0
  136. package/src/anonymous_actions.ts +434 -0
  137. package/src/auto_router.ts +95 -0
  138. package/src/cache_behavior.ts +130 -0
  139. package/src/cache_scope.ts +58 -0
  140. package/src/cache_switch_decision.ts +53 -0
  141. package/src/candidate_pruning.ts +257 -0
  142. package/src/candidate_resolution.ts +208 -0
  143. package/src/compatibility.ts +162 -0
  144. package/src/continuation_state.ts +368 -0
  145. package/src/cost.ts +455 -0
  146. package/src/dari_policy.ts +360 -0
  147. package/src/errors.ts +27 -0
  148. package/src/fingerprint.ts +148 -0
  149. package/src/fixed_turn_cost_config.ts +24 -0
  150. package/src/framework_error.ts +38 -0
  151. package/src/framework_lifecycle.ts +74 -0
  152. package/src/framework_models.ts +186 -0
  153. package/src/framework_router.ts +490 -0
  154. package/src/framework_streaming.ts +613 -0
  155. package/src/framework_types.ts +372 -0
  156. package/src/framework_validation.ts +235 -0
  157. package/src/index.ts +37 -0
  158. package/src/json.ts +43 -0
  159. package/src/model_ids.ts +29 -0
  160. package/src/pi_context.ts +251 -0
  161. package/src/pi_options.ts +295 -0
  162. package/src/pi_output.ts +387 -0
  163. package/src/pi_reasoning_signature.ts +41 -0
  164. package/src/pi_runtime.ts +238 -0
  165. package/src/pi_types.ts +71 -0
  166. package/src/portable_reasoning_state.ts +129 -0
  167. package/src/previous_decision.ts +109 -0
  168. package/src/prompts.ts +69 -0
  169. package/src/protocol_anthropic.ts +571 -0
  170. package/src/protocol_openai_chat.ts +645 -0
  171. package/src/protocol_validation.ts +202 -0
  172. package/src/route.ts +490 -0
  173. package/src/routing_history.ts +157 -0
  174. package/src/selector_input.ts +246 -0
  175. package/src/selector_parse.ts +138 -0
  176. package/src/selector_request.ts +130 -0
  177. package/src/selector_truncation.ts +48 -0
  178. package/src/selector_wire.ts +167 -0
  179. package/src/types.ts +231 -0
@@ -0,0 +1,42 @@
1
+ import { type CandidateCostEstimate, type ChatMessage, type CustomRouterRule, type PreviousDecision, type ReasoningEffort, type RouterEval, type RoutingCandidate } from "./types.js";
2
+ type SelectorCandidate = {
3
+ model: string;
4
+ thinking_level: RoutingCandidate["reasoningEffort"];
5
+ };
6
+ type SelectorPreviousDecision = SelectorCandidate & {
7
+ reason: string;
8
+ };
9
+ export type SelectorInput = {
10
+ candidate_pairs: SelectorCandidate[];
11
+ imported_evals: Array<Record<string, unknown>>;
12
+ previous_decision: SelectorPreviousDecision | null;
13
+ cost_estimates: CandidateCostEstimate[] | null;
14
+ messages: ChatMessage[];
15
+ };
16
+ type SelectorCustomRule = Omit<CustomRouterRule, "thinking_level"> & {
17
+ thinking_level: ReasoningEffort | null;
18
+ };
19
+ export type CustomSelectorInput = SelectorInput & {
20
+ custom_rules: SelectorCustomRule[];
21
+ default_target: {
22
+ model: string;
23
+ thinking_level: ReasoningEffort | null;
24
+ } | null;
25
+ };
26
+ export declare function selectorSafeMessages(messages: ChatMessage[]): ChatMessage[];
27
+ export declare function buildSelectorInput(args: {
28
+ candidates: RoutingCandidate[];
29
+ evals: RouterEval[];
30
+ previousDecision: PreviousDecision | null;
31
+ costEstimates: CandidateCostEstimate[] | null;
32
+ messages: ChatMessage[];
33
+ customRules?: CustomRouterRule[];
34
+ defaultTarget?: {
35
+ model: string;
36
+ thinkingLevel: ReasoningEffort | null;
37
+ } | null;
38
+ modelFallbackEnabled?: boolean;
39
+ fallbackRequiresDifferentProvider?: boolean;
40
+ imputeEvalScores?: boolean;
41
+ }): SelectorInput | CustomSelectorInput;
42
+ export {};
@@ -0,0 +1,153 @@
1
+ // Builds the selector input: candidate pairs, matched eval scores, cost
2
+ // estimates, the previous decision, and the (image-scrubbed) conversation.
3
+ // The system prompts live in prompts.ts.
4
+ import { isRecord, REASONING_EFFORTS, routingCandidateKey, } from "./types.js";
5
+ const IMAGE_OMITTED_PLACEHOLDER = "<image omitted>";
6
+ // Selector serialization must not include image bytes. The provider-facing
7
+ // request and prefix fingerprint still use the original content, while this
8
+ // stable placeholder preserves the selector's own prompt cache behavior.
9
+ export function selectorSafeMessages(messages) {
10
+ return messages.map((message) => {
11
+ if (!Array.isArray(message.content))
12
+ return message;
13
+ return {
14
+ ...message,
15
+ content: message.content.map((part) => isRecord(part) && part.type === "image_url"
16
+ ? { type: "image_url", image_url: { url: IMAGE_OMITTED_PLACEHOLDER } }
17
+ : part),
18
+ };
19
+ });
20
+ }
21
+ export function buildSelectorInput(args) {
22
+ const input = {
23
+ candidate_pairs: args.candidates.map(({ model, reasoningEffort }) => ({
24
+ model,
25
+ thinking_level: reasoningEffort,
26
+ })),
27
+ imported_evals: formatImportedEvals(args.evals, args.candidates, args.imputeEvalScores ?? false),
28
+ previous_decision: args.previousDecision
29
+ ? {
30
+ model: args.previousDecision.model,
31
+ thinking_level: args.previousDecision.reasoningEffort,
32
+ reason: args.previousDecision.reason,
33
+ }
34
+ : null,
35
+ cost_estimates: args.costEstimates,
36
+ messages: args.messages,
37
+ };
38
+ if (args.customRules !== undefined) {
39
+ input.custom_rules = args.customRules.map((rule) => ({
40
+ ...rule,
41
+ thinking_level: rule.thinking_level ?? null,
42
+ }));
43
+ input.default_target = args.defaultTarget
44
+ ? {
45
+ model: args.defaultTarget.model,
46
+ thinking_level: args.defaultTarget.thinkingLevel,
47
+ }
48
+ : null;
49
+ }
50
+ return input;
51
+ }
52
+ function formatImportedEvals(evals, candidates, imputeEvalScores) {
53
+ return evals.flatMap((evalCard) => {
54
+ const scores = matchingEvalScores(evalCard.scores, candidates, imputeEvalScores);
55
+ if (scores.length === 0)
56
+ return [];
57
+ return [
58
+ {
59
+ id: evalCard.id,
60
+ name: evalCard.name,
61
+ description: evalCard.description ?? null,
62
+ min_score: evalCard.min_score,
63
+ max_score: evalCard.max_score,
64
+ scores,
65
+ },
66
+ ];
67
+ });
68
+ }
69
+ function matchingEvalScores(scores, candidates, imputeEvalScores) {
70
+ const uniqueCandidates = new Map(candidates.map((candidate) => [routingCandidateKey(candidate), candidate]));
71
+ return [...uniqueCandidates.values()].flatMap((candidate) => {
72
+ const modelScores = scores.filter((score) => score.model_id === candidate.model);
73
+ const exact = modelScores.find((score) => score.thinking_level === candidate.reasoningEffort);
74
+ const generic = modelScores.find((score) => score.thinking_level == null);
75
+ const match = exact ?? generic;
76
+ if (match) {
77
+ return [
78
+ {
79
+ model_id: candidate.model,
80
+ thinking_level: candidate.reasoningEffort,
81
+ score: match.score,
82
+ ...normalizedScore(match.score, scores),
83
+ notes: match.notes ?? null,
84
+ },
85
+ ];
86
+ }
87
+ if (!imputeEvalScores)
88
+ return [];
89
+ const imputed = interpolatedScore(candidate, modelScores);
90
+ if (imputed === null)
91
+ return [];
92
+ return [
93
+ {
94
+ model_id: candidate.model,
95
+ thinking_level: candidate.reasoningEffort,
96
+ score: imputed,
97
+ ...normalizedScore(imputed, scores),
98
+ notes: null,
99
+ imputed: true,
100
+ },
101
+ ];
102
+ });
103
+ }
104
+ // Linear interpolation between the two per-level scores that bracket the
105
+ // requested thinking level. A single known level (or zero) is not enough to
106
+ // pin a line, so we only interpolate when the candidate has scores on both
107
+ // sides of the requested level; one-sided cases stay empty.
108
+ function interpolatedScore(candidate, modelScores) {
109
+ const requestedIndex = REASONING_EFFORTS.indexOf(candidate.reasoningEffort);
110
+ if (requestedIndex < 0)
111
+ return null;
112
+ let below = null;
113
+ let above = null;
114
+ for (const entry of modelScores) {
115
+ if (entry.thinking_level == null)
116
+ continue;
117
+ const index = REASONING_EFFORTS.indexOf(entry.thinking_level);
118
+ if (index < 0)
119
+ continue;
120
+ if (index < requestedIndex && (below === null || index > below.index)) {
121
+ below = { index, score: entry.score };
122
+ }
123
+ else if (index > requestedIndex &&
124
+ (above === null || index < above.index)) {
125
+ above = { index, score: entry.score };
126
+ }
127
+ }
128
+ if (below === null || above === null)
129
+ return null;
130
+ const ratio = (requestedIndex - below.index) / (above.index - below.index);
131
+ return round2(below.score + (above.score - below.score) * ratio);
132
+ }
133
+ // Positions a candidate's score against every model on the scorecard, not just
134
+ // the candidates that survived pruning. Candidate-relative normalization would
135
+ // move with the pruned set (with two candidates a z-score is always +/-1), so
136
+ // the selector would read pure ordering as if it carried magnitude.
137
+ function normalizedScore(score, population) {
138
+ const values = population.map((entry) => entry.score);
139
+ const mean = values.reduce((total, value) => total + value, 0) / values.length;
140
+ const variance = values.reduce((total, value) => total + (value - mean) ** 2, 0) /
141
+ values.length;
142
+ const stdDev = Math.sqrt(variance);
143
+ return {
144
+ // Competition ranking, best score first; tied scores share the low rank.
145
+ rank: 1 + values.filter((value) => value > score).length,
146
+ rank_total: values.length,
147
+ z_score: stdDev === 0 ? 0 : round2((score - mean) / stdDev),
148
+ };
149
+ }
150
+ function round2(value) {
151
+ return Math.round(value * 100) / 100;
152
+ }
153
+ //# sourceMappingURL=selector_input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector_input.js","sourceRoot":"","sources":["../src/selector_input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type RoutingCandidate, type RoutingDecision } from "./types.js";
2
+ export type ParsedSelectorDecision = {
3
+ decision: RoutingDecision;
4
+ fallbackDecision?: RoutingDecision;
5
+ };
6
+ export declare function parseSelectorDecision(text: string): ParsedSelectorDecision;
7
+ export declare function validateSelectorDecisions(args: {
8
+ decision: RoutingDecision;
9
+ fallbackDecision?: RoutingDecision;
10
+ candidates: RoutingCandidate[];
11
+ modelFallbackEnabled?: boolean;
12
+ fallbackRequiresDifferentProvider?: boolean;
13
+ }): void;
@@ -0,0 +1,95 @@
1
+ import { RouterCoreError } from "./errors.js";
2
+ import { providerForModel } from "./model_ids.js";
3
+ import { isReasoningEffort, sameRoutingCandidate, } from "./types.js";
4
+ // Parses the selector's raw output text into a routing decision (plus an
5
+ // optional fallback). Tolerates a fenced ```json block; everything else must
6
+ // be strict JSON matching the routing_decision schema.
7
+ export function parseSelectorDecision(text) {
8
+ const trimmed = text.trim().replace(/^```json\s*/i, "").replace(/^```\s*/i, "").replace(/```$/i, "").trim();
9
+ let parsed;
10
+ try {
11
+ parsed = JSON.parse(trimmed);
12
+ }
13
+ catch {
14
+ throw new RouterCoreError("selector_output", "Selector returned invalid JSON.", "selector_invalid_json");
15
+ }
16
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
17
+ throw new RouterCoreError("selector_output", "Selector returned invalid routing decision.", "selector_invalid_response");
18
+ }
19
+ const record = parsed;
20
+ if (typeof record.selected_model !== "string" || record.selected_model === "") {
21
+ throw new RouterCoreError("selector_output", "Selector response missing selected_model.", "selector_invalid_response");
22
+ }
23
+ if (!isReasoningEffort(record.reasoning_effort)) {
24
+ throw new RouterCoreError("selector_output", "Selector response missing a valid reasoning_effort.", "selector_invalid_response");
25
+ }
26
+ const reason = typeof record.reason === "string" ? record.reason.trim() : "";
27
+ const leaseTurnsRemaining = typeof record.lease_turns_remaining === "number" && Number.isFinite(record.lease_turns_remaining)
28
+ ? Math.trunc(record.lease_turns_remaining)
29
+ : undefined;
30
+ const decision = {
31
+ selectedModel: record.selected_model,
32
+ reasoningEffort: record.reasoning_effort,
33
+ reason: reason ||
34
+ `Selector selected ${record.selected_model}/${record.reasoning_effort}; no reason was provided.`,
35
+ ...(leaseTurnsRemaining === undefined ? {} : { leaseTurnsRemaining }),
36
+ };
37
+ const fallbackModel = record.fallback_model;
38
+ const fallbackEffort = record.fallback_reasoning_effort;
39
+ const fallbackReason = record.fallback_reason;
40
+ // Selectors that decline a fallback often still explain why in
41
+ // fallback_reason; a missing fallback_model alone means "no fallback".
42
+ const noFallback = fallbackModel === null || fallbackModel === undefined;
43
+ if (noFallback)
44
+ return { decision };
45
+ if (typeof fallbackModel !== "string" ||
46
+ !fallbackModel ||
47
+ !isReasoningEffort(fallbackEffort) ||
48
+ (fallbackReason !== undefined &&
49
+ fallbackReason !== null &&
50
+ typeof fallbackReason !== "string")) {
51
+ throw new RouterCoreError("selector_output", "Selector response contains an incomplete fallback decision.", "selector_invalid_response");
52
+ }
53
+ const normalizedFallbackReason = fallbackReason?.trim() ?? "";
54
+ return {
55
+ decision,
56
+ fallbackDecision: {
57
+ selectedModel: fallbackModel,
58
+ reasoningEffort: fallbackEffort,
59
+ reason: normalizedFallbackReason ||
60
+ `Selector ranked ${fallbackModel}/${fallbackEffort} as the fallback; no reason was provided.`,
61
+ },
62
+ };
63
+ }
64
+ // Validates a parsed selector decision against the candidate set and fallback
65
+ // policy: the selection must be a real candidate pair, and when fallback is
66
+ // enabled a fallback must be present whenever an eligible one exists and must
67
+ // itself be an eligible candidate on a distinct model (and provider, when
68
+ // required).
69
+ export function validateSelectorDecisions(args) {
70
+ const selected = {
71
+ model: args.decision.selectedModel,
72
+ reasoningEffort: args.decision.reasoningEffort,
73
+ };
74
+ if (!args.candidates.some((candidate) => sameRoutingCandidate(candidate, selected))) {
75
+ throw new RouterCoreError("selector_output", "Selector returned a model/thinking-level pair outside this router's candidates.", "selector_invalid_candidate");
76
+ }
77
+ const eligibleFallbacks = args.candidates.filter((candidate) => candidate.model !== selected.model &&
78
+ (!args.fallbackRequiresDifferentProvider ||
79
+ providerForModel(candidate.model) !== providerForModel(selected.model)));
80
+ if (args.modelFallbackEnabled) {
81
+ if (!args.fallbackDecision && eligibleFallbacks.length > 0) {
82
+ throw new RouterCoreError("selector_output", "Selector response missing an eligible fallback model.", "selector_invalid_response");
83
+ }
84
+ if (args.fallbackDecision) {
85
+ const fallback = {
86
+ model: args.fallbackDecision.selectedModel,
87
+ reasoningEffort: args.fallbackDecision.reasoningEffort,
88
+ };
89
+ if (!eligibleFallbacks.some((candidate) => sameRoutingCandidate(candidate, fallback))) {
90
+ throw new RouterCoreError("selector_output", "Selector returned an ineligible fallback model/thinking-level pair.", "selector_invalid_candidate");
91
+ }
92
+ }
93
+ }
94
+ }
95
+ //# sourceMappingURL=selector_parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector_parse.js","sourceRoot":"","sources":["../src/selector_parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { type CustomSelectorInput, type SelectorInput } from "./selector_input.js";
2
+ import type { CandidateCostEstimate, ChatCompletionRequest, ChatMessage, CustomRouterRule, PreviousDecision, ReasoningEffort, RouterEval, RoutingCandidate } from "./types.js";
3
+ export type BuiltSelectorRequest = {
4
+ selectorInput: SelectorInput | CustomSelectorInput;
5
+ selectorRequest: ChatCompletionRequest;
6
+ };
7
+ export type SelectorRequestArgs = {
8
+ candidates: RoutingCandidate[];
9
+ evals?: RouterEval[];
10
+ previousDecision?: PreviousDecision;
11
+ costEstimates?: CandidateCostEstimate[];
12
+ customRules?: CustomRouterRule[];
13
+ defaultTarget?: {
14
+ model: string;
15
+ thinkingLevel: ReasoningEffort | null;
16
+ } | null;
17
+ selectorModel: string;
18
+ messages: ChatMessage[];
19
+ modelFallbackEnabled?: boolean;
20
+ fallbackRequiresDifferentProvider?: boolean;
21
+ imputeEvalScores?: boolean;
22
+ };
23
+ export declare function buildSizedSelectorRequest(args: SelectorRequestArgs & {
24
+ contextWindowChars: number;
25
+ }): BuiltSelectorRequest;
26
+ export declare function buildSelectorRequest(args: SelectorRequestArgs): BuiltSelectorRequest;
@@ -0,0 +1,85 @@
1
+ import { RouterCoreError } from "./errors.js";
2
+ import { CUSTOM_SELECTOR_SYSTEM_PROMPT, SELECTOR_SYSTEM_PROMPT } from "./prompts.js";
3
+ import { buildSelectorInput, } from "./selector_input.js";
4
+ import { trimMessagesFromFront } from "./selector_truncation.js";
5
+ import { REASONING_EFFORTS } from "./types.js";
6
+ // Builds the selector request, front-trimming conversation messages until the
7
+ // serialized prompt fits the selector's context window. The window size is an
8
+ // explicit input (in characters) so the core stays free of model-registry
9
+ // lookups.
10
+ export function buildSizedSelectorRequest(args) {
11
+ let messages = args.messages;
12
+ let built = buildSelectorRequest({ ...args, messages });
13
+ let previousInputChars = Number.POSITIVE_INFINITY;
14
+ while (true) {
15
+ const inputChars = selectorRequestInputChars(built.selectorRequest);
16
+ if (inputChars <= args.contextWindowChars)
17
+ return built;
18
+ if (inputChars >= previousInputChars) {
19
+ throw new RouterCoreError("configuration", `Selector prompt cannot fit configured context window for ${args.selectorModel}.`, "configuration_error");
20
+ }
21
+ previousInputChars = inputChars;
22
+ messages = trimMessagesFromFront(messages, inputChars - args.contextWindowChars);
23
+ built = buildSelectorRequest({ ...args, messages });
24
+ }
25
+ }
26
+ function selectorRequestInputChars(request) {
27
+ return JSON.stringify(request.messages ?? []).length;
28
+ }
29
+ export function buildSelectorRequest(args) {
30
+ const isCustom = args.customRules !== undefined;
31
+ const selectorInput = buildSelectorInput({
32
+ candidates: args.candidates,
33
+ evals: args.evals ?? [],
34
+ previousDecision: args.previousDecision ?? null,
35
+ costEstimates: args.costEstimates ?? null,
36
+ messages: args.messages,
37
+ customRules: args.customRules,
38
+ defaultTarget: args.defaultTarget,
39
+ modelFallbackEnabled: args.modelFallbackEnabled,
40
+ fallbackRequiresDifferentProvider: args.fallbackRequiresDifferentProvider,
41
+ imputeEvalScores: args.imputeEvalScores,
42
+ });
43
+ return {
44
+ selectorInput,
45
+ selectorRequest: {
46
+ model: args.selectorModel,
47
+ messages: [
48
+ { role: "system", content: isCustom ? CUSTOM_SELECTOR_SYSTEM_PROMPT : SELECTOR_SYSTEM_PROMPT },
49
+ {
50
+ role: "user",
51
+ content: JSON.stringify(selectorInput),
52
+ },
53
+ ],
54
+ // The selector is an internal fixed-purpose JSON pick; it must not inherit
55
+ // the client-facing implicit-medium reasoning default. Selector models
56
+ // must support a true off mode.
57
+ reasoning_effort: "off",
58
+ response_format: {
59
+ type: "json_schema",
60
+ json_schema: {
61
+ name: "routing_decision",
62
+ strict: true,
63
+ schema: {
64
+ type: "object",
65
+ additionalProperties: false,
66
+ properties: {
67
+ selected_model: { type: "string" },
68
+ reasoning_effort: {
69
+ type: "string",
70
+ enum: [...REASONING_EFFORTS],
71
+ },
72
+ reason: { type: "string" },
73
+ },
74
+ required: [
75
+ "selected_model",
76
+ "reasoning_effort",
77
+ "reason",
78
+ ],
79
+ },
80
+ },
81
+ },
82
+ },
83
+ };
84
+ }
85
+ //# sourceMappingURL=selector_request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector_request.js","sourceRoot":"","sources":["../src/selector_request.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { type ChatMessage } from "./types.js";
2
+ export declare function trimMessagesFromFront(messages: ChatMessage[], dropChars: number): ChatMessage[];
@@ -0,0 +1,48 @@
1
+ // Selector prompt sizing. The selector can see a front-trimmed view of the
2
+ // conversation; the eventual provider call still receives the full request.
3
+ import { isRecord } from "./types.js";
4
+ const SELECTOR_TRUNCATION_MARKER = "<earlier messages truncated for routing>";
5
+ const MARKER_MESSAGE = { role: "user", content: SELECTOR_TRUNCATION_MARKER };
6
+ // Drop oldest messages first — in multi-turn conversations the latest
7
+ // messages carry the routing signal.
8
+ export function trimMessagesFromFront(messages, dropChars) {
9
+ const targetLength = Math.max(0, JSON.stringify(messages).length - Math.max(0, dropChars));
10
+ const kept = [...messages];
11
+ while (kept.length > 1 && JSON.stringify([MARKER_MESSAGE, ...kept]).length > targetLength) {
12
+ kept.shift();
13
+ }
14
+ const marked = [MARKER_MESSAGE, ...kept];
15
+ if (JSON.stringify(marked).length <= targetLength)
16
+ return marked;
17
+ if (kept.length === 1) {
18
+ const first = kept[0];
19
+ const trimmableContent = trimSourceContent(first);
20
+ if (trimmableContent === null)
21
+ return [MARKER_MESSAGE];
22
+ const prefix = `${SELECTOR_TRUNCATION_MARKER}\n`;
23
+ let content = `${prefix}${trimmableContent}`;
24
+ while (content.length > prefix.length) {
25
+ const excess = JSON.stringify([{ ...first, content }]).length - targetLength;
26
+ if (excess <= 0)
27
+ break;
28
+ content = `${prefix}${content.slice(prefix.length + excess)}`;
29
+ }
30
+ return [{ ...first, content }];
31
+ }
32
+ return [MARKER_MESSAGE];
33
+ }
34
+ function trimSourceContent(message) {
35
+ if (typeof message.content === "string")
36
+ return message.content;
37
+ if (!Array.isArray(message.content))
38
+ return null;
39
+ return message.content.map(formatContentPartForTrim).join("\n");
40
+ }
41
+ function formatContentPartForTrim(part) {
42
+ if (isRecord(part) && part.type === "text" && typeof part.text === "string")
43
+ return part.text;
44
+ if (isRecord(part) && part.type === "image_url")
45
+ return "<image omitted>";
46
+ return JSON.stringify(part);
47
+ }
48
+ //# sourceMappingURL=selector_truncation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector_truncation.js","sourceRoot":"","sources":["../src/selector_truncation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type Rng } from "./anonymous_actions.js";
2
+ import type { SelectorInput } from "./selector_input.js";
3
+ import { type PreviousDecision, type RoutingCandidate } from "./types.js";
4
+ export type DecodedSelectorRequest = {
5
+ candidates: RoutingCandidate[];
6
+ previousDecision?: PreviousDecision;
7
+ selectorInput: SelectorInput;
8
+ };
9
+ export declare function decodeUntrustedSelectorRequest(payload: unknown): DecodedSelectorRequest;
10
+ export declare function assertAnonymizableSelectorInput(selectorInput: SelectorInput, candidates: RoutingCandidate[], rng?: Rng): void;
@@ -0,0 +1,113 @@
1
+ // Inverse codec for the selector-request wire format buildSelectorRequest
2
+ // produces: the selector input travels as a JSON-stringified user message
3
+ // inside a chat-completion request.
4
+ import { anonymizeSelectorInput, assignAnonymousActions, } from "./anonymous_actions.js";
5
+ import { RouterFrameworkError } from "./framework_error.js";
6
+ import { isReasoningEffort, isRecord, routingCandidateKey, } from "./types.js";
7
+ // Decodes an untrusted POSTed selector request body; throws kind
8
+ // "invalid_request" on malformed input.
9
+ export function decodeUntrustedSelectorRequest(payload) {
10
+ const selectorInput = parseSelectorInput(payload);
11
+ const candidates = [];
12
+ const seenPairs = new Set();
13
+ for (const [index, pair] of selectorInput.candidate_pairs.entries()) {
14
+ const param = `candidate_pairs[${index}]`;
15
+ if (!isRecord(pair)) {
16
+ throw invalidSelectorRequest("Selector candidate must be an object.", param);
17
+ }
18
+ const candidate = parseCandidatePair(pair, "candidate", param);
19
+ const key = routingCandidateKey(candidate);
20
+ if (seenPairs.has(key)) {
21
+ throw invalidSelectorRequest(`Selector input contains duplicate candidate ${candidate.model}/${candidate.reasoningEffort}.`, param);
22
+ }
23
+ seenPairs.add(key);
24
+ candidates.push(candidate);
25
+ }
26
+ const previousDecision = parsePreviousDecision(selectorInput.previous_decision);
27
+ if (candidates.length === 0) {
28
+ throw invalidSelectorRequest("Selector request contains no candidates.");
29
+ }
30
+ return { candidates, ...(previousDecision !== undefined ? { previousDecision } : {}), selectorInput };
31
+ }
32
+ // anonymizeSelectorInput's validators throw plain Errors; dry-run it here so
33
+ // malformed input surfaces as invalid_request instead of an internal error.
34
+ export function assertAnonymizableSelectorInput(selectorInput, candidates, rng = Math.random) {
35
+ if (candidates.length < 2)
36
+ return;
37
+ try {
38
+ anonymizeSelectorInput(selectorInput, assignAnonymousActions(candidates, rng));
39
+ }
40
+ catch (error) {
41
+ throw invalidSelectorRequest(`Selector input is invalid: ${error instanceof Error ? error.message : String(error)}`);
42
+ }
43
+ }
44
+ function parsePreviousDecision(value) {
45
+ if (value === null || value === undefined)
46
+ return undefined;
47
+ if (!isRecord(value)) {
48
+ throw invalidSelectorRequest("Selector previous_decision must be an object or null.", "previous_decision");
49
+ }
50
+ const candidate = parseCandidatePair(value, "previous_decision", "previous_decision");
51
+ if (typeof value.reason !== "string") {
52
+ throw invalidSelectorRequest("Selector previous_decision reason must be a string.", "previous_decision.reason");
53
+ }
54
+ return { ...candidate, reason: value.reason };
55
+ }
56
+ function parseCandidatePair(value, subject, param) {
57
+ if (typeof value.model !== "string" || value.model === "") {
58
+ throw invalidSelectorRequest(`Selector ${subject} is missing a model name.`, `${param}.model`);
59
+ }
60
+ if (!isReasoningEffort(value.thinking_level)) {
61
+ throw invalidSelectorRequest(`Selector ${subject} has invalid thinking_level: ${String(value.thinking_level)}`, `${param}.thinking_level`);
62
+ }
63
+ return { model: value.model, reasoningEffort: value.thinking_level };
64
+ }
65
+ function parseSelectorInput(payload) {
66
+ if (!isRecord(payload)) {
67
+ throw invalidSelectorRequest("Selector request must be a JSON object.");
68
+ }
69
+ const messages = payload.messages ?? [];
70
+ if (!Array.isArray(messages)) {
71
+ throw invalidSelectorRequest("Selector request messages must be an array.", "messages");
72
+ }
73
+ const userMessage = messages.find((message) => isRecord(message) && message.role === "user");
74
+ if (userMessage === undefined) {
75
+ throw invalidSelectorRequest("Selector request is missing the user message.");
76
+ }
77
+ const content = userMessage.content;
78
+ if (typeof content !== "string") {
79
+ throw invalidSelectorRequest("Selector request user message content must be a string.");
80
+ }
81
+ let parsed;
82
+ try {
83
+ parsed = JSON.parse(content);
84
+ }
85
+ catch {
86
+ throw invalidSelectorRequest("Selector request user message is not valid JSON.");
87
+ }
88
+ if (!isRecord(parsed)) {
89
+ throw invalidSelectorRequest("Selector request user message is not a JSON object.");
90
+ }
91
+ if (!Array.isArray(parsed.candidate_pairs)) {
92
+ throw invalidSelectorRequest("Selector input is missing candidate_pairs.");
93
+ }
94
+ // Anonymization would silently drop custom rules rather than apply them.
95
+ if ("custom_rules" in parsed || "default_target" in parsed) {
96
+ throw new RouterFrameworkError("invalid_request", "The Dari Auto Router serves only the default routing policy and cannot apply " +
97
+ "custom routing rules. Self-host the selector or use the Dari managed platform " +
98
+ "for custom routing.", "custom_rules_not_supported");
99
+ }
100
+ if (!Array.isArray(parsed.messages)) {
101
+ throw invalidSelectorRequest("Selector input messages must be an array.", "messages");
102
+ }
103
+ for (const [index, message] of parsed.messages.entries()) {
104
+ if (!isRecord(message) || typeof message.role !== "string") {
105
+ throw invalidSelectorRequest("Selector input messages must be objects with a string role.", `messages[${index}]`);
106
+ }
107
+ }
108
+ return parsed;
109
+ }
110
+ function invalidSelectorRequest(message, param) {
111
+ return new RouterFrameworkError("invalid_request", message, "invalid_request_error", param);
112
+ }
113
+ //# sourceMappingURL=selector_wire.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector_wire.js","sourceRoot":"","sources":["../src/selector_wire.ts"],"names":[],"mappings":"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"}