@framers/agentos 0.2.7 → 0.2.9

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 (69) hide show
  1. package/dist/cognitive-pipeline/index.d.ts +197 -0
  2. package/dist/cognitive-pipeline/index.d.ts.map +1 -0
  3. package/dist/cognitive-pipeline/index.js +193 -0
  4. package/dist/cognitive-pipeline/index.js.map +1 -0
  5. package/dist/ingest-router/IngestRouter.d.ts +72 -0
  6. package/dist/ingest-router/IngestRouter.d.ts.map +1 -0
  7. package/dist/ingest-router/IngestRouter.js +98 -0
  8. package/dist/ingest-router/IngestRouter.js.map +1 -0
  9. package/dist/ingest-router/classifier.d.ts +63 -0
  10. package/dist/ingest-router/classifier.d.ts.map +1 -0
  11. package/dist/ingest-router/classifier.js +111 -0
  12. package/dist/ingest-router/classifier.js.map +1 -0
  13. package/dist/ingest-router/costs.d.ts +48 -0
  14. package/dist/ingest-router/costs.d.ts.map +1 -0
  15. package/dist/ingest-router/costs.js +63 -0
  16. package/dist/ingest-router/costs.js.map +1 -0
  17. package/dist/ingest-router/dispatcher.d.ts +35 -0
  18. package/dist/ingest-router/dispatcher.d.ts.map +1 -0
  19. package/dist/ingest-router/dispatcher.js +32 -0
  20. package/dist/ingest-router/dispatcher.js.map +1 -0
  21. package/dist/ingest-router/index.d.ts +43 -0
  22. package/dist/ingest-router/index.d.ts.map +1 -0
  23. package/dist/ingest-router/index.js +37 -0
  24. package/dist/ingest-router/index.js.map +1 -0
  25. package/dist/ingest-router/routing-tables.d.ts +122 -0
  26. package/dist/ingest-router/routing-tables.d.ts.map +1 -0
  27. package/dist/ingest-router/routing-tables.js +145 -0
  28. package/dist/ingest-router/routing-tables.js.map +1 -0
  29. package/dist/ingest-router/select-strategy.d.ts +67 -0
  30. package/dist/ingest-router/select-strategy.d.ts.map +1 -0
  31. package/dist/ingest-router/select-strategy.js +100 -0
  32. package/dist/ingest-router/select-strategy.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/index.d.ts +2 -0
  38. package/dist/memory-router/index.d.ts.map +1 -1
  39. package/dist/memory-router/index.js +1 -0
  40. package/dist/memory-router/index.js.map +1 -1
  41. package/dist/read-router/ReadRouter.d.ts +58 -0
  42. package/dist/read-router/ReadRouter.d.ts.map +1 -0
  43. package/dist/read-router/ReadRouter.js +91 -0
  44. package/dist/read-router/ReadRouter.js.map +1 -0
  45. package/dist/read-router/classifier.d.ts +54 -0
  46. package/dist/read-router/classifier.d.ts.map +1 -0
  47. package/dist/read-router/classifier.js +104 -0
  48. package/dist/read-router/classifier.js.map +1 -0
  49. package/dist/read-router/costs.d.ts +23 -0
  50. package/dist/read-router/costs.d.ts.map +1 -0
  51. package/dist/read-router/costs.js +51 -0
  52. package/dist/read-router/costs.js.map +1 -0
  53. package/dist/read-router/dispatcher.d.ts +33 -0
  54. package/dist/read-router/dispatcher.d.ts.map +1 -0
  55. package/dist/read-router/dispatcher.js +29 -0
  56. package/dist/read-router/dispatcher.js.map +1 -0
  57. package/dist/read-router/index.d.ts +23 -0
  58. package/dist/read-router/index.d.ts.map +1 -0
  59. package/dist/read-router/index.js +17 -0
  60. package/dist/read-router/index.js.map +1 -0
  61. package/dist/read-router/routing-tables.d.ts +85 -0
  62. package/dist/read-router/routing-tables.d.ts.map +1 -0
  63. package/dist/read-router/routing-tables.js +79 -0
  64. package/dist/read-router/routing-tables.js.map +1 -0
  65. package/dist/read-router/select-strategy.d.ts +42 -0
  66. package/dist/read-router/select-strategy.d.ts.map +1 -0
  67. package/dist/read-router/select-strategy.js +92 -0
  68. package/dist/read-router/select-strategy.js.map +1 -0
  69. package/package.json +16 -1
