@framers/agentos 0.2.7 → 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.
- package/dist/ingest-router/IngestRouter.d.ts +72 -0
- package/dist/ingest-router/IngestRouter.d.ts.map +1 -0
- package/dist/ingest-router/IngestRouter.js +98 -0
- package/dist/ingest-router/IngestRouter.js.map +1 -0
- package/dist/ingest-router/classifier.d.ts +63 -0
- package/dist/ingest-router/classifier.d.ts.map +1 -0
- package/dist/ingest-router/classifier.js +111 -0
- package/dist/ingest-router/classifier.js.map +1 -0
- package/dist/ingest-router/costs.d.ts +48 -0
- package/dist/ingest-router/costs.d.ts.map +1 -0
- package/dist/ingest-router/costs.js +63 -0
- package/dist/ingest-router/costs.js.map +1 -0
- package/dist/ingest-router/dispatcher.d.ts +35 -0
- package/dist/ingest-router/dispatcher.d.ts.map +1 -0
- package/dist/ingest-router/dispatcher.js +32 -0
- package/dist/ingest-router/dispatcher.js.map +1 -0
- package/dist/ingest-router/index.d.ts +43 -0
- package/dist/ingest-router/index.d.ts.map +1 -0
- package/dist/ingest-router/index.js +37 -0
- package/dist/ingest-router/index.js.map +1 -0
- package/dist/ingest-router/routing-tables.d.ts +122 -0
- package/dist/ingest-router/routing-tables.d.ts.map +1 -0
- package/dist/ingest-router/routing-tables.js +145 -0
- package/dist/ingest-router/routing-tables.js.map +1 -0
- package/dist/ingest-router/select-strategy.d.ts +67 -0
- package/dist/ingest-router/select-strategy.d.ts.map +1 -0
- package/dist/ingest-router/select-strategy.js +100 -0
- package/dist/ingest-router/select-strategy.js.map +1 -0
- package/dist/memory-router/adaptive.d.ts +142 -0
- package/dist/memory-router/adaptive.d.ts.map +1 -0
- package/dist/memory-router/adaptive.js +202 -0
- package/dist/memory-router/adaptive.js.map +1 -0
- package/dist/memory-router/index.d.ts +2 -0
- package/dist/memory-router/index.d.ts.map +1 -1
- package/dist/memory-router/index.js +1 -0
- package/dist/memory-router/index.js.map +1 -1
- package/dist/multi-stage-guardrails/index.d.ts +190 -0
- package/dist/multi-stage-guardrails/index.d.ts.map +1 -0
- package/dist/multi-stage-guardrails/index.js +186 -0
- package/dist/multi-stage-guardrails/index.js.map +1 -0
- package/dist/read-router/ReadRouter.d.ts +58 -0
- package/dist/read-router/ReadRouter.d.ts.map +1 -0
- package/dist/read-router/ReadRouter.js +91 -0
- package/dist/read-router/ReadRouter.js.map +1 -0
- package/dist/read-router/classifier.d.ts +54 -0
- package/dist/read-router/classifier.d.ts.map +1 -0
- package/dist/read-router/classifier.js +104 -0
- package/dist/read-router/classifier.js.map +1 -0
- package/dist/read-router/costs.d.ts +23 -0
- package/dist/read-router/costs.d.ts.map +1 -0
- package/dist/read-router/costs.js +51 -0
- package/dist/read-router/costs.js.map +1 -0
- package/dist/read-router/dispatcher.d.ts +33 -0
- package/dist/read-router/dispatcher.d.ts.map +1 -0
- package/dist/read-router/dispatcher.js +29 -0
- package/dist/read-router/dispatcher.js.map +1 -0
- package/dist/read-router/index.d.ts +23 -0
- package/dist/read-router/index.d.ts.map +1 -0
- package/dist/read-router/index.js +17 -0
- package/dist/read-router/index.js.map +1 -0
- package/dist/read-router/routing-tables.d.ts +85 -0
- package/dist/read-router/routing-tables.d.ts.map +1 -0
- package/dist/read-router/routing-tables.js +79 -0
- package/dist/read-router/routing-tables.js.map +1 -0
- package/dist/read-router/select-strategy.d.ts +42 -0
- package/dist/read-router/select-strategy.d.ts.map +1 -0
- package/dist/read-router/select-strategy.js +92 -0
- package/dist/read-router/select-strategy.js.map +1 -0
- package/package.json +16 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentOS IngestRouter Module
|
|
3
|
+
*
|
|
4
|
+
* Input-stage LLM-as-judge orchestrator for memory ingest. Sibling of
|
|
5
|
+
* {@link MemoryRouter} (recall-stage), {@link QueryRouter} (Q&A-stage),
|
|
6
|
+
* and the output-stage guardrails. Together they form the agentos
|
|
7
|
+
* multi-stage guardrails pattern.
|
|
8
|
+
*
|
|
9
|
+
* Where MemoryRouter picks the recall architecture for a query,
|
|
10
|
+
* IngestRouter picks the storage architecture for incoming content. The
|
|
11
|
+
* choice affects what's STORED, which downstream MemoryRouter then queries.
|
|
12
|
+
*
|
|
13
|
+
* **Architecture Overview:**
|
|
14
|
+
* ```
|
|
15
|
+
* Content stream
|
|
16
|
+
* │
|
|
17
|
+
* ▼
|
|
18
|
+
* ┌────────────────────────────────────────────────┐
|
|
19
|
+
* │ IngestRouter │
|
|
20
|
+
* │ classify content → pick strategy → store │
|
|
21
|
+
* └────────────────────────────────────────────────┘
|
|
22
|
+
* │ │ │
|
|
23
|
+
* ▼ ▼ ▼
|
|
24
|
+
* raw-chunks summarized observational
|
|
25
|
+
* fact-graph hybrid skip
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @module @framers/agentos/ingest-router
|
|
29
|
+
*/
|
|
30
|
+
export { INGEST_CONTENT_KINDS } from './routing-tables.js';
|
|
31
|
+
export { RAW_CHUNKS_TABLE, SUMMARIZED_TABLE, OBSERVATIONAL_TABLE, HYBRID_TABLE, PRESET_INGEST_TABLES, } from './routing-tables.js';
|
|
32
|
+
export { RAW_CHUNKS_COST, SUMMARIZED_COST, OBSERVATIONAL_COST, FACT_GRAPH_COST, HYBRID_COST, SKIP_COST, DEFAULT_INGEST_COSTS, } from './costs.js';
|
|
33
|
+
export { selectIngestStrategy, IngestRouterUnknownKindError, IngestRouterBudgetExceededError, } from './select-strategy.js';
|
|
34
|
+
export { INGEST_CLASSIFIER_SYSTEM_PROMPT, INGEST_CLASSIFIER_SYSTEM_PROMPT_FEWSHOT, SAFE_INGEST_FALLBACK_KIND, LLMIngestClassifier, normalizeIngestClassifierOutput, parseIngestClassifierOutput, } from './classifier.js';
|
|
35
|
+
export { FunctionIngestDispatcher, UnsupportedIngestStrategyError, } from './dispatcher.js';
|
|
36
|
+
export { IngestRouter, IngestRouterDispatcherMissingError, } from './IngestRouter.js';
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ingest-router/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAQH,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAoC3D,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,SAAS,EACT,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,oBAAoB,EACpB,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,+BAA+B,EAC/B,uCAAuC,EACvC,yBAAyB,EACzB,mBAAmB,EACnB,+BAA+B,EAC/B,2BAA2B,GAC5B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,wBAAwB,EACxB,8BAA8B,GAC/B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,YAAY,EACZ,kCAAkC,GACnC,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
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
|
+
* The six content kinds the LLM-as-judge ingest classifier can emit.
|
|
29
|
+
* Coarse taxonomy chosen to map cleanly onto distinct ingest strategies —
|
|
30
|
+
* extending the taxonomy means extending the routing tables consistently.
|
|
31
|
+
*/
|
|
32
|
+
export declare const INGEST_CONTENT_KINDS: readonly ["short-conversation", "long-conversation", "long-article", "code", "structured-data", "multimodal"];
|
|
33
|
+
export type IngestContentKind = (typeof INGEST_CONTENT_KINDS)[number];
|
|
34
|
+
/**
|
|
35
|
+
* The six storage strategies an IngestDispatcher can execute.
|
|
36
|
+
*
|
|
37
|
+
* - `raw-chunks`: standard turn-by-turn (or semantic) chunking, no LLM at
|
|
38
|
+
* ingest. The Memory.remember() default.
|
|
39
|
+
* - `summarized`: every chunk prepended with a dense session/document
|
|
40
|
+
* summary before embedding (Anthropic Sep 2024 "contextual retrieval").
|
|
41
|
+
* One LLM summarize call per session/document at ingest time.
|
|
42
|
+
* - `observational`: extract a structured observation log from the content
|
|
43
|
+
* (Mastra Observational Memory pattern). Multiple LLM extraction calls
|
|
44
|
+
* per session at ingest time. Recalled traces are observations rather
|
|
45
|
+
* than raw turns.
|
|
46
|
+
* - `fact-graph`: extract atomic fact triples from the content (Mem0-style).
|
|
47
|
+
* LLM-triple-extraction at ingest. Recall queries the fact graph.
|
|
48
|
+
* - `hybrid`: apply multiple strategies in parallel (e.g., raw-chunks +
|
|
49
|
+
* summarized + observational). Most expensive at ingest. Highest recall
|
|
50
|
+
* flexibility.
|
|
51
|
+
* - `skip`: do not ingest the content. For low-value session noise that
|
|
52
|
+
* wastes recall slots and inflates retrieval cost.
|
|
53
|
+
*/
|
|
54
|
+
export type IngestStrategyId = 'raw-chunks' | 'summarized' | 'observational' | 'fact-graph' | 'hybrid' | 'skip';
|
|
55
|
+
/**
|
|
56
|
+
* The shipping preset names. Each names a cost-vs-recall point.
|
|
57
|
+
*/
|
|
58
|
+
export type IngestRouterPreset = 'raw-chunks' | 'summarized' | 'observational' | 'hybrid';
|
|
59
|
+
/**
|
|
60
|
+
* A routing table maps every {@link IngestContentKind} to its preferred
|
|
61
|
+
* {@link IngestStrategyId}. Tables are frozen so consumers cannot mutate
|
|
62
|
+
* the routing surface from outside the module.
|
|
63
|
+
*/
|
|
64
|
+
export interface IngestRoutingTable {
|
|
65
|
+
readonly preset: IngestRouterPreset;
|
|
66
|
+
readonly defaultMapping: Readonly<Record<IngestContentKind, IngestStrategyId>>;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Preset: raw-chunks (default for cost-sensitive workloads).
|
|
70
|
+
*
|
|
71
|
+
* Stores everything as raw chunks regardless of content kind. Zero LLM
|
|
72
|
+
* cost at ingest time. All complexity is pushed to retrieval where the
|
|
73
|
+
* MemoryRouter can compose hybrid retrieval over the raw chunks.
|
|
74
|
+
*
|
|
75
|
+
* Recommended when: ingest volume is high, retrieval-side compute is
|
|
76
|
+
* cheap, and you trust the retrieval stage to do the heavy lifting.
|
|
77
|
+
*/
|
|
78
|
+
export declare const RAW_CHUNKS_TABLE: IngestRoutingTable;
|
|
79
|
+
/**
|
|
80
|
+
* Preset: summarized (contextual retrieval for long content).
|
|
81
|
+
*
|
|
82
|
+
* Long content (long-conversation, long-article) gets a session/document
|
|
83
|
+
* summary prepended to every chunk before embedding. Short content stays
|
|
84
|
+
* as raw chunks. Code and structured data are summarized for the
|
|
85
|
+
* cross-file context. Multimodal stays raw — embedding modality is
|
|
86
|
+
* orthogonal to summarization.
|
|
87
|
+
*
|
|
88
|
+
* Recommended when: documents and conversations have meaningful global
|
|
89
|
+
* context that improves retrieval recall.
|
|
90
|
+
*/
|
|
91
|
+
export declare const SUMMARIZED_TABLE: IngestRoutingTable;
|
|
92
|
+
/**
|
|
93
|
+
* Preset: observational (Mastra-style for multi-session synthesis).
|
|
94
|
+
*
|
|
95
|
+
* Long conversational content (long-conversation) becomes a structured
|
|
96
|
+
* observation log via LLM extraction at ingest. Long articles get the
|
|
97
|
+
* cheaper summarized treatment. Short content, code, structured, and
|
|
98
|
+
* multimodal stay raw.
|
|
99
|
+
*
|
|
100
|
+
* Recommended when: workload is conversational and includes many
|
|
101
|
+
* multi-session synthesis questions ("what have we agreed to so far",
|
|
102
|
+
* "across our chats, what topics recur").
|
|
103
|
+
*/
|
|
104
|
+
export declare const OBSERVATIONAL_TABLE: IngestRoutingTable;
|
|
105
|
+
/**
|
|
106
|
+
* Preset: hybrid (maximum-recall workloads).
|
|
107
|
+
*
|
|
108
|
+
* Applies multiple ingest strategies in parallel for long content. Every
|
|
109
|
+
* downstream retrieval architecture has its substrate (raw chunks for
|
|
110
|
+
* canonical hybrid, summary prefix for contextual retrieval, observation
|
|
111
|
+
* log for OM-style synthesis). Highest cost at ingest; highest flexibility
|
|
112
|
+
* at retrieval.
|
|
113
|
+
*
|
|
114
|
+
* Recommended when: cost-per-ingest is acceptable AND retrieval workload
|
|
115
|
+
* is heterogeneous enough that no single strategy dominates.
|
|
116
|
+
*/
|
|
117
|
+
export declare const HYBRID_TABLE: IngestRoutingTable;
|
|
118
|
+
/**
|
|
119
|
+
* Preset registry keyed by name.
|
|
120
|
+
*/
|
|
121
|
+
export declare const PRESET_INGEST_TABLES: Readonly<Record<IngestRouterPreset, IngestRoutingTable>>;
|
|
122
|
+
//# sourceMappingURL=routing-tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing-tables.d.ts","sourceRoot":"","sources":["../../src/ingest-router/routing-tables.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,+GAOvB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,YAAY,GACZ,eAAe,GACf,YAAY,GACZ,QAAQ,GACR,MAAM,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B,YAAY,GACZ,YAAY,GACZ,eAAe,GACf,QAAQ,CAAC;AAEb;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAC/B,MAAM,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,CAC5C,CAAC;CACH;AAMD;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,EAAE,kBAUP,CAAC;AAEzB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,EAAE,kBAUP,CAAC;AAEzB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,EAAE,kBAUV,CAAC;AAEzB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,EAAE,kBAUH,CAAC;AAEzB;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CACzC,MAAM,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAM9C,CAAC"}
|
|
@@ -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"}
|