@framers/agentos 0.2.6 → 0.2.8

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 (93) hide show
  1. package/dist/ingest-router/IngestRouter.d.ts +72 -0
  2. package/dist/ingest-router/IngestRouter.d.ts.map +1 -0
  3. package/dist/ingest-router/IngestRouter.js +98 -0
  4. package/dist/ingest-router/IngestRouter.js.map +1 -0
  5. package/dist/ingest-router/classifier.d.ts +63 -0
  6. package/dist/ingest-router/classifier.d.ts.map +1 -0
  7. package/dist/ingest-router/classifier.js +111 -0
  8. package/dist/ingest-router/classifier.js.map +1 -0
  9. package/dist/ingest-router/costs.d.ts +48 -0
  10. package/dist/ingest-router/costs.d.ts.map +1 -0
  11. package/dist/ingest-router/costs.js +63 -0
  12. package/dist/ingest-router/costs.js.map +1 -0
  13. package/dist/ingest-router/dispatcher.d.ts +35 -0
  14. package/dist/ingest-router/dispatcher.d.ts.map +1 -0
  15. package/dist/ingest-router/dispatcher.js +32 -0
  16. package/dist/ingest-router/dispatcher.js.map +1 -0
  17. package/dist/ingest-router/index.d.ts +43 -0
  18. package/dist/ingest-router/index.d.ts.map +1 -0
  19. package/dist/ingest-router/index.js +37 -0
  20. package/dist/ingest-router/index.js.map +1 -0
  21. package/dist/ingest-router/routing-tables.d.ts +122 -0
  22. package/dist/ingest-router/routing-tables.d.ts.map +1 -0
  23. package/dist/ingest-router/routing-tables.js +145 -0
  24. package/dist/ingest-router/routing-tables.js.map +1 -0
  25. package/dist/ingest-router/select-strategy.d.ts +67 -0
  26. package/dist/ingest-router/select-strategy.d.ts.map +1 -0
  27. package/dist/ingest-router/select-strategy.js +100 -0
  28. package/dist/ingest-router/select-strategy.js.map +1 -0
  29. package/dist/memory-router/MemoryRouter.d.ts +195 -0
  30. package/dist/memory-router/MemoryRouter.d.ts.map +1 -0
  31. package/dist/memory-router/MemoryRouter.js +155 -0
  32. package/dist/memory-router/MemoryRouter.js.map +1 -0
  33. package/dist/memory-router/adaptive.d.ts +142 -0
  34. package/dist/memory-router/adaptive.d.ts.map +1 -0
  35. package/dist/memory-router/adaptive.js +202 -0
  36. package/dist/memory-router/adaptive.js.map +1 -0
  37. package/dist/memory-router/backend-costs.d.ts +67 -0
  38. package/dist/memory-router/backend-costs.d.ts.map +1 -0
  39. package/dist/memory-router/backend-costs.js +136 -0
  40. package/dist/memory-router/backend-costs.js.map +1 -0
  41. package/dist/memory-router/classifier.d.ts +169 -0
  42. package/dist/memory-router/classifier.d.ts.map +1 -0
  43. package/dist/memory-router/classifier.js +193 -0
  44. package/dist/memory-router/classifier.js.map +1 -0
  45. package/dist/memory-router/dispatcher.d.ts +115 -0
  46. package/dist/memory-router/dispatcher.d.ts.map +1 -0
  47. package/dist/memory-router/dispatcher.js +84 -0
  48. package/dist/memory-router/dispatcher.js.map +1 -0
  49. package/dist/memory-router/index.d.ts +126 -0
  50. package/dist/memory-router/index.d.ts.map +1 -0
  51. package/dist/memory-router/index.js +122 -0
  52. package/dist/memory-router/index.js.map +1 -0
  53. package/dist/memory-router/routing-tables.d.ts +125 -0
  54. package/dist/memory-router/routing-tables.d.ts.map +1 -0
  55. package/dist/memory-router/routing-tables.js +137 -0
  56. package/dist/memory-router/routing-tables.js.map +1 -0
  57. package/dist/memory-router/select-backend.d.ts +136 -0
  58. package/dist/memory-router/select-backend.d.ts.map +1 -0
  59. package/dist/memory-router/select-backend.js +210 -0
  60. package/dist/memory-router/select-backend.js.map +1 -0
  61. package/dist/multi-stage-guardrails/index.d.ts +190 -0
  62. package/dist/multi-stage-guardrails/index.d.ts.map +1 -0
  63. package/dist/multi-stage-guardrails/index.js +186 -0
  64. package/dist/multi-stage-guardrails/index.js.map +1 -0
  65. package/dist/read-router/ReadRouter.d.ts +58 -0
  66. package/dist/read-router/ReadRouter.d.ts.map +1 -0
  67. package/dist/read-router/ReadRouter.js +91 -0
  68. package/dist/read-router/ReadRouter.js.map +1 -0
  69. package/dist/read-router/classifier.d.ts +54 -0
  70. package/dist/read-router/classifier.d.ts.map +1 -0
  71. package/dist/read-router/classifier.js +104 -0
  72. package/dist/read-router/classifier.js.map +1 -0
  73. package/dist/read-router/costs.d.ts +23 -0
  74. package/dist/read-router/costs.d.ts.map +1 -0
  75. package/dist/read-router/costs.js +51 -0
  76. package/dist/read-router/costs.js.map +1 -0
  77. package/dist/read-router/dispatcher.d.ts +33 -0
  78. package/dist/read-router/dispatcher.d.ts.map +1 -0
  79. package/dist/read-router/dispatcher.js +29 -0
  80. package/dist/read-router/dispatcher.js.map +1 -0
  81. package/dist/read-router/index.d.ts +23 -0
  82. package/dist/read-router/index.d.ts.map +1 -0
  83. package/dist/read-router/index.js +17 -0
  84. package/dist/read-router/index.js.map +1 -0
  85. package/dist/read-router/routing-tables.d.ts +85 -0
  86. package/dist/read-router/routing-tables.d.ts.map +1 -0
  87. package/dist/read-router/routing-tables.js +79 -0
  88. package/dist/read-router/routing-tables.js.map +1 -0
  89. package/dist/read-router/select-strategy.d.ts +42 -0
  90. package/dist/read-router/select-strategy.d.ts.map +1 -0
  91. package/dist/read-router/select-strategy.js +92 -0
  92. package/dist/read-router/select-strategy.js.map +1 -0
  93. package/package.json +21 -1