@@ -0,0 +1,145 @@
1
+ /**
2
+ * @file routing-tables.ts
3
+ * @description Preset routing tables for {@link IngestRouter}.
4
+ *
5
+ * IngestRouter is the input-stage sibling of MemoryRouter. Where MemoryRouter
6
+ * picks the recall architecture for a query, IngestRouter picks the storage
7
+ * architecture for incoming content. The choice affects what's STORED, which
8
+ * downstream MemoryRouter then queries.
9
+ *
10
+ * Four shipping presets express different cost-vs-recall priorities:
11
+ *
12
+ * - {@link RAW_CHUNKS_TABLE}: stores everything as raw chunks. Cheapest at
13
+ * ingest time. Pushes all complexity to retrieval. Default for cost-
14
+ * sensitive workloads.
15
+ * - {@link SUMMARIZED_TABLE}: applies session/article summarization on long
16
+ * content. Anthropic-style "contextual retrieval" — every chunk gets a
17
+ * dense session-summary prefix before embedding.
18
+ * - {@link OBSERVATIONAL_TABLE}: extracts observation logs (Mastra-style)
19
+ * from long conversational content. Most expensive at ingest, best for
20
+ * multi-session synthesis recall.
21
+ * - {@link HYBRID_TABLE}: applies multiple ingest strategies in parallel
22
+ * for long content (raw chunks + summary + observations). Highest cost,
23
+ * highest recall flexibility — every retrieval strategy has its substrate.
24
+ *
25
+ * @module @framers/agentos/ingest-router/routing-tables
26
+ */
27
+ // ============================================================================
28
+ // Types
29
+ // ============================================================================
30
+ /**
31
+ * The six content kinds the LLM-as-judge ingest classifier can emit.
32
+ * Coarse taxonomy chosen to map cleanly onto distinct ingest strategies —
33
+ * extending the taxonomy means extending the routing tables consistently.
34
+ */
35
+ export const INGEST_CONTENT_KINDS = [
36
+ 'short-conversation',
37
+ 'long-conversation',
38
+ 'long-article',
39
+ 'code',
40
+ 'structured-data',
41
+ 'multimodal',
42
+ ];
43
+ // ============================================================================
44
+ // Preset tables
45
+ // ============================================================================
46
+ /**
47
+ * Preset: raw-chunks (default for cost-sensitive workloads).
48
+ *
49
+ * Stores everything as raw chunks regardless of content kind. Zero LLM
50
+ * cost at ingest time. All complexity is pushed to retrieval where the
51
+ * MemoryRouter can compose hybrid retrieval over the raw chunks.
52
+ *
53
+ * Recommended when: ingest volume is high, retrieval-side compute is
54
+ * cheap, and you trust the retrieval stage to do the heavy lifting.
55
+ */
56
+ export const RAW_CHUNKS_TABLE = Object.freeze({
57
+ preset: 'raw-chunks',
58
+ defaultMapping: Object.freeze({
59
+ 'short-conversation': 'raw-chunks',
60
+ 'long-conversation': 'raw-chunks',
61
+ 'long-article': 'raw-chunks',
62
+ code: 'raw-chunks',
63
+ 'structured-data': 'raw-chunks',
64
+ multimodal: 'raw-chunks',
65
+ }),
66
+ });
67
+ /**
68
+ * Preset: summarized (contextual retrieval for long content).
69
+ *
70
+ * Long content (long-conversation, long-article) gets a session/document
71
+ * summary prepended to every chunk before embedding. Short content stays
72
+ * as raw chunks. Code and structured data are summarized for the
73
+ * cross-file context. Multimodal stays raw — embedding modality is
74
+ * orthogonal to summarization.
75
+ *
76
+ * Recommended when: documents and conversations have meaningful global
77
+ * context that improves retrieval recall.
78
+ */
79
+ export const SUMMARIZED_TABLE = Object.freeze({
80
+ preset: 'summarized',
81
+ defaultMapping: Object.freeze({
82
+ 'short-conversation': 'raw-chunks',
83
+ 'long-conversation': 'summarized',
84
+ 'long-article': 'summarized',
85
+ code: 'summarized',
86
+ 'structured-data': 'raw-chunks',
87
+ multimodal: 'raw-chunks',
88
+ }),
89
+ });
90
+ /**
91
+ * Preset: observational (Mastra-style for multi-session synthesis).
92
+ *
93
+ * Long conversational content (long-conversation) becomes a structured
94
+ * observation log via LLM extraction at ingest. Long articles get the
95
+ * cheaper summarized treatment. Short content, code, structured, and
96
+ * multimodal stay raw.
97
+ *
98
+ * Recommended when: workload is conversational and includes many
99
+ * multi-session synthesis questions ("what have we agreed to so far",
100
+ * "across our chats, what topics recur").
101
+ */
102
+ export const OBSERVATIONAL_TABLE = Object.freeze({
103
+ preset: 'observational',
104
+ defaultMapping: Object.freeze({
105
+ 'short-conversation': 'raw-chunks',
106
+ 'long-conversation': 'observational',
107
+ 'long-article': 'summarized',
108
+ code: 'raw-chunks',
109
+ 'structured-data': 'raw-chunks',
110
+ multimodal: 'raw-chunks',
111
+ }),
112
+ });
113
+ /**
114
+ * Preset: hybrid (maximum-recall workloads).
115
+ *
116
+ * Applies multiple ingest strategies in parallel for long content. Every
117
+ * downstream retrieval architecture has its substrate (raw chunks for
118
+ * canonical hybrid, summary prefix for contextual retrieval, observation
119
+ * log for OM-style synthesis). Highest cost at ingest; highest flexibility
120
+ * at retrieval.
121
+ *
122
+ * Recommended when: cost-per-ingest is acceptable AND retrieval workload
123
+ * is heterogeneous enough that no single strategy dominates.
124
+ */
125
+ export const HYBRID_TABLE = Object.freeze({
126
+ preset: 'hybrid',
127
+ defaultMapping: Object.freeze({
128
+ 'short-conversation': 'raw-chunks',
129
+ 'long-conversation': 'hybrid',
130
+ 'long-article': 'hybrid',
131
+ code: 'summarized',
132
+ 'structured-data': 'raw-chunks',
133
+ multimodal: 'raw-chunks',
134
+ }),
135
+ });
136
+ /**
137
+ * Preset registry keyed by name.
138
+ */
139
+ export const PRESET_INGEST_TABLES = Object.freeze({
140
+ 'raw-chunks': RAW_CHUNKS_TABLE,
141
+ summarized: SUMMARIZED_TABLE,
142
+ observational: OBSERVATIONAL_TABLE,
143
+ hybrid: HYBRID_TABLE,
144
+ });
145
+ //# sourceMappingURL=routing-tables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing-tables.js","sourceRoot":"","sources":["../../src/ingest-router/routing-tables.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,+EAA+E;AAC/E,QAAQ;AACR,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,oBAAoB;IACpB,mBAAmB;IACnB,cAAc;IACd,MAAM;IACN,iBAAiB;IACjB,YAAY;CACJ,CAAC;AAqDX,+EAA+E;AAC/E,gBAAgB;AAChB,+EAA+E;AAE/E;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAuB,MAAM,CAAC,MAAM,CAAC;IAChE,MAAM,EAAE,YAAqB;IAC7B,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC;QAC5B,oBAAoB,EAAE,YAAY;QAClC,mBAAmB,EAAE,YAAY;QACjC,cAAc,EAAE,YAAY;QAC5B,IAAI,EAAE,YAAY;QAClB,iBAAiB,EAAE,YAAY;QAC/B,UAAU,EAAE,YAAY;KACzB,CAAC;CACH,CAAuB,CAAC;AAEzB;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAuB,MAAM,CAAC,MAAM,CAAC;IAChE,MAAM,EAAE,YAAqB;IAC7B,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC;QAC5B,oBAAoB,EAAE,YAAY;QAClC,mBAAmB,EAAE,YAAY;QACjC,cAAc,EAAE,YAAY;QAC5B,IAAI,EAAE,YAAY;QAClB,iBAAiB,EAAE,YAAY;QAC/B,UAAU,EAAE,YAAY;KACzB,CAAC;CACH,CAAuB,CAAC;AAEzB;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAuB,MAAM,CAAC,MAAM,CAAC;IACnE,MAAM,EAAE,eAAwB;IAChC,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC;QAC5B,oBAAoB,EAAE,YAAY;QAClC,mBAAmB,EAAE,eAAe;QACpC,cAAc,EAAE,YAAY;QAC5B,IAAI,EAAE,YAAY;QAClB,iBAAiB,EAAE,YAAY;QAC/B,UAAU,EAAE,YAAY;KACzB,CAAC;CACH,CAAuB,CAAC;AAEzB;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,YAAY,GAAuB,MAAM,CAAC,MAAM,CAAC;IAC5D,MAAM,EAAE,QAAiB;IACzB,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC;QAC5B,oBAAoB,EAAE,YAAY;QAClC,mBAAmB,EAAE,QAAQ;QAC7B,cAAc,EAAE,QAAQ;QACxB,IAAI,EAAE,YAAY;QAClB,iBAAiB,EAAE,YAAY;QAC/B,UAAU,EAAE,YAAY;KACzB,CAAC;CACH,CAAuB,CAAC;AAEzB;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAE7B,MAAM,CAAC,MAAM,CAAC;IAChB,YAAY,EAAE,gBAAgB;IAC9B,UAAU,EAAE,gBAAgB;IAC5B,aAAa,EAAE,mBAAmB;IAClC,MAAM,EAAE,YAAY;CACrB,CAAC,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @file select-strategy.ts
3
+ * @description Pure function that picks an ingest strategy from a
4
+ * predicted content kind + routing table + budget policy.
5
+ *
6
+ * Stateless. Deterministic. No I/O. Same shape as
7
+ * {@link selectBackend} in memory-router so the multi-stage guardrails
8
+ * orchestrator can compose them uniformly.
9
+ *
10
+ * @module @framers/agentos/ingest-router/select-strategy
11
+ */
12
+ import type { IngestStrategyCostPoint } from './costs.js';
13
+ import type { IngestContentKind, IngestRouterPreset, IngestRoutingTable, IngestStrategyId } from './routing-tables.js';
14
+ /**
15
+ * Budget enforcement modes for ingest dispatch:
16
+ * - `hard`: throw {@link IngestRouterBudgetExceededError} if the
17
+ * routing-table pick exceeds the per-ingest USD ceiling.
18
+ * - `soft`: keep the picked strategy when the ceiling is exceeded
19
+ * (best-effort enforcement; flag exceeded in the decision).
20
+ * - `cheapest-fallback`: silently downgrade to the cheapest strategy
21
+ * that fits. If none fits, pick the absolute cheapest and flag.
22
+ */
23
+ export type IngestBudgetMode = 'hard' | 'soft' | 'cheapest-fallback';
24
+ /**
25
+ * Configuration object for {@link selectIngestStrategy}.
26
+ */
27
+ export interface IngestRouterConfig {
28
+ readonly table: IngestRoutingTable;
29
+ readonly budgetPerIngestUsd: number | null;
30
+ readonly budgetMode: IngestBudgetMode;
31
+ readonly strategyCosts: Readonly<Record<IngestStrategyId, IngestStrategyCostPoint>>;
32
+ }
33
+ /**
34
+ * Output of {@link selectIngestStrategy}. Carries the chosen strategy
35
+ * plus full telemetry about how the decision was made.
36
+ */
37
+ export interface IngestRoutingDecision {
38
+ readonly predictedKind: IngestContentKind;
39
+ /** Optional ground-truth kind (telemetry only; null in production). */
40
+ readonly groundTruthKind: IngestContentKind | null;
41
+ readonly chosenStrategy: IngestStrategyId;
42
+ readonly chosenStrategyReason: string;
43
+ readonly estimatedCostUsd: number;
44
+ readonly budgetCeiling: number | null;
45
+ readonly budgetExceeded: boolean;
46
+ readonly preset: IngestRouterPreset;
47
+ }
48
+ export declare class IngestRouterUnknownKindError extends Error {
49
+ readonly kind: string;
50
+ constructor(kind: string);
51
+ }
52
+ export declare class IngestRouterBudgetExceededError extends Error {
53
+ readonly strategy: IngestStrategyId;
54
+ readonly cost: number;
55
+ readonly budget: number;
56
+ constructor(strategy: IngestStrategyId, cost: number, budget: number);
57
+ }
58
+ /**
59
+ * Pure ingest-strategy selection. Mirrors selectBackend (memory-router)
60
+ * in structure for multi-stage composability.
61
+ */
62
+ export declare function selectIngestStrategy(args: {
63
+ predictedKind: IngestContentKind;
64
+ groundTruthKind: IngestContentKind | null;
65
+ config: IngestRouterConfig;
66
+ }): IngestRoutingDecision;
67
+ //# sourceMappingURL=select-strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-strategy.d.ts","sourceRoot":"","sources":["../../src/ingest-router/select-strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,mBAAmB,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAC9B,MAAM,CAAC,gBAAgB,EAAE,uBAAuB,CAAC,CAClD,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,aAAa,EAAE,iBAAiB,CAAC;IAC1C,uEAAuE;IACvE,QAAQ,CAAC,eAAe,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACnD,QAAQ,CAAC,cAAc,EAAE,gBAAgB,CAAC;IAC1C,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;CACrC;AAED,qBAAa,4BAA6B,SAAQ,KAAK;aACzB,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;CAIzC;AAED,qBAAa,+BAAgC,SAAQ,KAAK;aAEtC,QAAQ,EAAE,gBAAgB;aAC1B,IAAI,EAAE,MAAM;aACZ,MAAM,EAAE,MAAM;gBAFd,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM;CAQjC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,aAAa,EAAE,iBAAiB,CAAC;IACjC,eAAe,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC1C,MAAM,EAAE,kBAAkB,CAAC;CAC5B,GAAG,qBAAqB,CAsFxB"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @file select-strategy.ts
3
+ * @description Pure function that picks an ingest strategy from a
4
+ * predicted content kind + routing table + budget policy.
5
+ *
6
+ * Stateless. Deterministic. No I/O. Same shape as
7
+ * {@link selectBackend} in memory-router so the multi-stage guardrails
8
+ * orchestrator can compose them uniformly.
9
+ *
10
+ * @module @framers/agentos/ingest-router/select-strategy
11
+ */
12
+ export class IngestRouterUnknownKindError extends Error {
13
+ constructor(kind) {
14
+ super(`IngestRouter: kind '${kind}' not in routing table`);
15
+ this.kind = kind;
16
+ this.name = 'IngestRouterUnknownKindError';
17
+ }
18
+ }
19
+ export class IngestRouterBudgetExceededError extends Error {
20
+ constructor(strategy, cost, budget) {
21
+ super(`IngestRouter: strategy '${strategy}' cost $${cost.toFixed(4)} ` +
22
+ `exceeds hard budget $${budget.toFixed(4)}`);
23
+ this.strategy = strategy;
24
+ this.cost = cost;
25
+ this.budget = budget;
26
+ this.name = 'IngestRouterBudgetExceededError';
27
+ }
28
+ }
29
+ /**
30
+ * Pure ingest-strategy selection. Mirrors selectBackend (memory-router)
31
+ * in structure for multi-stage composability.
32
+ */
33
+ export function selectIngestStrategy(args) {
34
+ const { predictedKind, groundTruthKind, config } = args;
35
+ const { table, budgetPerIngestUsd, budgetMode, strategyCosts } = config;
36
+ const picked = table.defaultMapping[predictedKind];
37
+ if (!picked) {
38
+ throw new IngestRouterUnknownKindError(predictedKind);
39
+ }
40
+ const pickedCost = strategyCosts[picked].avgCostPerIngest;
41
+ if (budgetPerIngestUsd === null || pickedCost <= budgetPerIngestUsd) {
42
+ return {
43
+ predictedKind,
44
+ groundTruthKind,
45
+ chosenStrategy: picked,
46
+ chosenStrategyReason: budgetPerIngestUsd === null
47
+ ? 'routing-table pick, no budget'
48
+ : 'routing-table pick fits budget',
49
+ estimatedCostUsd: pickedCost,
50
+ budgetCeiling: budgetPerIngestUsd,
51
+ budgetExceeded: false,
52
+ preset: table.preset,
53
+ };
54
+ }
55
+ if (budgetMode === 'hard') {
56
+ throw new IngestRouterBudgetExceededError(picked, pickedCost, budgetPerIngestUsd);
57
+ }
58
+ const candidates = Object.values(strategyCosts).map((c) => ({ strategy: c.strategy, cost: c.avgCostPerIngest }));
59
+ const fits = candidates.filter((c) => c.cost <= budgetPerIngestUsd);
60
+ const cheapestFits = fits.length > 0
61
+ ? fits.reduce((a, b) => (a.cost <= b.cost ? a : b))
62
+ : null;
63
+ if (!cheapestFits) {
64
+ const globallyCheapest = candidates.reduce((a, b) => a.cost <= b.cost ? a : b);
65
+ return {
66
+ predictedKind,
67
+ groundTruthKind,
68
+ chosenStrategy: globallyCheapest.strategy,
69
+ chosenStrategyReason: 'no strategy fits budget; picking absolute cheapest',
70
+ estimatedCostUsd: globallyCheapest.cost,
71
+ budgetCeiling: budgetPerIngestUsd,
72
+ budgetExceeded: true,
73
+ preset: table.preset,
74
+ };
75
+ }
76
+ if (budgetMode === 'cheapest-fallback') {
77
+ return {
78
+ predictedKind,
79
+ groundTruthKind,
80
+ chosenStrategy: cheapestFits.strategy,
81
+ chosenStrategyReason: 'budget downgrade (cheapest-fallback mode)',
82
+ estimatedCostUsd: cheapestFits.cost,
83
+ budgetCeiling: budgetPerIngestUsd,
84
+ budgetExceeded: false,
85
+ preset: table.preset,
86
+ };
87
+ }
88
+ // soft: keep the pick, flag exceeded.
89
+ return {
90
+ predictedKind,
91
+ groundTruthKind,
92
+ chosenStrategy: picked,
93
+ chosenStrategyReason: 'soft exceed: keeping picked despite budget breach',
94
+ estimatedCostUsd: pickedCost,
95
+ budgetCeiling: budgetPerIngestUsd,
96
+ budgetExceeded: true,
97
+ preset: table.preset,
98
+ };
99
+ }
100
+ //# sourceMappingURL=select-strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-strategy.js","sourceRoot":"","sources":["../../src/ingest-router/select-strategy.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"}