maestro-core 0.2.0 → 0.2.2
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/cost.d.ts +60 -0
- package/dist/cost.d.ts.map +1 -0
- package/dist/cost.js +68 -0
- package/dist/cost.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +69 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +113 -0
- package/dist/models.js.map +1 -0
- package/dist/ports/quota-store.d.ts +2 -0
- package/dist/ports/quota-store.d.ts.map +1 -1
- package/dist/runtime/empty-recovery.d.ts +62 -0
- package/dist/runtime/empty-recovery.d.ts.map +1 -0
- package/dist/runtime/empty-recovery.js +34 -0
- package/dist/runtime/empty-recovery.js.map +1 -0
- package/dist/runtime/index.d.ts +6 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +6 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/memory.d.ts +32 -0
- package/dist/runtime/memory.d.ts.map +1 -0
- package/dist/runtime/memory.js +15 -0
- package/dist/runtime/memory.js.map +1 -0
- package/dist/runtime/providers.d.ts +53 -0
- package/dist/runtime/providers.d.ts.map +1 -0
- package/dist/runtime/providers.js +124 -0
- package/dist/runtime/providers.js.map +1 -0
- package/dist/runtime/quota.d.ts +66 -0
- package/dist/runtime/quota.d.ts.map +1 -0
- package/dist/runtime/quota.js +102 -0
- package/dist/runtime/quota.js.map +1 -0
- package/dist/runtime/run-chat-turn.d.ts +136 -0
- package/dist/runtime/run-chat-turn.d.ts.map +1 -0
- package/dist/runtime/run-chat-turn.js +329 -0
- package/dist/runtime/run-chat-turn.js.map +1 -0
- package/dist/windows.d.ts +49 -0
- package/dist/windows.d.ts.map +1 -0
- package/dist/windows.js +63 -0
- package/dist/windows.js.map +1 -0
- package/package.json +1 -1
package/dist/cost.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM pricing table + cost estimator.
|
|
3
|
+
*
|
|
4
|
+
* Per-million-token USD rates. Numbers track the Anthropic and OpenAI
|
|
5
|
+
* public pricing pages; update when the providers publish a new
|
|
6
|
+
* default alias.
|
|
7
|
+
*
|
|
8
|
+
* Hosts that need custom rates (private deployments, enterprise
|
|
9
|
+
* negotiated pricing, additional providers) pass an override map
|
|
10
|
+
* through the second argument of `estimateCost` — it merges over the
|
|
11
|
+
* built-in table without mutating it.
|
|
12
|
+
*
|
|
13
|
+
* IMPORTANT: model ids from OpenAI may include date suffixes at
|
|
14
|
+
* runtime (e.g. `gpt-4o-mini-2024-07-18`). `estimateCost` falls
|
|
15
|
+
* through to the blended rate for unknown ids — intentional, so an
|
|
16
|
+
* unrecognised model never crashes the cost call. Add the suffixed id
|
|
17
|
+
* to the table when the provider publishes one.
|
|
18
|
+
*/
|
|
19
|
+
export interface PricingRow {
|
|
20
|
+
/** Per-million input tokens, USD. */
|
|
21
|
+
input: number;
|
|
22
|
+
/** Per-million output tokens, USD. */
|
|
23
|
+
output: number;
|
|
24
|
+
/** Per-million cache-read tokens, USD. Anthropic: ~10% of input. OpenAI: 50%. */
|
|
25
|
+
cacheRead: number;
|
|
26
|
+
/** Per-million cache-write tokens, USD. Anthropic: ~1.25× input. OpenAI: no extra. */
|
|
27
|
+
cacheWrite: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Default model pricing snapshot. Sourced from:
|
|
31
|
+
* - Anthropic: https://www.anthropic.com/pricing (2026 baseline)
|
|
32
|
+
* - OpenAI: https://openai.com/api/pricing
|
|
33
|
+
*/
|
|
34
|
+
export declare const MODEL_PRICING: Record<string, PricingRow>;
|
|
35
|
+
/**
|
|
36
|
+
* Blended fallback used when the model id is unknown (date-suffixed
|
|
37
|
+
* OpenAI variants, custom deployments, missing telemetry). Skews
|
|
38
|
+
* Haiku-heavy because the default router lands on fast, but biases up
|
|
39
|
+
* slightly so dashboards never under-report cost.
|
|
40
|
+
*
|
|
41
|
+
* Hosts that surface this on a UI should label it as approximate.
|
|
42
|
+
*/
|
|
43
|
+
export declare const BLENDED_PRICING: PricingRow;
|
|
44
|
+
export interface TokenUsage {
|
|
45
|
+
input: number;
|
|
46
|
+
output: number;
|
|
47
|
+
cacheRead: number;
|
|
48
|
+
cacheWrite: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Estimate USD cost for a token-usage block. When `modelId` matches
|
|
52
|
+
* a known model in `MODEL_PRICING` (or in the optional `customPricing`
|
|
53
|
+
* override map) the exact rate applies; otherwise `BLENDED_PRICING`
|
|
54
|
+
* is used.
|
|
55
|
+
*
|
|
56
|
+
* `customPricing` is shallow-merged on top of the default table — host
|
|
57
|
+
* entries override built-ins when the ids collide.
|
|
58
|
+
*/
|
|
59
|
+
export declare function estimateCost(usage: TokenUsage, modelId?: string | null, customPricing?: Record<string, PricingRow>): number;
|
|
60
|
+
//# sourceMappingURL=cost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,UAAU;IACvB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAA;IACjB,sFAAsF;IACtF,UAAU,EAAE,MAAM,CAAA;CACrB;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CA4BpD,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,UAK7B,CAAA;AAED,MAAM,WAAW,UAAU;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CACxB,KAAK,EAAE,UAAU,EACjB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,EACvB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAC3C,MAAM,CAYR"}
|
package/dist/cost.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default model pricing snapshot. Sourced from:
|
|
3
|
+
* - Anthropic: https://www.anthropic.com/pricing (2026 baseline)
|
|
4
|
+
* - OpenAI: https://openai.com/api/pricing
|
|
5
|
+
*/
|
|
6
|
+
export const MODEL_PRICING = {
|
|
7
|
+
// ── Anthropic ─────────────────────────────────────────────────
|
|
8
|
+
'claude-haiku-4-5-20251001': {
|
|
9
|
+
input: 1.0,
|
|
10
|
+
output: 5.0,
|
|
11
|
+
cacheRead: 0.1,
|
|
12
|
+
cacheWrite: 1.25,
|
|
13
|
+
},
|
|
14
|
+
'claude-sonnet-4-6': {
|
|
15
|
+
input: 3.0,
|
|
16
|
+
output: 15.0,
|
|
17
|
+
cacheRead: 0.3,
|
|
18
|
+
cacheWrite: 3.75,
|
|
19
|
+
},
|
|
20
|
+
// ── OpenAI (fallback provider) ────────────────────────────────
|
|
21
|
+
'gpt-4o-mini': {
|
|
22
|
+
input: 0.15,
|
|
23
|
+
output: 0.6,
|
|
24
|
+
cacheRead: 0.075, // 50% of input rate
|
|
25
|
+
cacheWrite: 0.15, // no extra charge; matches input
|
|
26
|
+
},
|
|
27
|
+
'gpt-4o': {
|
|
28
|
+
input: 2.5,
|
|
29
|
+
output: 10.0,
|
|
30
|
+
cacheRead: 1.25, // 50% of input
|
|
31
|
+
cacheWrite: 2.5, // matches input
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Blended fallback used when the model id is unknown (date-suffixed
|
|
36
|
+
* OpenAI variants, custom deployments, missing telemetry). Skews
|
|
37
|
+
* Haiku-heavy because the default router lands on fast, but biases up
|
|
38
|
+
* slightly so dashboards never under-report cost.
|
|
39
|
+
*
|
|
40
|
+
* Hosts that surface this on a UI should label it as approximate.
|
|
41
|
+
*/
|
|
42
|
+
export const BLENDED_PRICING = {
|
|
43
|
+
input: 1.5,
|
|
44
|
+
output: 7.5,
|
|
45
|
+
cacheRead: 0.15,
|
|
46
|
+
cacheWrite: 1.875,
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Estimate USD cost for a token-usage block. When `modelId` matches
|
|
50
|
+
* a known model in `MODEL_PRICING` (or in the optional `customPricing`
|
|
51
|
+
* override map) the exact rate applies; otherwise `BLENDED_PRICING`
|
|
52
|
+
* is used.
|
|
53
|
+
*
|
|
54
|
+
* `customPricing` is shallow-merged on top of the default table — host
|
|
55
|
+
* entries override built-ins when the ids collide.
|
|
56
|
+
*/
|
|
57
|
+
export function estimateCost(usage, modelId, customPricing) {
|
|
58
|
+
const merged = customPricing
|
|
59
|
+
? { ...MODEL_PRICING, ...customPricing }
|
|
60
|
+
: MODEL_PRICING;
|
|
61
|
+
const price = (modelId && merged[modelId]) || BLENDED_PRICING;
|
|
62
|
+
return ((usage.input * price.input +
|
|
63
|
+
usage.output * price.output +
|
|
64
|
+
usage.cacheRead * price.cacheRead +
|
|
65
|
+
usage.cacheWrite * price.cacheWrite) /
|
|
66
|
+
1_000_000);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=cost.js.map
|
package/dist/cost.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost.js","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AA6BA;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAA+B;IACrD,iEAAiE;IACjE,2BAA2B,EAAE;QACzB,KAAK,EAAE,GAAG;QACV,MAAM,EAAE,GAAG;QACX,SAAS,EAAE,GAAG;QACd,UAAU,EAAE,IAAI;KACnB;IACD,mBAAmB,EAAE;QACjB,KAAK,EAAE,GAAG;QACV,MAAM,EAAE,IAAI;QACZ,SAAS,EAAE,GAAG;QACd,UAAU,EAAE,IAAI;KACnB;IAED,iEAAiE;IACjE,aAAa,EAAE;QACX,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,GAAG;QACX,SAAS,EAAE,KAAK,EAAE,oBAAoB;QACtC,UAAU,EAAE,IAAI,EAAE,iCAAiC;KACtD;IACD,QAAQ,EAAE;QACN,KAAK,EAAE,GAAG;QACV,MAAM,EAAE,IAAI;QACZ,SAAS,EAAE,IAAI,EAAE,eAAe;QAChC,UAAU,EAAE,GAAG,EAAE,gBAAgB;KACpC;CACJ,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,eAAe,GAAe;IACvC,KAAK,EAAE,GAAG;IACV,MAAM,EAAE,GAAG;IACX,SAAS,EAAE,IAAI;IACf,UAAU,EAAE,KAAK;CACpB,CAAA;AASD;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CACxB,KAAiB,EACjB,OAAuB,EACvB,aAA0C;IAE1C,MAAM,MAAM,GAAG,aAAa;QACxB,CAAC,CAAC,EAAE,GAAG,aAAa,EAAE,GAAG,aAAa,EAAE;QACxC,CAAC,CAAC,aAAa,CAAA;IACnB,MAAM,KAAK,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,eAAe,CAAA;IAC7D,OAAO,CACH,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK;QACtB,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM;QAC3B,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS;QACjC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;QACxC,SAAS,CACZ,CAAA;AACL,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,9 @@ export type { BaseToolContext } from './context.js';
|
|
|
2
2
|
export { err, isOk, ok, type ToolEnvelope, type ToolMeta } from './envelope.js';
|
|
3
3
|
export { type AgentToolDefinition, type AnyAgentToolDefinition, defineAgentTool, type ToolCostBand, type ToolKind, } from './tool.js';
|
|
4
4
|
export { applyCacheBreakpoints, type CacheableBlock, type CachedMessages, } from './cache-control.js';
|
|
5
|
+
export { BLENDED_PRICING, estimateCost, MODEL_PRICING, type PricingRow, type TokenUsage, } from './cost.js';
|
|
6
|
+
export { DEFAULT_SMART_KEYWORDS, DEFAULT_SMART_LENGTH_THRESHOLD, DEFAULT_SMART_TURN_THRESHOLD, type ModelSelection, type ModelTier, selectChatModel, type SelectModelArgs, } from './models.js';
|
|
5
7
|
export { captureToolException, type ToolExceptionHandler, type ToolExceptionTags, } from './safe-tool.js';
|
|
6
8
|
export * from './ports/index.js';
|
|
9
|
+
export { DAY_SECONDS, DAY_TTL_SECONDS, dailyCostWindow, dailyTokensWindow, dayKeyUtc, HOUR_SECONDS, HOUR_TTL_SECONDS, hourKeyUtc, hourlyToolCallsWindow, nextUtcHour, nextUtcMidnight, type WindowDescriptor, } from './windows.js';
|
|
7
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC/E,OAAO,EACH,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,eAAe,EACf,KAAK,YAAY,EACjB,KAAK,QAAQ,GAChB,MAAM,WAAW,CAAA;AAGlB,OAAO,EACH,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,cAAc,GACtB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACH,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACzB,MAAM,gBAAgB,CAAA;AAGvB,cAAc,kBAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC/E,OAAO,EACH,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,eAAe,EACf,KAAK,YAAY,EACjB,KAAK,QAAQ,GAChB,MAAM,WAAW,CAAA;AAGlB,OAAO,EACH,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,cAAc,GACtB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACH,eAAe,EACf,YAAY,EACZ,aAAa,EACb,KAAK,UAAU,EACf,KAAK,UAAU,GAClB,MAAM,WAAW,CAAA;AAClB,OAAO,EACH,sBAAsB,EACtB,8BAA8B,EAC9B,4BAA4B,EAC5B,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,eAAe,EACf,KAAK,eAAe,GACvB,MAAM,aAAa,CAAA;AACpB,OAAO,EACH,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACzB,MAAM,gBAAgB,CAAA;AAGvB,cAAc,kBAAkB,CAAA;AAKhC,OAAO,EACH,WAAW,EACX,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,qBAAqB,EACrB,WAAW,EACX,eAAe,EACf,KAAK,gBAAgB,GACxB,MAAM,cAAc,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,13 @@ export { err, isOk, ok } from './envelope.js';
|
|
|
2
2
|
export { defineAgentTool, } from './tool.js';
|
|
3
3
|
// Cross-cutting kernel utilities
|
|
4
4
|
export { applyCacheBreakpoints, } from './cache-control.js';
|
|
5
|
+
export { BLENDED_PRICING, estimateCost, MODEL_PRICING, } from './cost.js';
|
|
6
|
+
export { DEFAULT_SMART_KEYWORDS, DEFAULT_SMART_LENGTH_THRESHOLD, DEFAULT_SMART_TURN_THRESHOLD, selectChatModel, } from './models.js';
|
|
5
7
|
export { captureToolException, } from './safe-tool.js';
|
|
6
8
|
// Ports re-exported at root for ergonomic single-import setups
|
|
7
9
|
export * from './ports/index.js';
|
|
10
|
+
// Window-math helpers — host `QuotaStore` impls import these to
|
|
11
|
+
// compute consistent counter keys / TTLs / reset times. Not used
|
|
12
|
+
// directly by `runChatTurn`; exposed for the host port boundary.
|
|
13
|
+
export { DAY_SECONDS, DAY_TTL_SECONDS, dailyCostWindow, dailyTokensWindow, dayKeyUtc, HOUR_SECONDS, HOUR_TTL_SECONDS, hourKeyUtc, hourlyToolCallsWindow, nextUtcHour, nextUtcMidnight, } from './windows.js';
|
|
8
14
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAoC,MAAM,eAAe,CAAA;AAC/E,OAAO,EAGH,eAAe,GAGlB,MAAM,WAAW,CAAA;AAElB,iCAAiC;AACjC,OAAO,EACH,qBAAqB,GAGxB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACH,oBAAoB,GAGvB,MAAM,gBAAgB,CAAA;AAEvB,+DAA+D;AAC/D,cAAc,kBAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAoC,MAAM,eAAe,CAAA;AAC/E,OAAO,EAGH,eAAe,GAGlB,MAAM,WAAW,CAAA;AAElB,iCAAiC;AACjC,OAAO,EACH,qBAAqB,GAGxB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACH,eAAe,EACf,YAAY,EACZ,aAAa,GAGhB,MAAM,WAAW,CAAA;AAClB,OAAO,EACH,sBAAsB,EACtB,8BAA8B,EAC9B,4BAA4B,EAG5B,eAAe,GAElB,MAAM,aAAa,CAAA;AACpB,OAAO,EACH,oBAAoB,GAGvB,MAAM,gBAAgB,CAAA;AAEvB,+DAA+D;AAC/D,cAAc,kBAAkB,CAAA;AAEhC,gEAAgE;AAChE,iEAAiE;AACjE,iEAAiE;AACjE,OAAO,EACH,WAAW,EACX,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,qBAAqB,EACrB,WAAW,EACX,eAAe,GAElB,MAAM,cAAc,CAAA"}
|
package/dist/models.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two-tier model router for chat surfaces. Picks between a fast/cheap
|
|
3
|
+
* model and a smart/expensive one based on cheap heuristics on the
|
|
4
|
+
* user's last message.
|
|
5
|
+
*
|
|
6
|
+
* The kernel ships sensible defaults tuned for an owner-help persona
|
|
7
|
+
* (lookups → fast; mutations/long asks → smart). Hosts override the
|
|
8
|
+
* model ids by passing `models` and can extend or replace the keyword
|
|
9
|
+
* triggers via the optional `smartKeywords` / threshold args.
|
|
10
|
+
*
|
|
11
|
+
* The kernel does NOT read `process.env` — host products are responsible
|
|
12
|
+
* for pulling `MODEL_ID` overrides from their own env layer and passing
|
|
13
|
+
* them in. Keeps the kernel testable in isolation and avoids the
|
|
14
|
+
* surprise of NEXT_PUBLIC-style build-time inlining.
|
|
15
|
+
*/
|
|
16
|
+
export type ModelTier = 'fast' | 'smart';
|
|
17
|
+
export interface ModelSelection {
|
|
18
|
+
tier: ModelTier;
|
|
19
|
+
modelId: string;
|
|
20
|
+
/** Short string describing why this tier was chosen. Useful for telemetry. */
|
|
21
|
+
reason: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Default trigger words mapped to mutation verbs or compositional asks
|
|
25
|
+
* that justify routing to the smart tier. Tuned for Portuguese /
|
|
26
|
+
* Spanish / English owner-help personas. Replace via `smartKeywords`
|
|
27
|
+
* when the persona shifts.
|
|
28
|
+
*/
|
|
29
|
+
export declare const DEFAULT_SMART_KEYWORDS: readonly string[];
|
|
30
|
+
/** Default message-length threshold (chars) above which we route smart. */
|
|
31
|
+
export declare const DEFAULT_SMART_LENGTH_THRESHOLD = 200;
|
|
32
|
+
/** Default user-turn count above which we route smart (deeper chains benefit from reasoning). */
|
|
33
|
+
export declare const DEFAULT_SMART_TURN_THRESHOLD = 4;
|
|
34
|
+
export interface SelectModelArgs {
|
|
35
|
+
/** Most recent user message. */
|
|
36
|
+
userMessage: string;
|
|
37
|
+
/** 1-based user-turn count for the thread. */
|
|
38
|
+
turnIndex?: number;
|
|
39
|
+
/** Caller may force the tier (e.g. a known-complex nudge). */
|
|
40
|
+
forceTier?: ModelTier;
|
|
41
|
+
/**
|
|
42
|
+
* Model ids per tier. The kernel does not read env; the host
|
|
43
|
+
* resolves overrides from its env layer and passes them here.
|
|
44
|
+
*
|
|
45
|
+
* `force` short-circuits to that exact model id regardless of
|
|
46
|
+
* tier — useful for canary rollouts and eval pinning.
|
|
47
|
+
*/
|
|
48
|
+
models: {
|
|
49
|
+
fast: string;
|
|
50
|
+
smart: string;
|
|
51
|
+
force?: string | null;
|
|
52
|
+
};
|
|
53
|
+
/** Override the default keyword trigger set. Pass `[]` to disable keyword routing entirely. */
|
|
54
|
+
smartKeywords?: readonly string[];
|
|
55
|
+
/** Override the default length threshold (chars). */
|
|
56
|
+
smartLengthThreshold?: number;
|
|
57
|
+
/** Override the default turn-depth threshold. */
|
|
58
|
+
smartTurnThreshold?: number;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Heuristic router. Smart tier wins when any of:
|
|
62
|
+
* - `forceTier === 'smart'` (caller intent)
|
|
63
|
+
* - message length ≥ length threshold
|
|
64
|
+
* - turn index ≥ turn threshold
|
|
65
|
+
* - message contains a keyword trigger
|
|
66
|
+
* Otherwise fast. `models.force` always wins when set.
|
|
67
|
+
*/
|
|
68
|
+
export declare function selectChatModel(args: SelectModelArgs): ModelSelection;
|
|
69
|
+
//# sourceMappingURL=models.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,CAAA;AAExC,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,SAAS,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAA;CACjB;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EA0CnD,CAAA;AAED,2EAA2E;AAC3E,eAAO,MAAM,8BAA8B,MAAM,CAAA;AAEjD,iGAAiG;AACjG,eAAO,MAAM,4BAA4B,IAAI,CAAA;AAE7C,MAAM,WAAW,eAAe;IAC5B,gCAAgC;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,SAAS,CAAA;IAErB;;;;;;OAMG;IACH,MAAM,EAAE;QACJ,IAAI,EAAE,MAAM,CAAA;QACZ,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KACxB,CAAA;IAED,+FAA+F;IAC/F,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,qDAAqD;IACrD,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,iDAAiD;IACjD,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,cAAc,CAwCrE"}
|
package/dist/models.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two-tier model router for chat surfaces. Picks between a fast/cheap
|
|
3
|
+
* model and a smart/expensive one based on cheap heuristics on the
|
|
4
|
+
* user's last message.
|
|
5
|
+
*
|
|
6
|
+
* The kernel ships sensible defaults tuned for an owner-help persona
|
|
7
|
+
* (lookups → fast; mutations/long asks → smart). Hosts override the
|
|
8
|
+
* model ids by passing `models` and can extend or replace the keyword
|
|
9
|
+
* triggers via the optional `smartKeywords` / threshold args.
|
|
10
|
+
*
|
|
11
|
+
* The kernel does NOT read `process.env` — host products are responsible
|
|
12
|
+
* for pulling `MODEL_ID` overrides from their own env layer and passing
|
|
13
|
+
* them in. Keeps the kernel testable in isolation and avoids the
|
|
14
|
+
* surprise of NEXT_PUBLIC-style build-time inlining.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Default trigger words mapped to mutation verbs or compositional asks
|
|
18
|
+
* that justify routing to the smart tier. Tuned for Portuguese /
|
|
19
|
+
* Spanish / English owner-help personas. Replace via `smartKeywords`
|
|
20
|
+
* when the persona shifts.
|
|
21
|
+
*/
|
|
22
|
+
export const DEFAULT_SMART_KEYWORDS = [
|
|
23
|
+
// PT
|
|
24
|
+
'agendar',
|
|
25
|
+
'agenda pra',
|
|
26
|
+
'marcar',
|
|
27
|
+
'cancelar',
|
|
28
|
+
'remarcar',
|
|
29
|
+
'registrar venda',
|
|
30
|
+
'registra venda',
|
|
31
|
+
'vendi',
|
|
32
|
+
'criar promoç',
|
|
33
|
+
'criar cupom',
|
|
34
|
+
'cadastrar cliente',
|
|
35
|
+
'mesclar',
|
|
36
|
+
'excluir',
|
|
37
|
+
'apagar',
|
|
38
|
+
'comparar',
|
|
39
|
+
'compare',
|
|
40
|
+
'resumo geral',
|
|
41
|
+
'me dá um resumo',
|
|
42
|
+
'agendamento em série',
|
|
43
|
+
'série de agendamentos',
|
|
44
|
+
// ES
|
|
45
|
+
'reservar',
|
|
46
|
+
'reagendar',
|
|
47
|
+
'registrar venta',
|
|
48
|
+
'crear promo',
|
|
49
|
+
'crear cupon',
|
|
50
|
+
'eliminar',
|
|
51
|
+
'resumen general',
|
|
52
|
+
// EN
|
|
53
|
+
'book ',
|
|
54
|
+
'schedule ',
|
|
55
|
+
'cancel',
|
|
56
|
+
'reschedule',
|
|
57
|
+
'log a sale',
|
|
58
|
+
'record sale',
|
|
59
|
+
'create coupon',
|
|
60
|
+
'create promotion',
|
|
61
|
+
'merge clients',
|
|
62
|
+
'delete',
|
|
63
|
+
'summary',
|
|
64
|
+
];
|
|
65
|
+
/** Default message-length threshold (chars) above which we route smart. */
|
|
66
|
+
export const DEFAULT_SMART_LENGTH_THRESHOLD = 200;
|
|
67
|
+
/** Default user-turn count above which we route smart (deeper chains benefit from reasoning). */
|
|
68
|
+
export const DEFAULT_SMART_TURN_THRESHOLD = 4;
|
|
69
|
+
/**
|
|
70
|
+
* Heuristic router. Smart tier wins when any of:
|
|
71
|
+
* - `forceTier === 'smart'` (caller intent)
|
|
72
|
+
* - message length ≥ length threshold
|
|
73
|
+
* - turn index ≥ turn threshold
|
|
74
|
+
* - message contains a keyword trigger
|
|
75
|
+
* Otherwise fast. `models.force` always wins when set.
|
|
76
|
+
*/
|
|
77
|
+
export function selectChatModel(args) {
|
|
78
|
+
const forceId = args.models.force ?? null;
|
|
79
|
+
if (forceId) {
|
|
80
|
+
return { tier: 'fast', modelId: forceId, reason: 'force-override' };
|
|
81
|
+
}
|
|
82
|
+
if (args.forceTier === 'smart') {
|
|
83
|
+
return { tier: 'smart', modelId: args.models.smart, reason: 'forced' };
|
|
84
|
+
}
|
|
85
|
+
if (args.forceTier === 'fast') {
|
|
86
|
+
return { tier: 'fast', modelId: args.models.fast, reason: 'forced' };
|
|
87
|
+
}
|
|
88
|
+
const text = (args.userMessage ?? '').trim().toLowerCase();
|
|
89
|
+
if (text.length === 0) {
|
|
90
|
+
return { tier: 'fast', modelId: args.models.fast, reason: 'empty' };
|
|
91
|
+
}
|
|
92
|
+
const lengthThreshold = args.smartLengthThreshold ?? DEFAULT_SMART_LENGTH_THRESHOLD;
|
|
93
|
+
if (text.length >= lengthThreshold) {
|
|
94
|
+
return { tier: 'smart', modelId: args.models.smart, reason: 'long-message' };
|
|
95
|
+
}
|
|
96
|
+
const turn = args.turnIndex ?? 1;
|
|
97
|
+
const turnThreshold = args.smartTurnThreshold ?? DEFAULT_SMART_TURN_THRESHOLD;
|
|
98
|
+
if (turn >= turnThreshold) {
|
|
99
|
+
return { tier: 'smart', modelId: args.models.smart, reason: 'deep-thread' };
|
|
100
|
+
}
|
|
101
|
+
const keywords = args.smartKeywords ?? DEFAULT_SMART_KEYWORDS;
|
|
102
|
+
for (const keyword of keywords) {
|
|
103
|
+
if (text.includes(keyword)) {
|
|
104
|
+
return {
|
|
105
|
+
tier: 'smart',
|
|
106
|
+
modelId: args.models.smart,
|
|
107
|
+
reason: `keyword:${keyword.trim()}`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { tier: 'fast', modelId: args.models.fast, reason: 'default-fast' };
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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"}
|
|
@@ -40,6 +40,8 @@ export interface QuotaUsage {
|
|
|
40
40
|
tokensOut: number;
|
|
41
41
|
cacheReadTokens: number;
|
|
42
42
|
cacheWriteTokens: number;
|
|
43
|
+
/** Tool invocations attributed to this turn. Drives the `maxCallsPerWindow` ceiling. */
|
|
44
|
+
toolCalls?: number;
|
|
43
45
|
/** USD cost in micro-dollars (integer). */
|
|
44
46
|
costUsdMicro: number;
|
|
45
47
|
modelId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quota-store.d.ts","sourceRoot":"","sources":["../../src/ports/quota-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,CAAA;AAE1D,MAAM,WAAW,QAAQ;IACrB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,EAAE;QACF,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;KACnB,CAAA;IACD,WAAW,EAAE,IAAI,CAAA;IACjB,SAAS,EAAE,IAAI,CAAA;CAClB;AAED,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,MAAM,CAAA;IACvB,gBAAgB,EAAE,MAAM,CAAA;IACxB,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,IAAI,CAAA;CACnB;AAED,MAAM,WAAW,UAAU;IACvB,gEAAgE;IAChE,WAAW,CAAC,KAAK,EAAE;QACf,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,EAAE,WAAW,CAAA;KACtB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAErB,mEAAmE;IACnE,KAAK,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;IAExE,sDAAsD;IACtD,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3C"}
|
|
1
|
+
{"version":3,"file":"quota-store.d.ts","sourceRoot":"","sources":["../../src/ports/quota-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,CAAA;AAE1D,MAAM,WAAW,QAAQ;IACrB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,EAAE;QACF,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;KACnB,CAAA;IACD,WAAW,EAAE,IAAI,CAAA;IACjB,SAAS,EAAE,IAAI,CAAA;CAClB;AAED,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,MAAM,CAAA;IACvB,gBAAgB,EAAE,MAAM,CAAA;IACxB,wFAAwF;IACxF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,IAAI,CAAA;CACnB;AAED,MAAM,WAAW,UAAU;IACvB,gEAAgE;IAChE,WAAW,CAAC,KAAK,EAAE;QACf,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,EAAE,WAAW,CAAA;KACtB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAErB,mEAAmE;IACnE,KAAK,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;IAExE,sDAAsD;IACtD,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3C"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Empty-text recovery decision helper.
|
|
3
|
+
*
|
|
4
|
+
* The recoverable bug class: the model called a tool, got valid data
|
|
5
|
+
* back, then emitted zero user-visible text. The visitor sees an empty
|
|
6
|
+
* bubble below the tool card and reads it as failure. Symptom seen in
|
|
7
|
+
* prod across multiple deployments — `event.text === '' && event.toolCalls.length > 0`
|
|
8
|
+
* after streamText finishes.
|
|
9
|
+
*
|
|
10
|
+
* The kernel offers this as a PURE decision helper. Callers detect the
|
|
11
|
+
* empty-text condition themselves (cheapest check: `text.trim().length === 0`
|
|
12
|
+
* after a turn that invoked tools), supply the locale-appropriate
|
|
13
|
+
* fallback string, and act on the decision struct (inject text into
|
|
14
|
+
* the stream + persist the recovery error code on the turn row).
|
|
15
|
+
*
|
|
16
|
+
* Why a helper instead of in-kernel recovery: the act of injecting
|
|
17
|
+
* text mid-stream is host-specific (Next.js Server Components,
|
|
18
|
+
* Cloudflare Worker, raw Node HTTP all differ). The decision is
|
|
19
|
+
* portable; the execution is not.
|
|
20
|
+
*/
|
|
21
|
+
export type EmptyRecoveryMode = 'off' | 'log_only' | 'enforce';
|
|
22
|
+
export interface EmptyRecoveryDecision {
|
|
23
|
+
/**
|
|
24
|
+
* Whether recovery engaged for this turn. `false` means the mode
|
|
25
|
+
* was `off`, the turn isn't a recoverable tool-loop-no-text case,
|
|
26
|
+
* or the turn produced visible text.
|
|
27
|
+
*/
|
|
28
|
+
triggered: boolean;
|
|
29
|
+
mode: EmptyRecoveryMode;
|
|
30
|
+
/**
|
|
31
|
+
* Pre-localized fallback string the caller should inject. Only
|
|
32
|
+
* populated when `triggered === true && mode === 'enforce'`. `null`
|
|
33
|
+
* in `log_only` mode (caller logs but does NOT modify the stream
|
|
34
|
+
* or row).
|
|
35
|
+
*/
|
|
36
|
+
fallbackText: string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Suggested error code to persist on the turn row:
|
|
39
|
+
* - `null` — recovery did not engage.
|
|
40
|
+
* - `'tool_loop_no_text_logged'` — log_only mode signal.
|
|
41
|
+
* - `'tool_loop_no_text_recovered_fallback'` — enforce signal.
|
|
42
|
+
*/
|
|
43
|
+
persistedErrorCode: string | null;
|
|
44
|
+
}
|
|
45
|
+
export interface DecideEmptyRecoveryArgs {
|
|
46
|
+
mode: EmptyRecoveryMode;
|
|
47
|
+
/**
|
|
48
|
+
* Caller-detected signal: `true` when the model invoked a tool but
|
|
49
|
+
* produced no visible text on the turn. Other empty-answer shapes
|
|
50
|
+
* (token-limit cap, empty response) are handled by separate layers.
|
|
51
|
+
*/
|
|
52
|
+
isToolLoopNoText: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Locale + surface-appropriate fallback. The kernel intentionally
|
|
55
|
+
* does NOT ship per-locale defaults — every host has its own
|
|
56
|
+
* translation namespace, and shipping a copy here would create two
|
|
57
|
+
* sources of truth.
|
|
58
|
+
*/
|
|
59
|
+
fallbackText: string;
|
|
60
|
+
}
|
|
61
|
+
export declare function decideEmptyRecovery(args: DecideEmptyRecoveryArgs): EmptyRecoveryDecision;
|
|
62
|
+
//# sourceMappingURL=empty-recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty-recovery.d.ts","sourceRoot":"","sources":["../../src/runtime/empty-recovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,UAAU,GAAG,SAAS,CAAA;AAE9D,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,SAAS,EAAE,OAAO,CAAA;IAClB,IAAI,EAAE,iBAAiB,CAAA;IACvB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B;;;;;OAKG;IACH,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC;AAED,MAAM,WAAW,uBAAuB;IACpC,IAAI,EAAE,iBAAiB,CAAA;IACvB;;;;OAIG;IACH,gBAAgB,EAAE,OAAO,CAAA;IACzB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAA;CACvB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,uBAAuB,GAAG,qBAAqB,CAgCxF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function decideEmptyRecovery(args) {
|
|
2
|
+
if (args.mode === 'off') {
|
|
3
|
+
return {
|
|
4
|
+
triggered: false,
|
|
5
|
+
mode: 'off',
|
|
6
|
+
fallbackText: null,
|
|
7
|
+
persistedErrorCode: null,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
if (!args.isToolLoopNoText) {
|
|
11
|
+
return {
|
|
12
|
+
triggered: false,
|
|
13
|
+
mode: args.mode,
|
|
14
|
+
fallbackText: null,
|
|
15
|
+
persistedErrorCode: null,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (args.mode === 'log_only') {
|
|
19
|
+
return {
|
|
20
|
+
triggered: true,
|
|
21
|
+
mode: 'log_only',
|
|
22
|
+
fallbackText: null,
|
|
23
|
+
persistedErrorCode: 'tool_loop_no_text_logged',
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// enforce
|
|
27
|
+
return {
|
|
28
|
+
triggered: true,
|
|
29
|
+
mode: 'enforce',
|
|
30
|
+
fallbackText: args.fallbackText,
|
|
31
|
+
persistedErrorCode: 'tool_loop_no_text_recovered_fallback',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=empty-recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty-recovery.js","sourceRoot":"","sources":["../../src/runtime/empty-recovery.ts"],"names":[],"mappings":"AA+DA,MAAM,UAAU,mBAAmB,CAAC,IAA6B;IAC7D,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACtB,OAAO;YACH,SAAS,EAAE,KAAK;YAChB,IAAI,EAAE,KAAK;YACX,YAAY,EAAE,IAAI;YAClB,kBAAkB,EAAE,IAAI;SAC3B,CAAA;IACL,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACzB,OAAO;YACH,SAAS,EAAE,KAAK;YAChB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,YAAY,EAAE,IAAI;YAClB,kBAAkB,EAAE,IAAI;SAC3B,CAAA;IACL,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC3B,OAAO;YACH,SAAS,EAAE,IAAI;YACf,IAAI,EAAE,UAAU;YAChB,YAAY,EAAE,IAAI;YAClB,kBAAkB,EAAE,0BAA0B;SACjD,CAAA;IACL,CAAC;IACD,UAAU;IACV,OAAO;QACH,SAAS,EAAE,IAAI;QACf,IAAI,EAAE,SAAS;QACf,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,kBAAkB,EAAE,sCAAsC;KAC7D,CAAA;AACL,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { decideEmptyRecovery, type DecideEmptyRecoveryArgs, type EmptyRecoveryDecision, type EmptyRecoveryMode, } from './empty-recovery.js';
|
|
2
|
+
export { formatMemoryBlock, loadMemoryBlock } from './memory.js';
|
|
3
|
+
export { mapModelIdToOpenAI, shouldFallback } from './providers.js';
|
|
4
|
+
export { AiQuotaDeniedError, type AiQuotaDenyPayload, type AiQuotaDenyReason, checkAndEnforce, enforceQuotaOrThrow, } from './quota.js';
|
|
5
|
+
export { runChatTurn, type RunChatTurnArgs, type RunChatTurnPorts, } from './run-chat-turn.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,mBAAmB,EACnB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,GACzB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACnE,OAAO,EACH,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,eAAe,EACf,mBAAmB,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EACH,WAAW,EACX,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACxB,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { decideEmptyRecovery, } from './empty-recovery.js';
|
|
2
|
+
export { formatMemoryBlock, loadMemoryBlock } from './memory.js';
|
|
3
|
+
export { mapModelIdToOpenAI, shouldFallback } from './providers.js';
|
|
4
|
+
export { AiQuotaDeniedError, checkAndEnforce, enforceQuotaOrThrow, } from './quota.js';
|
|
5
|
+
export { runChatTurn, } from './run-chat-turn.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,mBAAmB,GAItB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACnE,OAAO,EACH,kBAAkB,EAGlB,eAAe,EACf,mBAAmB,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EACH,WAAW,GAGd,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { MemoryRecord, MemoryScope, MemoryStore } from '../ports/memory-store.js';
|
|
2
|
+
/**
|
|
3
|
+
* Load + format memory facts for system-prompt injection.
|
|
4
|
+
*
|
|
5
|
+
* Pull semantics: the kernel asks the host's MemoryStore for ALL facts
|
|
6
|
+
* matching the scope, then formats them as a compact prose block. The
|
|
7
|
+
* host is responsible for any retrieval / semantic filtering — barbeiro's
|
|
8
|
+
* impl, for example, runs a relevance pass via embeddings before
|
|
9
|
+
* returning. The kernel does not do retrieval; it just consumes the
|
|
10
|
+
* already-selected list.
|
|
11
|
+
*
|
|
12
|
+
* Output goes in the DYNAMIC system segment (varies per principal,
|
|
13
|
+
* cannot be cached). Anthropic prompt cache would split per-user
|
|
14
|
+
* otherwise, killing cross-tenant cache reuse.
|
|
15
|
+
*
|
|
16
|
+
* Returns `''` (empty string) when there are no facts so callers can
|
|
17
|
+
* safely concatenate to existing dynamic content without conditional
|
|
18
|
+
* branching.
|
|
19
|
+
*/
|
|
20
|
+
export interface LoadMemoryBlockArgs {
|
|
21
|
+
memoryStore: MemoryStore;
|
|
22
|
+
scope: MemoryScope;
|
|
23
|
+
/** Optional header line. Defaults to a generic prefix. */
|
|
24
|
+
header?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function loadMemoryBlock(args: LoadMemoryBlockArgs): Promise<string>;
|
|
27
|
+
/**
|
|
28
|
+
* Pure formatter — separated from the port call so tests can drive
|
|
29
|
+
* arbitrary record sets without standing up a fake store.
|
|
30
|
+
*/
|
|
31
|
+
export declare function formatMemoryBlock(records: readonly MemoryRecord[], header?: string): string;
|
|
32
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/runtime/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAEtF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,mBAAmB;IAChC,WAAW,EAAE,WAAW,CAAA;IACxB,KAAK,EAAE,WAAW,CAAA;IAClB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAGhF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC7B,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,MAAM,SAAqD,GAC5D,MAAM,CAIR"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export async function loadMemoryBlock(args) {
|
|
2
|
+
const records = await args.memoryStore.load(args.scope);
|
|
3
|
+
return formatMemoryBlock(records, args.header);
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Pure formatter — separated from the port call so tests can drive
|
|
7
|
+
* arbitrary record sets without standing up a fake store.
|
|
8
|
+
*/
|
|
9
|
+
export function formatMemoryBlock(records, header = 'User context (memories you should keep in mind):') {
|
|
10
|
+
if (records.length === 0)
|
|
11
|
+
return '';
|
|
12
|
+
const lines = records.map((r) => `- ${r.fact}`);
|
|
13
|
+
return `${header}\n${lines.join('\n')}`;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/runtime/memory.ts"],"names":[],"mappings":"AA2BA,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAyB;IAC3D,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACvD,OAAO,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC7B,OAAgC,EAChC,MAAM,GAAG,kDAAkD;IAE3D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;IAC/C,OAAO,GAAG,MAAM,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;AAC3C,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-fallback helpers. Used by hosts that want OpenAI as a
|
|
3
|
+
* resilience fallback when the primary Anthropic call hits a transient
|
|
4
|
+
* failure mode.
|
|
5
|
+
*
|
|
6
|
+
* 0.2.0 ships the helpers but does NOT wrap `runChatTurn` with the
|
|
7
|
+
* retry loop — mid-stream provider switching is invasive enough to
|
|
8
|
+
* deserve its own design pass. Hosts compose retry themselves using
|
|
9
|
+
* these primitives:
|
|
10
|
+
*
|
|
11
|
+
* try {
|
|
12
|
+
* return await runChatTurn({ ..., models: anthropicModels })
|
|
13
|
+
* } catch (e) {
|
|
14
|
+
* if (shouldFallback(e)) {
|
|
15
|
+
* return runChatTurn({
|
|
16
|
+
* ...,
|
|
17
|
+
* models: {
|
|
18
|
+
* fast: mapModelIdToOpenAI(anthropicModels.fast),
|
|
19
|
+
* smart: mapModelIdToOpenAI(anthropicModels.smart),
|
|
20
|
+
* },
|
|
21
|
+
* })
|
|
22
|
+
* }
|
|
23
|
+
* throw e
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* Built-in retry wrapper tracked for 0.2.1.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Returns true when the error suggests a transient provider failure
|
|
30
|
+
* worth retrying against a different provider (rate limit, 5xx,
|
|
31
|
+
* network error, timeout). Returns false for caller-side errors
|
|
32
|
+
* (auth, content policy, abort, intentional quota deny) so a real
|
|
33
|
+
* problem doesn't get masked by a successful fallback.
|
|
34
|
+
*
|
|
35
|
+
* Unwraps a single layer of `RetryError` (the AI SDK wraps the
|
|
36
|
+
* underlying APICallError after exhausting its internal retries) so
|
|
37
|
+
* the status-code logic applies to the root cause.
|
|
38
|
+
*/
|
|
39
|
+
export declare function shouldFallback(err: unknown): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Map an Anthropic model id to its OpenAI equivalent for the fallback
|
|
42
|
+
* path. Capability + cost parity:
|
|
43
|
+
* - Haiku → gpt-4o-mini (fast, cheap)
|
|
44
|
+
* - Sonnet → gpt-4o (capable, mid-range)
|
|
45
|
+
* - Opus → gpt-4o (closest available equivalent)
|
|
46
|
+
* - Unknown → gpt-4o-mini (conservative default — cheaper)
|
|
47
|
+
*
|
|
48
|
+
* Anthropic model ids may include date suffixes
|
|
49
|
+
* (e.g. `claude-haiku-4-5-20251001`); the substring match handles all
|
|
50
|
+
* variants.
|
|
51
|
+
*/
|
|
52
|
+
export declare function mapModelIdToOpenAI(anthropicModelId: string | null | undefined): string;
|
|
53
|
+
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/runtime/providers.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CA2DpD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAKtF"}
|