@@ -0,0 +1,195 @@
1
+ /**
2
+ * @file MemoryRouter.ts
3
+ * @description Top-level orchestrator that composes the LLM-as-judge
4
+ * classifier and the pure `selectBackend` decision function into a single
5
+ * per-query routing call.
6
+ *
7
+ * MemoryRouter is deliberately a THIN composition layer. It:
8
+ * 1. Runs the classifier on the incoming query → category + token counts.
9
+ * 2. Resolves the routing table from (preset | custom table | custom mapping).
10
+ * 3. Calls the pure selectBackend to get the routing decision.
11
+ * 4. Returns a {@link MemoryRouterDecision} bundling both.
12
+ *
13
+ * It does NOT execute the recall — backend execution is the job of
14
+ * {@link IMemoryDispatcher}. This split keeps the router pure-enough to
15
+ * be used in both "decide only" flows (benchmarks, dashboards, dry-runs)
16
+ * and "decide + execute" flows (production queries).
17
+ *
18
+ * @module @framers/agentos/memory-router/MemoryRouter
19
+ */
20
+ import type { IMemoryClassifier, MemoryClassifierResult } from './classifier.js';
21
+ import { type MemoryBackendCostPoint } from './backend-costs.js';
22
+ import { type MemoryBackendId, type MemoryQueryCategory, type MemoryRouterPreset, type RoutingTable } from './routing-tables.js';
23
+ import { type MemoryBudgetMode, type MemoryRoutingDecision } from './select-backend.js';
24
+ import type { IMemoryDispatcher } from './dispatcher.js';
25
+ /**
26
+ * Per-query USD budget policy. Combined into a single nested object so
27
+ * consumers can enable budget enforcement without flat-argument sprawl.
28
+ */
29
+ export interface MemoryBudgetPolicy {
30
+ /**
31
+ * Budget ceiling per query in USD. When omitted, routing passes
32
+ * through the table's pick regardless of cost.
33
+ */
34
+ readonly perQueryUsd?: number;
35
+ /**
36
+ * How to handle budget overrun. Default `cheapest-fallback` for
37
+ * production safety (silently downgrades rather than throwing).
38
+ * See {@link MemoryBudgetMode}.
39
+ */
40
+ readonly mode?: MemoryBudgetMode;
41
+ }
42
+ /**
43
+ * Constructor options for {@link MemoryRouter}.
44
+ */
45
+ export interface MemoryRouterOptions {
46
+ /** LLM-as-judge classifier. Usually {@link LLMMemoryClassifier}. */
47
+ readonly classifier: IMemoryClassifier;
48
+ /**
49
+ * Shipping preset to use. Defaults to `minimize-cost` — the same
50
+ * Pareto-best-for-cost preset we use on LongMemEval-S Phase B.
51
+ */
52
+ readonly preset?: MemoryRouterPreset;
53
+ /**
54
+ * Optional custom routing table override. When provided, replaces the
55
+ * preset's default table. The `preset` field is still used for
56
+ * telemetry labeling and must match.
57
+ */
58
+ readonly routingTable?: RoutingTable;
59
+ /**
60
+ * Optional per-category routing override that patches the resolved
61
+ * routing table. Useful when a workload needs to change a single
62
+ * category's dispatch without rewriting the whole table.
63
+ */
64
+ readonly mapping?: Partial<Record<MemoryQueryCategory, MemoryBackendId>>;
65
+ /**
66
+ * Optional budget policy. When omitted, no budget is enforced.
67
+ */
68
+ readonly budget?: MemoryBudgetPolicy;
69
+ /**
70
+ * Optional custom backend cost-points (for workloads whose cost /
71
+ * accuracy profile diverges from LongMemEval-S Phase B). When omitted,
72
+ * uses {@link DEFAULT_MEMORY_BACKEND_COSTS}.
73
+ */
74
+ readonly backendCosts?: Readonly<Record<MemoryBackendId, MemoryBackendCostPoint>>;
75
+ /**
76
+ * Default for {@link MemoryClassifierClassifyOptions.useFewShotPrompt}
77
+ * on every `decide()` call. Callers can still override per-call.
78
+ */
79
+ readonly useFewShotPrompt?: boolean;
80
+ /**
81
+ * Optional dispatcher. When supplied, {@link MemoryRouter.decideAndDispatch}
82
+ * is usable; otherwise callers must use {@link MemoryRouter.decide} and
83
+ * execute the chosen backend themselves.
84
+ */
85
+ readonly dispatcher?: IMemoryDispatcher<unknown, unknown>;
86
+ }
87
+ /**
88
+ * Per-call options for {@link MemoryRouter.decide}.
89
+ */
90
+ export interface MemoryRouterDecideOptions {
91
+ /**
92
+ * Ground-truth category, passed through to the routing decision for
93
+ * telemetry. Not used in production. Benchmark adapters pass this when
94
+ * the gold label is available so downstream analysis can distinguish
95
+ * classifier misroutes from architectural misses.
96
+ */
97
+ readonly groundTruthCategory?: MemoryQueryCategory | null;
98
+ /**
99
+ * Per-call override of the few-shot prompt variant. When omitted,
100
+ * inherits the router's constructor-scoped default.
101
+ */
102
+ readonly useFewShotPrompt?: boolean;
103
+ }
104
+ /**
105
+ * Bundled result of a `decide()` call. Carries the classifier result
106
+ * (for cost tracking + debugging) alongside the routing decision.
107
+ */
108
+ export interface MemoryRouterDecision {
109
+ readonly classifier: MemoryClassifierResult;
110
+ readonly routing: MemoryRoutingDecision;
111
+ }
112
+ /**
113
+ * Bundled result of a `decideAndDispatch()` call. Combines the full
114
+ * {@link MemoryRouterDecision} with the dispatched traces so telemetry
115
+ * and answer-generation can consume both in one step.
116
+ */
117
+ export interface MemoryRouterDispatchedDecision<TTrace> {
118
+ readonly decision: MemoryRouterDecision;
119
+ readonly traces: TTrace[];
120
+ readonly backend: MemoryBackendId;
121
+ }
122
+ /**
123
+ * Thrown when `decideAndDispatch` is called on a router that was
124
+ * constructed without a dispatcher.
125
+ */
126
+ export declare class MemoryRouterDispatcherMissingError extends Error {
127
+ constructor();
128
+ }
129
+ /**
130
+ * The public MemoryRouter primitive. One instance per memory-recall
131
+ * endpoint; construct once at app startup with the chosen preset and
132
+ * reuse across queries.
133
+ *
134
+ * @example Basic min-cost routing
135
+ * ```ts
136
+ * import { LLMMemoryClassifier, MemoryRouter } from '../memory-router';
137
+ *
138
+ * const router = new MemoryRouter({
139
+ * classifier: new LLMMemoryClassifier({ llm: myOpenAIAdapter }),
140
+ * preset: 'minimize-cost',
141
+ * });
142
+ *
143
+ * const decision = await router.decide("What's my current job title?");
144
+ * console.log(decision.classifier.category); // 'knowledge-update'
145
+ * console.log(decision.routing.chosenBackend); // 'canonical-hybrid'
146
+ * console.log(decision.routing.estimatedCostUsd); // 0.0189
147
+ * ```
148
+ *
149
+ * @example With a strict budget
150
+ * ```ts
151
+ * const router = new MemoryRouter({
152
+ * classifier: myClassifier,
153
+ * preset: 'maximize-accuracy',
154
+ * budget: { perQueryUsd: 0.025, mode: 'cheapest-fallback' },
155
+ * });
156
+ * ```
157
+ */
158
+ export declare class MemoryRouter {
159
+ private readonly classifier;
160
+ private readonly preset;
161
+ private readonly routingTable;
162
+ private readonly budgetPerQuery;
163
+ private readonly budgetMode;
164
+ private readonly backendCosts;
165
+ private readonly defaultUseFewShotPrompt;
166
+ private readonly dispatcher;
167
+ constructor(options: MemoryRouterOptions);
168
+ /**
169
+ * Decide-only routing. Classifies the query, picks a backend, returns
170
+ * both pieces. Does NOT execute the recall — pair with an
171
+ * {@link IMemoryDispatcher} for the end-to-end flow, or call
172
+ * {@link MemoryRouter.decideAndDispatch} if a dispatcher is wired.
173
+ *
174
+ * @param query - The user's memory-recall query text.
175
+ * @param options - Per-call overrides (ground-truth telemetry, prompt variant).
176
+ * @returns A {@link MemoryRouterDecision} bundling classifier + routing results.
177
+ */
178
+ decide(query: string, options?: MemoryRouterDecideOptions): Promise<MemoryRouterDecision>;
179
+ /**
180
+ * Decide + dispatch in one call. Requires the router to have been
181
+ * constructed with a {@link IMemoryDispatcher}.
182
+ *
183
+ * @typeParam TTrace - Caller's trace shape (passed through verbatim).
184
+ * @typeParam TPayload - Caller's payload shape for the dispatcher.
185
+ * @param query - User memory-recall query.
186
+ * @param dispatchPayload - Optional payload forwarded to the dispatcher's
187
+ * per-backend executor (e.g. topK, retrieval policy).
188
+ * @param options - Per-call overrides (ground-truth telemetry, prompt variant).
189
+ *
190
+ * @throws {@link MemoryRouterDispatcherMissingError} when no dispatcher
191
+ * was supplied at construction.
192
+ */
193
+ decideAndDispatch<TTrace, TPayload = undefined>(query: string, dispatchPayload?: TPayload, options?: MemoryRouterDecideOptions): Promise<MemoryRouterDispatchedDecision<TTrace>>;
194
+ }
195
+ //# sourceMappingURL=MemoryRouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoryRouter.d.ts","sourceRoot":"","sources":["../../src/memory-router/MemoryRouter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * @file MemoryRouter.ts
3
+ * @description Top-level orchestrator that composes the LLM-as-judge
4
+ * classifier and the pure `selectBackend` decision function into a single
5
+ * per-query routing call.
6
+ *
7
+ * MemoryRouter is deliberately a THIN composition layer. It:
8
+ * 1. Runs the classifier on the incoming query → category + token counts.
9
+ * 2. Resolves the routing table from (preset | custom table | custom mapping).
10
+ * 3. Calls the pure selectBackend to get the routing decision.
11
+ * 4. Returns a {@link MemoryRouterDecision} bundling both.
12
+ *
13
+ * It does NOT execute the recall — backend execution is the job of
14
+ * {@link IMemoryDispatcher}. This split keeps the router pure-enough to
15
+ * be used in both "decide only" flows (benchmarks, dashboards, dry-runs)
16
+ * and "decide + execute" flows (production queries).
17
+ *
18
+ * @module @framers/agentos/memory-router/MemoryRouter
19
+ */
20
+ import { DEFAULT_MEMORY_BACKEND_COSTS, } from './backend-costs.js';
21
+ import { PRESET_TABLES, } from './routing-tables.js';
22
+ import { selectBackend, } from './select-backend.js';
23
+ /**
24
+ * Thrown when `decideAndDispatch` is called on a router that was
25
+ * constructed without a dispatcher.
26
+ */
27
+ export class MemoryRouterDispatcherMissingError extends Error {
28
+ constructor() {
29
+ super('MemoryRouter.decideAndDispatch requires a dispatcher. ' +
30
+ 'Either pass a dispatcher in options, or call `decide` and dispatch yourself.');
31
+ this.name = 'MemoryRouterDispatcherMissingError';
32
+ }
33
+ }
34
+ // ============================================================================
35
+ // Class
36
+ // ============================================================================
37
+ /**
38
+ * The public MemoryRouter primitive. One instance per memory-recall
39
+ * endpoint; construct once at app startup with the chosen preset and
40
+ * reuse across queries.
41
+ *
42
+ * @example Basic min-cost routing
43
+ * ```ts
44
+ * import { LLMMemoryClassifier, MemoryRouter } from '../memory-router/index.js';
45
+ *
46
+ * const router = new MemoryRouter({
47
+ * classifier: new LLMMemoryClassifier({ llm: myOpenAIAdapter }),
48
+ * preset: 'minimize-cost',
49
+ * });
50
+ *
51
+ * const decision = await router.decide("What's my current job title?");
52
+ * console.log(decision.classifier.category); // 'knowledge-update'
53
+ * console.log(decision.routing.chosenBackend); // 'canonical-hybrid'
54
+ * console.log(decision.routing.estimatedCostUsd); // 0.0189
55
+ * ```
56
+ *
57
+ * @example With a strict budget
58
+ * ```ts
59
+ * const router = new MemoryRouter({
60
+ * classifier: myClassifier,
61
+ * preset: 'maximize-accuracy',
62
+ * budget: { perQueryUsd: 0.025, mode: 'cheapest-fallback' },
63
+ * });
64
+ * ```
65
+ */
66
+ export class MemoryRouter {
67
+ constructor(options) {
68
+ this.classifier = options.classifier;
69
+ this.preset = options.preset ?? 'minimize-cost';
70
+ this.dispatcher = options.dispatcher ?? null;
71
+ // Resolve routing table: explicit > preset's default.
72
+ const baseTable = options.routingTable ?? PRESET_TABLES[this.preset];
73
+ // Apply optional per-category mapping override.
74
+ if (options.mapping) {
75
+ const patched = {
76
+ ...baseTable.defaultMapping,
77
+ };
78
+ for (const key of Object.keys(options.mapping)) {
79
+ const override = options.mapping[key];
80
+ if (override)
81
+ patched[key] = override;
82
+ }
83
+ this.routingTable = Object.freeze({
84
+ preset: baseTable.preset,
85
+ defaultMapping: Object.freeze(patched),
86
+ });
87
+ }
88
+ else {
89
+ this.routingTable = baseTable;
90
+ }
91
+ this.budgetPerQuery = options.budget?.perQueryUsd ?? null;
92
+ this.budgetMode = options.budget?.mode ?? 'cheapest-fallback';
93
+ this.backendCosts = options.backendCosts ?? DEFAULT_MEMORY_BACKEND_COSTS;
94
+ this.defaultUseFewShotPrompt = options.useFewShotPrompt ?? false;
95
+ }
96
+ /**
97
+ * Decide-only routing. Classifies the query, picks a backend, returns
98
+ * both pieces. Does NOT execute the recall — pair with an
99
+ * {@link IMemoryDispatcher} for the end-to-end flow, or call
100
+ * {@link MemoryRouter.decideAndDispatch} if a dispatcher is wired.
101
+ *
102
+ * @param query - The user's memory-recall query text.
103
+ * @param options - Per-call overrides (ground-truth telemetry, prompt variant).
104
+ * @returns A {@link MemoryRouterDecision} bundling classifier + routing results.
105
+ */
106
+ async decide(query, options) {
107
+ const useFewShot = options?.useFewShotPrompt ?? this.defaultUseFewShotPrompt;
108
+ const classifierOptions = useFewShot
109
+ ? { useFewShotPrompt: true }
110
+ : undefined;
111
+ const classifier = await this.classifier.classify(query, classifierOptions);
112
+ const routing = selectBackend({
113
+ predictedCategory: classifier.category,
114
+ groundTruthCategory: options?.groundTruthCategory ?? null,
115
+ config: {
116
+ table: this.routingTable,
117
+ budgetPerQuery: this.budgetPerQuery,
118
+ budgetMode: this.budgetMode,
119
+ backendCosts: this.backendCosts,
120
+ },
121
+ });
122
+ return { classifier, routing };
123
+ }
124
+ /**
125
+ * Decide + dispatch in one call. Requires the router to have been
126
+ * constructed with a {@link IMemoryDispatcher}.
127
+ *
128
+ * @typeParam TTrace - Caller's trace shape (passed through verbatim).
129
+ * @typeParam TPayload - Caller's payload shape for the dispatcher.
130
+ * @param query - User memory-recall query.
131
+ * @param dispatchPayload - Optional payload forwarded to the dispatcher's
132
+ * per-backend executor (e.g. topK, retrieval policy).
133
+ * @param options - Per-call overrides (ground-truth telemetry, prompt variant).
134
+ *
135
+ * @throws {@link MemoryRouterDispatcherMissingError} when no dispatcher
136
+ * was supplied at construction.
137
+ */
138
+ async decideAndDispatch(query, dispatchPayload, options) {
139
+ if (!this.dispatcher) {
140
+ throw new MemoryRouterDispatcherMissingError();
141
+ }
142
+ const decision = await this.decide(query, options);
143
+ const dispatched = (await this.dispatcher.dispatch({
144
+ backend: decision.routing.chosenBackend,
145
+ query,
146
+ payload: dispatchPayload,
147
+ }));
148
+ return {
149
+ decision,
150
+ traces: dispatched.traces,
151
+ backend: dispatched.backend,
152
+ };
153
+ }
154
+ }
155
+ //# sourceMappingURL=MemoryRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoryRouter.js","sourceRoot":"","sources":["../../src/memory-router/MemoryRouter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * @file adaptive.ts
3
+ * @description Self-calibrating routing-table generator.
4
+ *
5
+ * The shipping {@link MINIMIZE_COST_TABLE} / {@link BALANCED_TABLE} /
6
+ * {@link MAXIMIZE_ACCURACY_TABLE} are calibrated from LongMemEval-S
7
+ * Phase B N=500 measurements. For workloads whose cost-accuracy profile
8
+ * diverges from that distribution, those tables are not optimal.
9
+ *
10
+ * AdaptiveMemoryRouter takes a workload-specific calibration dataset
11
+ * (a list of {category, backend, costUsd, correct} samples) and derives
12
+ * a routing table from it. Same MemoryRouter API; different table
13
+ * source.
14
+ *
15
+ * Calibration workflow:
16
+ * 1. Run a Phase A sweep on your workload (a few hundred queries
17
+ * across a small subset of expected categories, dispatched to all
18
+ * candidate backends).
19
+ * 2. Each sample contributes one (category, backend, costUsd, correct)
20
+ * data point.
21
+ * 3. AdaptiveMemoryRouter aggregates these into per-(category, backend)
22
+ * mean cost + mean accuracy.
23
+ * 4. Apply a preset selection rule:
24
+ * - 'minimize-cost': cheapest backend within 2pp of best accuracy;
25
+ * if none within tolerance, pick best accuracy.
26
+ * - 'maximize-accuracy': highest accuracy; ties broken by cost.
27
+ * - 'balanced': best $/correct (mean cost divided by mean
28
+ * accuracy).
29
+ * 5. Categories with insufficient samples fall back to the static
30
+ * preset table.
31
+ *
32
+ * The router is otherwise identical to {@link MemoryRouter} — same
33
+ * decide() / decideAndDispatch() / budget-aware dispatch.
34
+ *
35
+ * @module @framers/agentos/memory-router/adaptive
36
+ */
37
+ import { MemoryRouter, type MemoryRouterOptions } from './MemoryRouter.js';
38
+ import { type MemoryBackendId, type MemoryQueryCategory, type RoutingTable } from './routing-tables.js';
39
+ /**
40
+ * One calibration sample. Caller produces these from running their own
41
+ * workload through each candidate backend and recording the outcome.
42
+ */
43
+ export interface CalibrationSample {
44
+ readonly category: MemoryQueryCategory;
45
+ readonly backend: MemoryBackendId;
46
+ readonly costUsd: number;
47
+ /** 1 = correct, 0 = incorrect (or score in [0,1] for soft graders). */
48
+ readonly correct: number;
49
+ }
50
+ /**
51
+ * Aggregated calibration cell: one (category, backend) → mean cost +
52
+ * mean accuracy + sample count.
53
+ */
54
+ export interface CalibrationCell {
55
+ readonly n: number;
56
+ readonly meanCost: number;
57
+ readonly meanAccuracy: number;
58
+ }
59
+ /**
60
+ * Map of (category, backend) → CalibrationCell. Categories or backends
61
+ * with no samples are simply absent from the map.
62
+ */
63
+ export type AggregatedCalibration = Partial<Record<MemoryQueryCategory, Partial<Record<MemoryBackendId, CalibrationCell>>>>;
64
+ /**
65
+ * Preset selection rules for {@link selectByPreset}.
66
+ *
67
+ * - `minimize-cost`: pick the cheapest backend whose meanAccuracy is
68
+ * within `accuracyTolerance` (default 0.02 = 2pp) of the best
69
+ * meanAccuracy on this category. If no backend is within tolerance,
70
+ * pick the best-accuracy backend (the gap exceeds the tolerance,
71
+ * meaning accuracy gain justifies cost).
72
+ * - `maximize-accuracy`: pick the highest-meanAccuracy backend;
73
+ * ties broken by lower meanCost.
74
+ * - `balanced`: pick the lowest meanCost / meanAccuracy ratio
75
+ * ($/correct). Backends with zero meanAccuracy are skipped (would
76
+ * produce divide-by-zero).
77
+ */
78
+ export type AdaptivePresetRule = 'minimize-cost' | 'balanced' | 'maximize-accuracy';
79
+ export interface SelectByPresetArgs {
80
+ readonly category: MemoryQueryCategory;
81
+ readonly agg: AggregatedCalibration;
82
+ readonly preset: AdaptivePresetRule;
83
+ /**
84
+ * Minimum sample count per (category, backend) cell required for
85
+ * adaptive selection. Cells below this threshold are ignored. Default
86
+ * 1 (any sample qualifies). Increase for noisier workloads.
87
+ */
88
+ readonly minSamplesPerCell?: number;
89
+ /**
90
+ * For `minimize-cost`: max accuracy gap from the best-accuracy backend
91
+ * tolerated when picking the cheaper alternative. Default 0.02 (2pp).
92
+ */
93
+ readonly accuracyTolerance?: number;
94
+ }
95
+ export interface BuildAdaptiveRoutingTableArgs {
96
+ readonly samples: readonly CalibrationSample[];
97
+ readonly preset: AdaptivePresetRule;
98
+ readonly minSamplesPerCell?: number;
99
+ readonly accuracyTolerance?: number;
100
+ /**
101
+ * Fallback static table for categories with insufficient calibration.
102
+ * Defaults to the preset's shipping static table.
103
+ */
104
+ readonly fallbackTable?: RoutingTable;
105
+ }
106
+ export interface AdaptiveMemoryRouterOptions extends Omit<MemoryRouterOptions, 'routingTable' | 'preset'> {
107
+ readonly calibrationSamples: readonly CalibrationSample[];
108
+ readonly preset: AdaptivePresetRule;
109
+ readonly minSamplesPerCell?: number;
110
+ readonly accuracyTolerance?: number;
111
+ }
112
+ /**
113
+ * Roll up raw calibration samples into per-(category, backend) cells.
114
+ * Each cell carries n, meanCost, meanAccuracy.
115
+ */
116
+ export declare function aggregateCalibration(samples: readonly CalibrationSample[]): AggregatedCalibration;
117
+ /**
118
+ * Select a backend for one category from aggregated calibration data
119
+ * using the named preset rule. Falls back to the preset's static table
120
+ * when calibration is insufficient.
121
+ */
122
+ export declare function selectByPreset(args: SelectByPresetArgs): MemoryBackendId;
123
+ /**
124
+ * Build a complete frozen routing table from calibration samples + a
125
+ * preset rule. Categories without enough calibration fall back to the
126
+ * preset's static table.
127
+ */
128
+ export declare function buildAdaptiveRoutingTable(args: BuildAdaptiveRoutingTableArgs): RoutingTable;
129
+ /**
130
+ * Memory router whose routing table is derived from a calibration
131
+ * dataset rather than a static preset. Otherwise identical API to
132
+ * {@link MemoryRouter}.
133
+ */
134
+ export declare class AdaptiveMemoryRouter extends MemoryRouter {
135
+ private readonly derivedTable;
136
+ constructor(options: AdaptiveMemoryRouterOptions);
137
+ /**
138
+ * Inspect the derived routing table for debugging / telemetry.
139
+ */
140
+ getRoutingTable(): RoutingTable;
141
+ }
142
+ //# sourceMappingURL=adaptive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adaptive.d.ts","sourceRoot":"","sources":["../../src/memory-router/adaptive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAExB,KAAK,YAAY,EAClB,MAAM,qBAAqB,CAAC;AAM7B;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,OAAO,CACzC,MAAM,CAAC,mBAAmB,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC,CAAC,CAC/E,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,kBAAkB,GAC1B,eAAe,GACf,UAAU,GACV,mBAAmB,CAAC;AAExB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,GAAG,EAAE,qBAAqB,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC/C,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,YAAY,CAAC;CACvC;AAED,MAAM,WAAW,2BACf,SAAQ,IAAI,CAAC,mBAAmB,EAAE,cAAc,GAAG,QAAQ,CAAC;IAC5D,QAAQ,CAAC,kBAAkB,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC1D,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,SAAS,iBAAiB,EAAE,GACpC,qBAAqB,CA4BvB;AAMD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,eAAe,CA8DxE;AAeD;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,6BAA6B,GAClC,YAAY,CAqCd;AAMD;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;IACpD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;gBAEhC,OAAO,EAAE,2BAA2B;IAiBhD;;OAEG;IACH,eAAe,IAAI,YAAY;CAGhC"}