maestro-core 0.2.1 → 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.
Files changed (43) hide show
  1. package/dist/cost.d.ts +60 -0
  2. package/dist/cost.d.ts.map +1 -0
  3. package/dist/cost.js +68 -0
  4. package/dist/cost.js.map +1 -0
  5. package/dist/index.d.ts +3 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +6 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/models.d.ts +69 -0
  10. package/dist/models.d.ts.map +1 -0
  11. package/dist/models.js +113 -0
  12. package/dist/models.js.map +1 -0
  13. package/dist/ports/quota-store.d.ts +2 -0
  14. package/dist/ports/quota-store.d.ts.map +1 -1
  15. package/dist/runtime/empty-recovery.d.ts +62 -0
  16. package/dist/runtime/empty-recovery.d.ts.map +1 -0
  17. package/dist/runtime/empty-recovery.js +34 -0
  18. package/dist/runtime/empty-recovery.js.map +1 -0
  19. package/dist/runtime/index.d.ts +6 -0
  20. package/dist/runtime/index.d.ts.map +1 -0
  21. package/dist/runtime/index.js +6 -0
  22. package/dist/runtime/index.js.map +1 -0
  23. package/dist/runtime/memory.d.ts +32 -0
  24. package/dist/runtime/memory.d.ts.map +1 -0
  25. package/dist/runtime/memory.js +15 -0
  26. package/dist/runtime/memory.js.map +1 -0
  27. package/dist/runtime/providers.d.ts +53 -0
  28. package/dist/runtime/providers.d.ts.map +1 -0
  29. package/dist/runtime/providers.js +124 -0
  30. package/dist/runtime/providers.js.map +1 -0
  31. package/dist/runtime/quota.d.ts +66 -0
  32. package/dist/runtime/quota.d.ts.map +1 -0
  33. package/dist/runtime/quota.js +102 -0
  34. package/dist/runtime/quota.js.map +1 -0
  35. package/dist/runtime/run-chat-turn.d.ts +136 -0
  36. package/dist/runtime/run-chat-turn.d.ts.map +1 -0
  37. package/dist/runtime/run-chat-turn.js +329 -0
  38. package/dist/runtime/run-chat-turn.js.map +1 -0
  39. package/dist/windows.d.ts +49 -0
  40. package/dist/windows.d.ts.map +1 -0
  41. package/dist/windows.js +63 -0
  42. package/dist/windows.js.map +1 -0
  43. 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
@@ -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
@@ -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"}
@@ -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":"AAAA;;;;;;;;;;;;;;GAcG;AAWH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAsB;IACrD,KAAK;IACL,SAAS;IACT,YAAY;IACZ,QAAQ;IACR,UAAU;IACV,UAAU;IACV,iBAAiB;IACjB,gBAAgB;IAChB,OAAO;IACP,cAAc;IACd,aAAa;IACb,mBAAmB;IACnB,SAAS;IACT,SAAS;IACT,QAAQ;IACR,UAAU;IACV,SAAS;IACT,cAAc;IACd,iBAAiB;IACjB,sBAAsB;IACtB,uBAAuB;IACvB,KAAK;IACL,UAAU;IACV,WAAW;IACX,iBAAiB;IACjB,aAAa;IACb,aAAa;IACb,UAAU;IACV,iBAAiB;IACjB,KAAK;IACL,OAAO;IACP,WAAW;IACX,QAAQ;IACR,YAAY;IACZ,YAAY;IACZ,aAAa;IACb,eAAe;IACf,kBAAkB;IAClB,eAAe;IACf,QAAQ;IACR,SAAS;CACZ,CAAA;AAED,2EAA2E;AAC3E,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,CAAA;AAEjD,iGAAiG;AACjG,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAA;AA+B7C;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,IAAqB;IACjD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAA;IACzC,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAA;IACvE,CAAC;IACD,IAAI,IAAI,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA;IAC1E,CAAC;IACD,IAAI,IAAI,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;QAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA;IACxE,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAC1D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;IACvE,CAAC;IAED,MAAM,eAAe,GAAG,IAAI,CAAC,oBAAoB,IAAI,8BAA8B,CAAA;IACnF,IAAI,IAAI,CAAC,MAAM,IAAI,eAAe,EAAE,CAAC;QACjC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;IAChF,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,IAAI,CAAC,CAAA;IAChC,MAAM,aAAa,GAAG,IAAI,CAAC,kBAAkB,IAAI,4BAA4B,CAAA;IAC7E,IAAI,IAAI,IAAI,aAAa,EAAE,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,CAAA;IAC/E,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,IAAI,sBAAsB,CAAA;IAC7D,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACzB,OAAO;gBACH,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;gBAC1B,MAAM,EAAE,WAAW,OAAO,CAAC,IAAI,EAAE,EAAE;aACtC,CAAA;QACL,CAAC;IACL,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;AAC9E,CAAC"}
@@ -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"}