@blockrun/clawrouter 0.12.95 → 0.12.97
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/auth.d.ts +82 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +388 -0
- package/dist/auth.js.map +1 -0
- package/dist/balance.d.ts +97 -0
- package/dist/balance.d.ts.map +1 -0
- package/dist/balance.js +157 -0
- package/dist/balance.js.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +256 -54994
- package/dist/cli.js.map +1 -1
- package/dist/compression/codebook.d.ts +24 -0
- package/dist/compression/codebook.d.ts.map +1 -0
- package/dist/compression/codebook.js +119 -0
- package/dist/compression/codebook.js.map +1 -0
- package/dist/compression/index.d.ts +33 -0
- package/dist/compression/index.d.ts.map +1 -0
- package/dist/compression/index.js +246 -0
- package/dist/compression/index.js.map +1 -0
- package/dist/compression/layers/deduplication.d.ts +28 -0
- package/dist/compression/layers/deduplication.d.ts.map +1 -0
- package/dist/compression/layers/deduplication.js +101 -0
- package/dist/compression/layers/deduplication.js.map +1 -0
- package/dist/compression/layers/dictionary.d.ts +21 -0
- package/dist/compression/layers/dictionary.d.ts.map +1 -0
- package/dist/compression/layers/dictionary.js +73 -0
- package/dist/compression/layers/dictionary.js.map +1 -0
- package/dist/compression/layers/dynamic-codebook.d.ts +26 -0
- package/dist/compression/layers/dynamic-codebook.d.ts.map +1 -0
- package/dist/compression/layers/dynamic-codebook.js +149 -0
- package/dist/compression/layers/dynamic-codebook.js.map +1 -0
- package/dist/compression/layers/json-compact.d.ts +23 -0
- package/dist/compression/layers/json-compact.d.ts.map +1 -0
- package/dist/compression/layers/json-compact.js +79 -0
- package/dist/compression/layers/json-compact.js.map +1 -0
- package/dist/compression/layers/observation.d.ts +21 -0
- package/dist/compression/layers/observation.d.ts.map +1 -0
- package/dist/compression/layers/observation.js +130 -0
- package/dist/compression/layers/observation.js.map +1 -0
- package/dist/compression/layers/paths.d.ts +24 -0
- package/dist/compression/layers/paths.d.ts.map +1 -0
- package/dist/compression/layers/paths.js +110 -0
- package/dist/compression/layers/paths.js.map +1 -0
- package/dist/compression/layers/whitespace.d.ts +27 -0
- package/dist/compression/layers/whitespace.d.ts.map +1 -0
- package/dist/compression/layers/whitespace.js +60 -0
- package/dist/compression/layers/whitespace.js.map +1 -0
- package/dist/compression/types.d.ts +84 -0
- package/dist/compression/types.d.ts.map +1 -0
- package/dist/compression/types.js +27 -0
- package/dist/compression/types.js.map +1 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +22 -0
- package/dist/config.js.map +1 -0
- package/dist/dedup.d.ts +34 -0
- package/dist/dedup.d.ts.map +1 -0
- package/dist/dedup.js +150 -0
- package/dist/dedup.js.map +1 -0
- package/dist/doctor.d.ts +8 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +375 -0
- package/dist/doctor.js.map +1 -0
- package/dist/error-classification.test.d.ts +2 -0
- package/dist/error-classification.test.d.ts.map +1 -0
- package/dist/error-classification.test.js +59 -0
- package/dist/error-classification.test.js.map +1 -0
- package/dist/errors.d.ts +54 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +85 -0
- package/dist/errors.js.map +1 -0
- package/dist/exclude-models.d.ts +28 -0
- package/dist/exclude-models.d.ts.map +1 -0
- package/dist/exclude-models.integration.test.d.ts +2 -0
- package/dist/exclude-models.integration.test.d.ts.map +1 -0
- package/dist/exclude-models.integration.test.js +46 -0
- package/dist/exclude-models.integration.test.js.map +1 -0
- package/dist/exclude-models.js +70 -0
- package/dist/exclude-models.js.map +1 -0
- package/dist/exclude-models.test.d.ts +5 -0
- package/dist/exclude-models.test.d.ts.map +1 -0
- package/dist/exclude-models.test.js +95 -0
- package/dist/exclude-models.test.js.map +1 -0
- package/dist/fs-read.d.ts +11 -0
- package/dist/fs-read.d.ts.map +1 -0
- package/dist/fs-read.js +47 -0
- package/dist/fs-read.js.map +1 -0
- package/dist/index.d.ts +34 -1368
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1071 -56194
- package/dist/index.js.map +1 -1
- package/dist/journal.d.ts +67 -0
- package/dist/journal.d.ts.map +1 -0
- package/dist/journal.js +184 -0
- package/dist/journal.js.map +1 -0
- package/dist/journal.test.d.ts +2 -0
- package/dist/journal.test.d.ts.map +1 -0
- package/dist/journal.test.js +201 -0
- package/dist/journal.test.js.map +1 -0
- package/dist/logger.d.ts +33 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +35 -0
- package/dist/logger.js.map +1 -0
- package/dist/models.d.ts +107 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +941 -0
- package/dist/models.js.map +1 -0
- package/dist/models.test.d.ts +2 -0
- package/dist/models.test.d.ts.map +1 -0
- package/dist/models.test.js +38 -0
- package/dist/models.test.js.map +1 -0
- package/dist/partners/index.d.ts +8 -0
- package/dist/partners/index.d.ts.map +1 -0
- package/dist/partners/index.js +6 -0
- package/dist/partners/index.js.map +1 -0
- package/dist/partners/registry.d.ts +51 -0
- package/dist/partners/registry.d.ts.map +1 -0
- package/dist/partners/registry.js +256 -0
- package/dist/partners/registry.js.map +1 -0
- package/dist/partners/tools.d.ts +24 -0
- package/dist/partners/tools.d.ts.map +1 -0
- package/dist/partners/tools.js +97 -0
- package/dist/partners/tools.js.map +1 -0
- package/dist/payment-preauth.d.ts +17 -0
- package/dist/payment-preauth.d.ts.map +1 -0
- package/dist/payment-preauth.js +102 -0
- package/dist/payment-preauth.js.map +1 -0
- package/dist/provider.d.ts +19 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +45 -0
- package/dist/provider.js.map +1 -0
- package/dist/proxy.d.ts +210 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.debrand.test.d.ts +2 -0
- package/dist/proxy.debrand.test.d.ts.map +1 -0
- package/dist/proxy.debrand.test.js +101 -0
- package/dist/proxy.debrand.test.js.map +1 -0
- package/dist/proxy.degraded-response.test.d.ts +2 -0
- package/dist/proxy.degraded-response.test.d.ts.map +1 -0
- package/dist/proxy.degraded-response.test.js +105 -0
- package/dist/proxy.degraded-response.test.js.map +1 -0
- package/dist/proxy.image-download.test.d.ts +2 -0
- package/dist/proxy.image-download.test.d.ts.map +1 -0
- package/dist/proxy.image-download.test.js +92 -0
- package/dist/proxy.image-download.test.js.map +1 -0
- package/dist/proxy.js +3810 -0
- package/dist/proxy.js.map +1 -0
- package/dist/proxy.models-endpoint.test.d.ts +2 -0
- package/dist/proxy.models-endpoint.test.d.ts.map +1 -0
- package/dist/proxy.models-endpoint.test.js +19 -0
- package/dist/proxy.models-endpoint.test.js.map +1 -0
- package/dist/proxy.multiturn-thinking.test.d.ts +2 -0
- package/dist/proxy.multiturn-thinking.test.d.ts.map +1 -0
- package/dist/proxy.multiturn-thinking.test.js +82 -0
- package/dist/proxy.multiturn-thinking.test.js.map +1 -0
- package/dist/proxy.payment-chain-reuse.test.d.ts +2 -0
- package/dist/proxy.payment-chain-reuse.test.d.ts.map +1 -0
- package/dist/proxy.payment-chain-reuse.test.js +30 -0
- package/dist/proxy.payment-chain-reuse.test.js.map +1 -0
- package/dist/proxy.solana-resilience.test.d.ts +12 -0
- package/dist/proxy.solana-resilience.test.d.ts.map +1 -0
- package/dist/proxy.solana-resilience.test.js +39 -0
- package/dist/proxy.solana-resilience.test.js.map +1 -0
- package/dist/report.d.ts +6 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +44 -0
- package/dist/report.js.map +1 -0
- package/dist/response-cache.advanced.test.d.ts +2 -0
- package/dist/response-cache.advanced.test.d.ts.map +1 -0
- package/dist/response-cache.advanced.test.js +566 -0
- package/dist/response-cache.advanced.test.js.map +1 -0
- package/dist/response-cache.d.ts +85 -0
- package/dist/response-cache.d.ts.map +1 -0
- package/dist/response-cache.edge-cases.test.d.ts +2 -0
- package/dist/response-cache.edge-cases.test.d.ts.map +1 -0
- package/dist/response-cache.edge-cases.test.js +488 -0
- package/dist/response-cache.edge-cases.test.js.map +1 -0
- package/dist/response-cache.extreme.test.d.ts +2 -0
- package/dist/response-cache.extreme.test.d.ts.map +1 -0
- package/dist/response-cache.extreme.test.js +561 -0
- package/dist/response-cache.extreme.test.js.map +1 -0
- package/dist/response-cache.js +240 -0
- package/dist/response-cache.js.map +1 -0
- package/dist/response-cache.test.d.ts +2 -0
- package/dist/response-cache.test.d.ts.map +1 -0
- package/dist/response-cache.test.js +242 -0
- package/dist/response-cache.test.js.map +1 -0
- package/dist/retry.d.ts +42 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +99 -0
- package/dist/retry.js.map +1 -0
- package/dist/router/config.d.ts +11 -0
- package/dist/router/config.d.ts.map +1 -0
- package/dist/router/config.js +1215 -0
- package/dist/router/config.js.map +1 -0
- package/dist/router/index.d.ts +18 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +19 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router/llm-classifier.d.ts +29 -0
- package/dist/router/llm-classifier.d.ts.map +1 -0
- package/dist/router/llm-classifier.js +99 -0
- package/dist/router/llm-classifier.js.map +1 -0
- package/dist/router/rules.d.ts +12 -0
- package/dist/router/rules.d.ts.map +1 -0
- package/dist/router/rules.js +202 -0
- package/dist/router/rules.js.map +1 -0
- package/dist/router/selector.d.ts +58 -0
- package/dist/router/selector.d.ts.map +1 -0
- package/dist/router/selector.js +165 -0
- package/dist/router/selector.js.map +1 -0
- package/dist/router/selector.test.d.ts +2 -0
- package/dist/router/selector.test.d.ts.map +1 -0
- package/dist/router/selector.test.js +67 -0
- package/dist/router/selector.test.js.map +1 -0
- package/dist/router/strategy.d.ts +19 -0
- package/dist/router/strategy.d.ts.map +1 -0
- package/dist/router/strategy.js +138 -0
- package/dist/router/strategy.js.map +1 -0
- package/dist/router/strategy.test.d.ts +2 -0
- package/dist/router/strategy.test.d.ts.map +1 -0
- package/dist/router/strategy.test.js +131 -0
- package/dist/router/strategy.test.js.map +1 -0
- package/dist/router/types.d.ts +127 -0
- package/dist/router/types.d.ts.map +1 -0
- package/dist/router/types.js +11 -0
- package/dist/router/types.js.map +1 -0
- package/dist/session.d.ts +124 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +256 -0
- package/dist/session.js.map +1 -0
- package/dist/session.test.d.ts +2 -0
- package/dist/session.test.d.ts.map +1 -0
- package/dist/session.test.js +163 -0
- package/dist/session.test.js.map +1 -0
- package/dist/solana-balance.d.ts +48 -0
- package/dist/solana-balance.d.ts.map +1 -0
- package/dist/solana-balance.js +142 -0
- package/dist/solana-balance.js.map +1 -0
- package/dist/spend-control.d.ts +112 -0
- package/dist/spend-control.d.ts.map +1 -0
- package/dist/spend-control.js +278 -0
- package/dist/spend-control.js.map +1 -0
- package/dist/spend-control.test.d.ts +5 -0
- package/dist/spend-control.test.d.ts.map +1 -0
- package/dist/spend-control.test.js +210 -0
- package/dist/spend-control.test.js.map +1 -0
- package/dist/stats.d.ts +64 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +295 -0
- package/dist/stats.js.map +1 -0
- package/dist/types.d.ts +150 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/update-hint.test.d.ts +9 -0
- package/dist/update-hint.test.d.ts.map +1 -0
- package/dist/update-hint.test.js +156 -0
- package/dist/update-hint.test.js.map +1 -0
- package/dist/updater.d.ts +10 -0
- package/dist/updater.d.ts.map +1 -0
- package/dist/updater.js +55 -0
- package/dist/updater.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +16 -0
- package/dist/version.js.map +1 -0
- package/dist/wallet.d.ts +52 -0
- package/dist/wallet.d.ts.map +1 -0
- package/dist/wallet.js +93 -0
- package/dist/wallet.js.map +1 -0
- package/dist/wallet.test.d.ts +6 -0
- package/dist/wallet.test.d.ts.map +1 -0
- package/dist/wallet.test.js +117 -0
- package/dist/wallet.test.js.map +1 -0
- package/dist/x402-sdk.test.d.ts +6 -0
- package/dist/x402-sdk.test.d.ts.map +1 -0
- package/dist/x402-sdk.test.js +161 -0
- package/dist/x402-sdk.test.js.map +1 -0
- package/package.json +1 -1
- package/scripts/e2e-multiturn.mjs +4 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Router Types
|
|
3
|
+
*
|
|
4
|
+
* Four classification tiers — REASONING is distinct from COMPLEX because
|
|
5
|
+
* reasoning tasks need different models (o3, gemini-pro) than general
|
|
6
|
+
* complex tasks (gpt-4o, sonnet-4).
|
|
7
|
+
*
|
|
8
|
+
* Scoring uses weighted float dimensions with sigmoid confidence calibration.
|
|
9
|
+
*/
|
|
10
|
+
export type Tier = "SIMPLE" | "MEDIUM" | "COMPLEX" | "REASONING";
|
|
11
|
+
export type ScoringResult = {
|
|
12
|
+
score: number;
|
|
13
|
+
tier: Tier | null;
|
|
14
|
+
confidence: number;
|
|
15
|
+
signals: string[];
|
|
16
|
+
agenticScore?: number;
|
|
17
|
+
dimensions?: Array<{
|
|
18
|
+
name: string;
|
|
19
|
+
score: number;
|
|
20
|
+
signal: string | null;
|
|
21
|
+
}>;
|
|
22
|
+
};
|
|
23
|
+
export type RoutingDecision = {
|
|
24
|
+
model: string;
|
|
25
|
+
tier: Tier;
|
|
26
|
+
confidence: number;
|
|
27
|
+
method: "rules" | "llm";
|
|
28
|
+
reasoning: string;
|
|
29
|
+
costEstimate: number;
|
|
30
|
+
baselineCost: number;
|
|
31
|
+
savings: number;
|
|
32
|
+
agenticScore?: number;
|
|
33
|
+
/** Which tier configs were used (auto/eco/premium/agentic) — avoids re-derivation in proxy */
|
|
34
|
+
tierConfigs?: Record<Tier, TierConfig>;
|
|
35
|
+
/** Which routing profile was applied */
|
|
36
|
+
profile?: "auto" | "eco" | "premium" | "agentic";
|
|
37
|
+
};
|
|
38
|
+
export interface RouterStrategy {
|
|
39
|
+
readonly name: string;
|
|
40
|
+
route(prompt: string, systemPrompt: string | undefined, maxOutputTokens: number, options: RouterOptions): RoutingDecision;
|
|
41
|
+
}
|
|
42
|
+
export type RouterOptions = {
|
|
43
|
+
config: RoutingConfig;
|
|
44
|
+
modelPricing: Map<string, import("./selector.js").ModelPricing>;
|
|
45
|
+
routingProfile?: "eco" | "auto" | "premium";
|
|
46
|
+
hasTools?: boolean;
|
|
47
|
+
};
|
|
48
|
+
export type TierConfig = {
|
|
49
|
+
primary: string;
|
|
50
|
+
fallback: string[];
|
|
51
|
+
};
|
|
52
|
+
export type ScoringConfig = {
|
|
53
|
+
tokenCountThresholds: {
|
|
54
|
+
simple: number;
|
|
55
|
+
complex: number;
|
|
56
|
+
};
|
|
57
|
+
codeKeywords: string[];
|
|
58
|
+
reasoningKeywords: string[];
|
|
59
|
+
simpleKeywords: string[];
|
|
60
|
+
technicalKeywords: string[];
|
|
61
|
+
creativeKeywords: string[];
|
|
62
|
+
imperativeVerbs: string[];
|
|
63
|
+
constraintIndicators: string[];
|
|
64
|
+
outputFormatKeywords: string[];
|
|
65
|
+
referenceKeywords: string[];
|
|
66
|
+
negationKeywords: string[];
|
|
67
|
+
domainSpecificKeywords: string[];
|
|
68
|
+
agenticTaskKeywords: string[];
|
|
69
|
+
dimensionWeights: Record<string, number>;
|
|
70
|
+
tierBoundaries: {
|
|
71
|
+
simpleMedium: number;
|
|
72
|
+
mediumComplex: number;
|
|
73
|
+
complexReasoning: number;
|
|
74
|
+
};
|
|
75
|
+
confidenceSteepness: number;
|
|
76
|
+
confidenceThreshold: number;
|
|
77
|
+
};
|
|
78
|
+
export type ClassifierConfig = {
|
|
79
|
+
llmModel: string;
|
|
80
|
+
llmMaxTokens: number;
|
|
81
|
+
llmTemperature: number;
|
|
82
|
+
promptTruncationChars: number;
|
|
83
|
+
cacheTtlMs: number;
|
|
84
|
+
};
|
|
85
|
+
export type OverridesConfig = {
|
|
86
|
+
maxTokensForceComplex: number;
|
|
87
|
+
structuredOutputMinTier: Tier;
|
|
88
|
+
ambiguousDefaultTier: Tier;
|
|
89
|
+
/**
|
|
90
|
+
* When enabled, prefer models optimized for agentic workflows.
|
|
91
|
+
* Agentic models continue autonomously with multi-step tasks
|
|
92
|
+
* instead of stopping and waiting for user input.
|
|
93
|
+
*/
|
|
94
|
+
agenticMode?: boolean;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Time-windowed promotion that temporarily overrides tier routing.
|
|
98
|
+
* Active promotions are auto-applied; expired ones are ignored at runtime.
|
|
99
|
+
*/
|
|
100
|
+
export type Promotion = {
|
|
101
|
+
/** Human-readable label (e.g. "GLM-5 Launch Promo") */
|
|
102
|
+
name: string;
|
|
103
|
+
/** ISO date string, promotion starts (inclusive). e.g. "2026-04-01" */
|
|
104
|
+
startDate: string;
|
|
105
|
+
/** ISO date string, promotion ends (exclusive). e.g. "2026-04-15" */
|
|
106
|
+
endDate: string;
|
|
107
|
+
/** Partial tier overrides — merged into the active tier configs (primary/fallback) */
|
|
108
|
+
tierOverrides: Partial<Record<Tier, Partial<TierConfig>>>;
|
|
109
|
+
/** Which profiles this applies to. Default: all profiles. */
|
|
110
|
+
profiles?: Array<"auto" | "eco" | "premium" | "agentic">;
|
|
111
|
+
};
|
|
112
|
+
export type RoutingConfig = {
|
|
113
|
+
version: string;
|
|
114
|
+
classifier: ClassifierConfig;
|
|
115
|
+
scoring: ScoringConfig;
|
|
116
|
+
tiers: Record<Tier, TierConfig>;
|
|
117
|
+
/** Tier configs for agentic mode - models that excel at multi-step tasks */
|
|
118
|
+
agenticTiers?: Record<Tier, TierConfig>;
|
|
119
|
+
/** Tier configs for eco profile - ultra cost-optimized (blockrun/eco) */
|
|
120
|
+
ecoTiers?: Record<Tier, TierConfig>;
|
|
121
|
+
/** Tier configs for premium profile - best quality (blockrun/premium) */
|
|
122
|
+
premiumTiers?: Record<Tier, TierConfig>;
|
|
123
|
+
/** Time-windowed promotions that temporarily override tier routing */
|
|
124
|
+
promotions?: Promotion[];
|
|
125
|
+
overrides: OverridesConfig;
|
|
126
|
+
};
|
|
127
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/router/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Router Types
|
|
3
|
+
*
|
|
4
|
+
* Four classification tiers — REASONING is distinct from COMPLEX because
|
|
5
|
+
* reasoning tasks need different models (o3, gemini-pro) than general
|
|
6
|
+
* complex tasks (gpt-4o, sonnet-4).
|
|
7
|
+
*
|
|
8
|
+
* Scoring uses weighted float dimensions with sigmoid confidence calibration.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/router/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Persistence Store
|
|
3
|
+
*
|
|
4
|
+
* Tracks model selections per session to prevent model switching mid-task.
|
|
5
|
+
* When a session is active, the router will continue using the same model
|
|
6
|
+
* instead of re-routing each request.
|
|
7
|
+
*/
|
|
8
|
+
export type SessionEntry = {
|
|
9
|
+
model: string;
|
|
10
|
+
tier: string;
|
|
11
|
+
createdAt: number;
|
|
12
|
+
lastUsedAt: number;
|
|
13
|
+
requestCount: number;
|
|
14
|
+
recentHashes: string[];
|
|
15
|
+
strikes: number;
|
|
16
|
+
escalated: boolean;
|
|
17
|
+
sessionCostMicros: bigint;
|
|
18
|
+
};
|
|
19
|
+
export type SessionConfig = {
|
|
20
|
+
/** Enable session persistence (default: false) */
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
/** Session timeout in ms (default: 30 minutes) */
|
|
23
|
+
timeoutMs: number;
|
|
24
|
+
/** Header name for session ID (default: X-Session-ID) */
|
|
25
|
+
headerName: string;
|
|
26
|
+
};
|
|
27
|
+
export declare const DEFAULT_SESSION_CONFIG: SessionConfig;
|
|
28
|
+
/**
|
|
29
|
+
* Session persistence store for maintaining model selections.
|
|
30
|
+
*/
|
|
31
|
+
export declare class SessionStore {
|
|
32
|
+
private sessions;
|
|
33
|
+
private config;
|
|
34
|
+
private cleanupInterval;
|
|
35
|
+
constructor(config?: Partial<SessionConfig>);
|
|
36
|
+
/**
|
|
37
|
+
* Get the pinned model for a session, if any.
|
|
38
|
+
*/
|
|
39
|
+
getSession(sessionId: string): SessionEntry | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Pin a model to a session.
|
|
42
|
+
*/
|
|
43
|
+
setSession(sessionId: string, model: string, tier: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Touch a session to extend its timeout.
|
|
46
|
+
*/
|
|
47
|
+
touchSession(sessionId: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Clear a specific session.
|
|
50
|
+
*/
|
|
51
|
+
clearSession(sessionId: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Clear all sessions.
|
|
54
|
+
*/
|
|
55
|
+
clearAll(): void;
|
|
56
|
+
/**
|
|
57
|
+
* Get session stats for debugging.
|
|
58
|
+
*/
|
|
59
|
+
getStats(): {
|
|
60
|
+
count: number;
|
|
61
|
+
sessions: Array<{
|
|
62
|
+
id: string;
|
|
63
|
+
model: string;
|
|
64
|
+
age: number;
|
|
65
|
+
}>;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Clean up expired sessions.
|
|
69
|
+
*/
|
|
70
|
+
private cleanup;
|
|
71
|
+
/**
|
|
72
|
+
* Record a request content hash and detect repetitive patterns.
|
|
73
|
+
* Returns true if escalation should be triggered (3+ consecutive similar requests).
|
|
74
|
+
*/
|
|
75
|
+
recordRequestHash(sessionId: string, hash: string): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Escalate session to next tier. Returns the new model/tier or null if already at max.
|
|
78
|
+
*/
|
|
79
|
+
escalateSession(sessionId: string, tierConfigs: Record<string, {
|
|
80
|
+
primary: string;
|
|
81
|
+
fallback: string[];
|
|
82
|
+
}>): {
|
|
83
|
+
model: string;
|
|
84
|
+
tier: string;
|
|
85
|
+
} | null;
|
|
86
|
+
/**
|
|
87
|
+
* Add cost to a session's running total for maxCostPerRun tracking.
|
|
88
|
+
* Cost is in USDC 6-decimal units (micros).
|
|
89
|
+
* Creates a cost-tracking-only entry if none exists (e.g., explicit model requests
|
|
90
|
+
* that never go through the routing path).
|
|
91
|
+
*/
|
|
92
|
+
addSessionCost(sessionId: string, additionalMicros: bigint): void;
|
|
93
|
+
/**
|
|
94
|
+
* Get the total accumulated cost for a session in USD.
|
|
95
|
+
*/
|
|
96
|
+
getSessionCostUsd(sessionId: string): number;
|
|
97
|
+
/**
|
|
98
|
+
* Stop the cleanup interval.
|
|
99
|
+
*/
|
|
100
|
+
close(): void;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Generate a session ID from request headers or create a default.
|
|
104
|
+
*/
|
|
105
|
+
export declare function getSessionId(headers: Record<string, string | string[] | undefined>, headerName?: string): string | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Derive a stable session ID from message content when no explicit session
|
|
108
|
+
* header is provided. Uses the first user message as the conversation anchor —
|
|
109
|
+
* same opening message = same session ID across all subsequent turns.
|
|
110
|
+
*
|
|
111
|
+
* This prevents model-switching mid-conversation even when OpenClaw doesn't
|
|
112
|
+
* send an x-session-id header (which is the default OpenClaw behaviour).
|
|
113
|
+
*/
|
|
114
|
+
export declare function deriveSessionId(messages: Array<{
|
|
115
|
+
role: string;
|
|
116
|
+
content: unknown;
|
|
117
|
+
}>): string | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* Generate a short hash fingerprint from request content.
|
|
120
|
+
* Captures: last user message text + tool call names (if any).
|
|
121
|
+
* Normalizes whitespace to avoid false negatives from minor formatting diffs.
|
|
122
|
+
*/
|
|
123
|
+
export declare function hashRequestContent(lastUserContent: string, toolCallNames?: string[]): string;
|
|
124
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IAErB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IAEnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,kDAAkD;IAClD,OAAO,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,aAIpC,CAAC;AAEF;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAwC;IACxD,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,eAAe,CAA+C;gBAE1D,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM;IAS/C;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAoBvD;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IA+BhE;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAYrC;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIrC;;OAEG;IACH,QAAQ,IAAI,IAAI;IAIhB;;OAEG;IACH,QAAQ,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,KAAK,CAAC;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE;IAU1F;;OAEG;IACH,OAAO,CAAC,OAAO;IASf;;;OAGG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IAmB3D;;OAEG;IACH,eAAe,CACb,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,GACnE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAoBzC;;;;;OAKG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAoBjE;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAM5C;;OAEG;IACH,KAAK,IAAI,IAAI;CAMd;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EACtD,UAAU,GAAE,MAA0C,GACrD,MAAM,GAAG,SAAS,CASpB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,GAClD,MAAM,GAAG,SAAS,CAUpB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,eAAe,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAO5F"}
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Persistence Store
|
|
3
|
+
*
|
|
4
|
+
* Tracks model selections per session to prevent model switching mid-task.
|
|
5
|
+
* When a session is active, the router will continue using the same model
|
|
6
|
+
* instead of re-routing each request.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
export const DEFAULT_SESSION_CONFIG = {
|
|
10
|
+
enabled: true,
|
|
11
|
+
timeoutMs: 30 * 60 * 1000, // 30 minutes
|
|
12
|
+
headerName: "x-session-id",
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Session persistence store for maintaining model selections.
|
|
16
|
+
*/
|
|
17
|
+
export class SessionStore {
|
|
18
|
+
sessions = new Map();
|
|
19
|
+
config;
|
|
20
|
+
cleanupInterval = null;
|
|
21
|
+
constructor(config = {}) {
|
|
22
|
+
this.config = { ...DEFAULT_SESSION_CONFIG, ...config };
|
|
23
|
+
// Start cleanup interval (every 5 minutes)
|
|
24
|
+
if (this.config.enabled) {
|
|
25
|
+
this.cleanupInterval = setInterval(() => this.cleanup(), 5 * 60 * 1000);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get the pinned model for a session, if any.
|
|
30
|
+
*/
|
|
31
|
+
getSession(sessionId) {
|
|
32
|
+
if (!this.config.enabled || !sessionId) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const entry = this.sessions.get(sessionId);
|
|
36
|
+
if (!entry) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
// Check if session has expired
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
if (now - entry.lastUsedAt > this.config.timeoutMs) {
|
|
42
|
+
this.sessions.delete(sessionId);
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
return entry;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Pin a model to a session.
|
|
49
|
+
*/
|
|
50
|
+
setSession(sessionId, model, tier) {
|
|
51
|
+
if (!this.config.enabled || !sessionId) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const existing = this.sessions.get(sessionId);
|
|
55
|
+
const now = Date.now();
|
|
56
|
+
if (existing) {
|
|
57
|
+
existing.lastUsedAt = now;
|
|
58
|
+
existing.requestCount++;
|
|
59
|
+
// Update model if different (e.g., fallback)
|
|
60
|
+
if (existing.model !== model) {
|
|
61
|
+
existing.model = model;
|
|
62
|
+
existing.tier = tier;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
this.sessions.set(sessionId, {
|
|
67
|
+
model,
|
|
68
|
+
tier,
|
|
69
|
+
createdAt: now,
|
|
70
|
+
lastUsedAt: now,
|
|
71
|
+
requestCount: 1,
|
|
72
|
+
recentHashes: [],
|
|
73
|
+
strikes: 0,
|
|
74
|
+
escalated: false,
|
|
75
|
+
sessionCostMicros: 0n,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Touch a session to extend its timeout.
|
|
81
|
+
*/
|
|
82
|
+
touchSession(sessionId) {
|
|
83
|
+
if (!this.config.enabled || !sessionId) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const entry = this.sessions.get(sessionId);
|
|
87
|
+
if (entry) {
|
|
88
|
+
entry.lastUsedAt = Date.now();
|
|
89
|
+
entry.requestCount++;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Clear a specific session.
|
|
94
|
+
*/
|
|
95
|
+
clearSession(sessionId) {
|
|
96
|
+
this.sessions.delete(sessionId);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Clear all sessions.
|
|
100
|
+
*/
|
|
101
|
+
clearAll() {
|
|
102
|
+
this.sessions.clear();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get session stats for debugging.
|
|
106
|
+
*/
|
|
107
|
+
getStats() {
|
|
108
|
+
const now = Date.now();
|
|
109
|
+
const sessions = Array.from(this.sessions.entries()).map(([id, entry]) => ({
|
|
110
|
+
id: id.slice(0, 8) + "...",
|
|
111
|
+
model: entry.model,
|
|
112
|
+
age: Math.round((now - entry.createdAt) / 1000),
|
|
113
|
+
}));
|
|
114
|
+
return { count: this.sessions.size, sessions };
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Clean up expired sessions.
|
|
118
|
+
*/
|
|
119
|
+
cleanup() {
|
|
120
|
+
const now = Date.now();
|
|
121
|
+
for (const [id, entry] of this.sessions) {
|
|
122
|
+
if (now - entry.lastUsedAt > this.config.timeoutMs) {
|
|
123
|
+
this.sessions.delete(id);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Record a request content hash and detect repetitive patterns.
|
|
129
|
+
* Returns true if escalation should be triggered (3+ consecutive similar requests).
|
|
130
|
+
*/
|
|
131
|
+
recordRequestHash(sessionId, hash) {
|
|
132
|
+
const entry = this.sessions.get(sessionId);
|
|
133
|
+
if (!entry)
|
|
134
|
+
return false;
|
|
135
|
+
const prev = entry.recentHashes;
|
|
136
|
+
if (prev.length > 0 && prev[prev.length - 1] === hash) {
|
|
137
|
+
entry.strikes++;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
entry.strikes = 0;
|
|
141
|
+
}
|
|
142
|
+
entry.recentHashes.push(hash);
|
|
143
|
+
if (entry.recentHashes.length > 3) {
|
|
144
|
+
entry.recentHashes.shift();
|
|
145
|
+
}
|
|
146
|
+
return entry.strikes >= 2 && !entry.escalated;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Escalate session to next tier. Returns the new model/tier or null if already at max.
|
|
150
|
+
*/
|
|
151
|
+
escalateSession(sessionId, tierConfigs) {
|
|
152
|
+
const entry = this.sessions.get(sessionId);
|
|
153
|
+
if (!entry)
|
|
154
|
+
return null;
|
|
155
|
+
const TIER_ORDER = ["SIMPLE", "MEDIUM", "COMPLEX", "REASONING"];
|
|
156
|
+
const currentIdx = TIER_ORDER.indexOf(entry.tier);
|
|
157
|
+
if (currentIdx < 0 || currentIdx >= TIER_ORDER.length - 1)
|
|
158
|
+
return null;
|
|
159
|
+
const nextTier = TIER_ORDER[currentIdx + 1];
|
|
160
|
+
const nextConfig = tierConfigs[nextTier];
|
|
161
|
+
if (!nextConfig)
|
|
162
|
+
return null;
|
|
163
|
+
entry.model = nextConfig.primary;
|
|
164
|
+
entry.tier = nextTier;
|
|
165
|
+
entry.strikes = 0;
|
|
166
|
+
entry.escalated = true;
|
|
167
|
+
return { model: nextConfig.primary, tier: nextTier };
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Add cost to a session's running total for maxCostPerRun tracking.
|
|
171
|
+
* Cost is in USDC 6-decimal units (micros).
|
|
172
|
+
* Creates a cost-tracking-only entry if none exists (e.g., explicit model requests
|
|
173
|
+
* that never go through the routing path).
|
|
174
|
+
*/
|
|
175
|
+
addSessionCost(sessionId, additionalMicros) {
|
|
176
|
+
let entry = this.sessions.get(sessionId);
|
|
177
|
+
if (!entry) {
|
|
178
|
+
const now = Date.now();
|
|
179
|
+
entry = {
|
|
180
|
+
model: "",
|
|
181
|
+
tier: "DIRECT",
|
|
182
|
+
createdAt: now,
|
|
183
|
+
lastUsedAt: now,
|
|
184
|
+
requestCount: 0,
|
|
185
|
+
recentHashes: [],
|
|
186
|
+
strikes: 0,
|
|
187
|
+
escalated: false,
|
|
188
|
+
sessionCostMicros: 0n,
|
|
189
|
+
};
|
|
190
|
+
this.sessions.set(sessionId, entry);
|
|
191
|
+
}
|
|
192
|
+
entry.sessionCostMicros += additionalMicros;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Get the total accumulated cost for a session in USD.
|
|
196
|
+
*/
|
|
197
|
+
getSessionCostUsd(sessionId) {
|
|
198
|
+
const entry = this.sessions.get(sessionId);
|
|
199
|
+
if (!entry)
|
|
200
|
+
return 0;
|
|
201
|
+
return Number(entry.sessionCostMicros) / 1_000_000;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Stop the cleanup interval.
|
|
205
|
+
*/
|
|
206
|
+
close() {
|
|
207
|
+
if (this.cleanupInterval) {
|
|
208
|
+
clearInterval(this.cleanupInterval);
|
|
209
|
+
this.cleanupInterval = null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Generate a session ID from request headers or create a default.
|
|
215
|
+
*/
|
|
216
|
+
export function getSessionId(headers, headerName = DEFAULT_SESSION_CONFIG.headerName) {
|
|
217
|
+
const value = headers[headerName] || headers[headerName.toLowerCase()];
|
|
218
|
+
if (typeof value === "string" && value.length > 0) {
|
|
219
|
+
return value;
|
|
220
|
+
}
|
|
221
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
222
|
+
return value[0];
|
|
223
|
+
}
|
|
224
|
+
return undefined;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Derive a stable session ID from message content when no explicit session
|
|
228
|
+
* header is provided. Uses the first user message as the conversation anchor —
|
|
229
|
+
* same opening message = same session ID across all subsequent turns.
|
|
230
|
+
*
|
|
231
|
+
* This prevents model-switching mid-conversation even when OpenClaw doesn't
|
|
232
|
+
* send an x-session-id header (which is the default OpenClaw behaviour).
|
|
233
|
+
*/
|
|
234
|
+
export function deriveSessionId(messages) {
|
|
235
|
+
const firstUser = messages.find((m) => m.role === "user");
|
|
236
|
+
if (!firstUser)
|
|
237
|
+
return undefined;
|
|
238
|
+
const content = typeof firstUser.content === "string" ? firstUser.content : JSON.stringify(firstUser.content);
|
|
239
|
+
// 8-char hex prefix of SHA-256 — short enough for logs, collision-resistant
|
|
240
|
+
// enough for session tracking within a single gateway instance.
|
|
241
|
+
return createHash("sha256").update(content).digest("hex").slice(0, 8);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Generate a short hash fingerprint from request content.
|
|
245
|
+
* Captures: last user message text + tool call names (if any).
|
|
246
|
+
* Normalizes whitespace to avoid false negatives from minor formatting diffs.
|
|
247
|
+
*/
|
|
248
|
+
export function hashRequestContent(lastUserContent, toolCallNames) {
|
|
249
|
+
const normalized = lastUserContent.replace(/\s+/g, " ").trim().slice(0, 500);
|
|
250
|
+
const toolSuffix = toolCallNames?.length ? `|tools:${toolCallNames.sort().join(",")}` : "";
|
|
251
|
+
return createHash("sha256")
|
|
252
|
+
.update(normalized + toolSuffix)
|
|
253
|
+
.digest("hex")
|
|
254
|
+
.slice(0, 12);
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.test.d.ts","sourceRoot":"","sources":["../src/session.test.ts"],"names":[],"mappings":""}
|