@code-yeongyu/senpi 2026.7.20-2 → 2026.7.20

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 (160) hide show
  1. package/CHANGELOG.md +0 -18
  2. package/dist/core/agent-session.d.ts +0 -32
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +68 -368
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/compaction/compaction.d.ts +2 -2
  7. package/dist/core/compaction/compaction.d.ts.map +1 -1
  8. package/dist/core/compaction/compaction.js +11 -39
  9. package/dist/core/compaction/compaction.js.map +1 -1
  10. package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
  11. package/dist/core/extensions/builtin/compaction/index.js +8 -24
  12. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  13. package/dist/core/extensions/builtin/goal/command-registration.d.ts +2 -2
  14. package/dist/core/extensions/builtin/goal/command-registration.d.ts.map +1 -1
  15. package/dist/core/extensions/builtin/goal/command-registration.js +4 -3
  16. package/dist/core/extensions/builtin/goal/command-registration.js.map +1 -1
  17. package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
  18. package/dist/core/extensions/builtin/goal/index.js +27 -11
  19. package/dist/core/extensions/builtin/goal/index.js.map +1 -1
  20. package/dist/core/extensions/builtin/goal/tool-registration.d.ts +2 -2
  21. package/dist/core/extensions/builtin/goal/tool-registration.d.ts.map +1 -1
  22. package/dist/core/extensions/builtin/goal/tool-registration.js +3 -2
  23. package/dist/core/extensions/builtin/goal/tool-registration.js.map +1 -1
  24. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  25. package/dist/core/extensions/builtin/index.js +0 -2
  26. package/dist/core/extensions/builtin/index.js.map +1 -1
  27. package/dist/core/extensions/builtin/nested-agents-md/index.d.ts.map +1 -1
  28. package/dist/core/extensions/builtin/nested-agents-md/index.js +1 -4
  29. package/dist/core/extensions/builtin/nested-agents-md/index.js.map +1 -1
  30. package/dist/core/extensions/builtin/rules/index.d.ts.map +1 -1
  31. package/dist/core/extensions/builtin/rules/index.js +1 -4
  32. package/dist/core/extensions/builtin/rules/index.js.map +1 -1
  33. package/dist/core/extensions/builtin/websearch/websearch/renderers.d.ts.map +1 -1
  34. package/dist/core/extensions/builtin/websearch/websearch/renderers.js +4 -13
  35. package/dist/core/extensions/builtin/websearch/websearch/renderers.js.map +1 -1
  36. package/dist/core/extensions/builtin/websearch/websearch/search.d.ts +2 -3
  37. package/dist/core/extensions/builtin/websearch/websearch/search.d.ts.map +1 -1
  38. package/dist/core/extensions/builtin/websearch/websearch/search.js +1 -2
  39. package/dist/core/extensions/builtin/websearch/websearch/search.js.map +1 -1
  40. package/dist/core/extensions/builtin/websearch/websearch/tool.d.ts.map +1 -1
  41. package/dist/core/extensions/builtin/websearch/websearch/tool.js +1 -17
  42. package/dist/core/extensions/builtin/websearch/websearch/tool.js.map +1 -1
  43. package/dist/core/extensions/builtin/websearch/websearch/types.d.ts +0 -2
  44. package/dist/core/extensions/builtin/websearch/websearch/types.d.ts.map +1 -1
  45. package/dist/core/extensions/builtin/websearch/websearch/types.js.map +1 -1
  46. package/dist/core/extensions/runner.d.ts +0 -1
  47. package/dist/core/extensions/runner.d.ts.map +1 -1
  48. package/dist/core/extensions/runner.js +0 -31
  49. package/dist/core/extensions/runner.js.map +1 -1
  50. package/dist/core/extensions/types.d.ts +10 -67
  51. package/dist/core/extensions/types.d.ts.map +1 -1
  52. package/dist/core/extensions/types.js.map +1 -1
  53. package/dist/core/sdk.d.ts.map +1 -1
  54. package/dist/core/sdk.js +0 -1
  55. package/dist/core/sdk.js.map +1 -1
  56. package/dist/core/session-manager.d.ts +1 -6
  57. package/dist/core/session-manager.d.ts.map +1 -1
  58. package/dist/core/session-manager.js +3 -19
  59. package/dist/core/session-manager.js.map +1 -1
  60. package/dist/core/settings-manager.d.ts +0 -15
  61. package/dist/core/settings-manager.d.ts.map +1 -1
  62. package/dist/core/settings-manager.js +1 -80
  63. package/dist/core/settings-manager.js.map +1 -1
  64. package/dist/modes/interactive/components/footer.d.ts +1 -2
  65. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  66. package/dist/modes/interactive/components/footer.js +2 -21
  67. package/dist/modes/interactive/components/footer.js.map +1 -1
  68. package/dist/modes/interactive/interactive-mode.d.ts +0 -4
  69. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  70. package/dist/modes/interactive/interactive-mode.js +3 -78
  71. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  72. package/docs/extensions.md +0 -28
  73. package/docs/settings.md +0 -35
  74. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +0 -12
  75. package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
  76. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  77. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +8 -76
  78. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
  79. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
  80. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +1 -26
  81. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
  82. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
  83. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +2 -24
  84. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
  85. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts +0 -5
  86. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts.map +1 -1
  87. package/node_modules/@earendil-works/pi-agent-core/dist/types.js.map +1 -1
  88. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  89. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  90. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +25 -68
  91. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  92. package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.d.ts.map +1 -1
  93. package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js +52 -62
  94. package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js.map +1 -1
  95. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +0 -1
  96. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  97. package/node_modules/@earendil-works/pi-ai/dist/index.js +0 -1
  98. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  99. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +4 -0
  100. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  101. package/node_modules/@earendil-works/pi-ai/dist/providers/data/kimi-coding.json +1 -1
  102. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  103. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  104. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.d.ts +0 -1
  105. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.d.ts.map +1 -1
  106. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.js +0 -1
  107. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.js.map +1 -1
  108. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts +4 -0
  109. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts.map +1 -1
  110. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js.map +1 -1
  111. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +0 -15
  112. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  113. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  114. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  115. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +1 -5
  116. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  117. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  118. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  119. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  120. package/package.json +6 -6
  121. package/dist/core/extensions/builtin/goal/turn-usage.d.ts +0 -20
  122. package/dist/core/extensions/builtin/goal/turn-usage.d.ts.map +0 -1
  123. package/dist/core/extensions/builtin/goal/turn-usage.js +0 -61
  124. package/dist/core/extensions/builtin/goal/turn-usage.js.map +0 -1
  125. package/dist/core/extensions/builtin/model-fallback/index.d.ts +0 -4
  126. package/dist/core/extensions/builtin/model-fallback/index.d.ts.map +0 -1
  127. package/dist/core/extensions/builtin/model-fallback/index.js +0 -55
  128. package/dist/core/extensions/builtin/model-fallback/index.js.map +0 -1
  129. package/dist/core/extensions/builtin/model-fallback/settings.d.ts +0 -6
  130. package/dist/core/extensions/builtin/model-fallback/settings.d.ts.map +0 -1
  131. package/dist/core/extensions/builtin/model-fallback/settings.js +0 -11
  132. package/dist/core/extensions/builtin/model-fallback/settings.js.map +0 -1
  133. package/dist/core/extensions/builtin/model-fallback/ui.d.ts +0 -12
  134. package/dist/core/extensions/builtin/model-fallback/ui.d.ts.map +0 -1
  135. package/dist/core/extensions/builtin/model-fallback/ui.js +0 -72
  136. package/dist/core/extensions/builtin/model-fallback/ui.js.map +0 -1
  137. package/dist/core/retry-fallback/chains.d.ts +0 -29
  138. package/dist/core/retry-fallback/chains.d.ts.map +0 -1
  139. package/dist/core/retry-fallback/chains.js +0 -109
  140. package/dist/core/retry-fallback/chains.js.map +0 -1
  141. package/dist/core/retry-fallback/controller.d.ts +0 -77
  142. package/dist/core/retry-fallback/controller.d.ts.map +0 -1
  143. package/dist/core/retry-fallback/controller.js +0 -157
  144. package/dist/core/retry-fallback/controller.js.map +0 -1
  145. package/dist/core/retry-fallback/cooldown.d.ts +0 -21
  146. package/dist/core/retry-fallback/cooldown.d.ts.map +0 -1
  147. package/dist/core/retry-fallback/cooldown.js +0 -49
  148. package/dist/core/retry-fallback/cooldown.js.map +0 -1
  149. package/dist/core/retry-fallback/log.d.ts +0 -10
  150. package/dist/core/retry-fallback/log.d.ts.map +0 -1
  151. package/dist/core/retry-fallback/log.js +0 -128
  152. package/dist/core/retry-fallback/log.js.map +0 -1
  153. package/dist/core/retry-fallback/validate.d.ts +0 -8
  154. package/dist/core/retry-fallback/validate.d.ts.map +0 -1
  155. package/dist/core/retry-fallback/validate.js +0 -63
  156. package/dist/core/retry-fallback/validate.js.map +0 -1
  157. package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.d.ts +0 -4
  158. package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.d.ts.map +0 -1
  159. package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.js +0 -6
  160. package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.js.map +0 -1
@@ -1,157 +0,0 @@
1
- import { getSupportedThinkingLevels } from "../thinking-levels.js";
2
- import { baseSelector, candidatesAfter, canonicalizeFallbackChains, formatSelector, parseFallbackSelector, resolveChainKey, } from "./chains.js";
3
- export class RetryFallbackController {
4
- constructor(deps) {
5
- this.triedSelectors = new Set();
6
- this.deps = deps;
7
- }
8
- get activeState() {
9
- return this.state;
10
- }
11
- get exhaustedChainKey() {
12
- return this.lastExhaustedChainKey;
13
- }
14
- resetTurn() {
15
- this.triedSelectors.clear();
16
- this.lastExhaustedChainKey = undefined;
17
- }
18
- clear() {
19
- this.state = undefined;
20
- this.resetTurn();
21
- }
22
- canTryFallback() {
23
- return this.nextCandidate(false) !== undefined;
24
- }
25
- /**
26
- * Revert to the chain's original model at a turn boundary. Only fires for
27
- * unpinned state under the cooldown-expiry policy once the original selector
28
- * is no longer suppressed and is still usable; pinned (refusal) state and the
29
- * "never" policy always hold the fallback model.
30
- */
31
- async maybeRestorePrimary(revertPolicy) {
32
- const state = this.state;
33
- if (!state || state.pinned || revertPolicy !== "cooldown-expiry")
34
- return false;
35
- if (this.deps.cooldowns.isSuppressed(state.originalSelector))
36
- return false;
37
- const selector = parseFallbackSelector(state.originalSelector, this.deps.registry);
38
- if (!selector || !this.deps.isAuthAvailable(selector.provider))
39
- return false;
40
- const model = this.deps.registry.find(selector.provider, selector.id);
41
- const current = this.deps.getCurrentSelector();
42
- if (!model || !current)
43
- return false;
44
- // User override wins: only restore the original thinking level when the
45
- // current level still equals the level the fallback switch applied. A manual
46
- // setThinkingLevel clears lastAppliedThinkingLevel (see noteManualThinkingLevel).
47
- const thinking = current.thinkingLevel === state.lastAppliedThinkingLevel
48
- ? (state.originalThinkingLevel ?? current.thinkingLevel ?? "off")
49
- : (current.thinkingLevel ?? "off");
50
- await this.deps.switchModel(model, thinking, "fallback-revert");
51
- const from = formatSelector(current.model);
52
- this.state = undefined;
53
- this.deps.logger.info("fallback_reverted", { from, to: state.originalSelector });
54
- this.deps.emit({ type: "retry_fallback_reverted", from, to: state.originalSelector });
55
- return true;
56
- }
57
- /**
58
- * A user-driven setThinkingLevel makes the current level a deliberate choice,
59
- * so the revert restore-rule must no longer treat it as fallback-applied.
60
- */
61
- noteManualThinkingLevel() {
62
- if (this.state)
63
- this.state.lastAppliedThinkingLevel = undefined;
64
- }
65
- /** A user-driven model change abandons the fallback window entirely. */
66
- clearForManualModelChange(model) {
67
- if (this.state) {
68
- this.deps.logger.info("fallback_cleared_manual", { selector: formatSelector(model) });
69
- }
70
- this.state = undefined;
71
- this.deps.cooldowns.clear(formatSelector(model));
72
- }
73
- async tryFallback(reason, failure) {
74
- const current = this.deps.getCurrentSelector();
75
- const candidate = this.nextCandidate();
76
- if (!current || !candidate)
77
- return false;
78
- const currentBase = formatSelector(current.model);
79
- if (reason === "transient" || reason === "hard-error") {
80
- this.deps.cooldowns.note(currentBase, failure);
81
- this.deps.logger.info("cooldown_noted", { selector: currentBase, errorMessage: failure.errorMessage });
82
- }
83
- const thinking = this.selectThinking(candidate.selector, candidate.model, current.thinkingLevel);
84
- await this.deps.switchModel(candidate.model, thinking, "fallback");
85
- const from = formatSelector(current.model);
86
- const to = formatSelector(candidate.model);
87
- this.state = {
88
- chainKey: candidate.chainKey,
89
- originalSelector: this.state?.originalSelector ?? from,
90
- originalThinkingLevel: this.state?.originalThinkingLevel ?? current.thinkingLevel,
91
- lastAppliedThinkingLevel: thinking,
92
- pinned: this.state?.pinned === true || reason === "refusal",
93
- };
94
- this.deps.logger.info("fallback_applied", { from, to, chainKey: candidate.chainKey, reason });
95
- this.deps.emit({ type: "retry_fallback_applied", from, to, chainKey: candidate.chainKey, reason });
96
- return true;
97
- }
98
- nextCandidate(reserve = true) {
99
- const settings = this.deps.getSettings();
100
- const current = this.deps.getCurrentSelector();
101
- if (!settings.modelFallback || !current)
102
- return undefined;
103
- const chains = canonicalizeFallbackChains(settings.chains, this.deps.registry);
104
- const chainKey = resolveChainKey(current.model, current.thinkingLevel, chains) ?? this.state?.chainKey;
105
- const entries = chainKey ? chains[chainKey] : undefined;
106
- if (!chainKey || !entries) {
107
- if (reserve)
108
- this.deps.logger.debug("no_chain", { selector: formatSelector(current.model) });
109
- return undefined;
110
- }
111
- for (const raw of candidatesAfter(entries, formatSelector(current.model, current.thinkingLevel))) {
112
- const selector = parseFallbackSelector(raw, this.deps.registry);
113
- if (!selector) {
114
- this.skip(raw, "unknown");
115
- continue;
116
- }
117
- if (selector.provider === current.model.provider && selector.id === current.model.id) {
118
- this.skip(raw, "self");
119
- continue;
120
- }
121
- const base = baseSelector(selector);
122
- if (this.triedSelectors.has(base)) {
123
- this.skip(raw, "tried");
124
- continue;
125
- }
126
- if (this.deps.cooldowns.isSuppressed(base)) {
127
- this.skip(raw, "suppressed");
128
- continue;
129
- }
130
- if (!this.deps.isAuthAvailable(selector.provider)) {
131
- this.skip(raw, "unauthenticated");
132
- continue;
133
- }
134
- const model = this.deps.registry.find(selector.provider, selector.id);
135
- if (!model) {
136
- this.skip(raw, "unknown");
137
- continue;
138
- }
139
- if (reserve)
140
- this.triedSelectors.add(base);
141
- return { chainKey, selector, model };
142
- }
143
- this.lastExhaustedChainKey = chainKey;
144
- if (reserve)
145
- this.deps.logger.info("candidates_exhausted", { chainKey });
146
- return undefined;
147
- }
148
- selectThinking(selector, model, inherited) {
149
- const requested = selector.thinkingLevel ?? inherited ?? "off";
150
- const supported = getSupportedThinkingLevels(model);
151
- return supported.includes(requested) ? requested : (supported[supported.length - 1] ?? "off");
152
- }
153
- skip(candidate, skipReason) {
154
- this.deps.logger.debug("candidate_skipped", { candidate, skipReason });
155
- }
156
- }
157
- //# sourceMappingURL=controller.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../src/core/retry-fallback/controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { getSupportedThinkingLevels } from \"../thinking-levels.ts\";\nimport {\n\tbaseSelector,\n\tcandidatesAfter,\n\tcanonicalizeFallbackChains,\n\ttype FallbackSelector,\n\tformatSelector,\n\tparseFallbackSelector,\n\tresolveChainKey,\n} from \"./chains.ts\";\nimport type { SelectorCooldowns } from \"./cooldown.ts\";\nimport type { FallbackLogger } from \"./log.ts\";\n\nexport interface ActiveFallbackState {\n\tchainKey: string;\n\toriginalSelector: string;\n\toriginalThinkingLevel?: ThinkingLevel;\n\tlastAppliedThinkingLevel?: ThinkingLevel;\n\tpinned: boolean;\n}\n\ntype FallbackReason = \"transient\" | \"refusal\" | \"hard-error\";\n\ninterface FallbackSettings {\n\tmodelFallback: boolean;\n\tchains: Readonly<Record<string, readonly string[]>>;\n}\n\nexport interface RetryFallbackControllerDeps {\n\tgetSettings(): FallbackSettings;\n\tregistry: { find(provider: string, id: string): Model<Api> | undefined; getAll(): Model<Api>[] };\n\tcooldowns: SelectorCooldowns;\n\tlogger: FallbackLogger;\n\tswitchModel(model: Model<Api>, thinking: ThinkingLevel, reason: \"fallback\" | \"fallback-revert\"): Promise<void>;\n\temit(\n\t\tevent:\n\t\t\t| {\n\t\t\t\t\ttype: \"retry_fallback_applied\";\n\t\t\t\t\tfrom: string;\n\t\t\t\t\tto: string;\n\t\t\t\t\tchainKey: string;\n\t\t\t\t\treason: FallbackReason;\n\t\t\t }\n\t\t\t| { type: \"retry_fallback_reverted\"; from: string; to: string },\n\t): void;\n\tgetCurrentSelector(): { model: Model<Api>; thinkingLevel?: ThinkingLevel } | undefined;\n\tisAuthAvailable(provider: string): boolean;\n}\n\nexport class RetryFallbackController {\n\tprivate readonly deps: RetryFallbackControllerDeps;\n\tprivate readonly triedSelectors = new Set<string>();\n\tprivate state: ActiveFallbackState | undefined;\n\tprivate lastExhaustedChainKey: string | undefined;\n\n\tconstructor(deps: RetryFallbackControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tget activeState(): Readonly<ActiveFallbackState> | undefined {\n\t\treturn this.state;\n\t}\n\n\tget exhaustedChainKey(): string | undefined {\n\t\treturn this.lastExhaustedChainKey;\n\t}\n\n\tresetTurn(): void {\n\t\tthis.triedSelectors.clear();\n\t\tthis.lastExhaustedChainKey = undefined;\n\t}\n\n\tclear(): void {\n\t\tthis.state = undefined;\n\t\tthis.resetTurn();\n\t}\n\n\tcanTryFallback(): boolean {\n\t\treturn this.nextCandidate(false) !== undefined;\n\t}\n\n\t/**\n\t * Revert to the chain's original model at a turn boundary. Only fires for\n\t * unpinned state under the cooldown-expiry policy once the original selector\n\t * is no longer suppressed and is still usable; pinned (refusal) state and the\n\t * \"never\" policy always hold the fallback model.\n\t */\n\tasync maybeRestorePrimary(revertPolicy: \"cooldown-expiry\" | \"never\"): Promise<boolean> {\n\t\tconst state = this.state;\n\t\tif (!state || state.pinned || revertPolicy !== \"cooldown-expiry\") return false;\n\t\tif (this.deps.cooldowns.isSuppressed(state.originalSelector)) return false;\n\t\tconst selector = parseFallbackSelector(state.originalSelector, this.deps.registry);\n\t\tif (!selector || !this.deps.isAuthAvailable(selector.provider)) return false;\n\t\tconst model = this.deps.registry.find(selector.provider, selector.id);\n\t\tconst current = this.deps.getCurrentSelector();\n\t\tif (!model || !current) return false;\n\t\t// User override wins: only restore the original thinking level when the\n\t\t// current level still equals the level the fallback switch applied. A manual\n\t\t// setThinkingLevel clears lastAppliedThinkingLevel (see noteManualThinkingLevel).\n\t\tconst thinking =\n\t\t\tcurrent.thinkingLevel === state.lastAppliedThinkingLevel\n\t\t\t\t? (state.originalThinkingLevel ?? current.thinkingLevel ?? \"off\")\n\t\t\t\t: (current.thinkingLevel ?? \"off\");\n\t\tawait this.deps.switchModel(model, thinking, \"fallback-revert\");\n\t\tconst from = formatSelector(current.model);\n\t\tthis.state = undefined;\n\t\tthis.deps.logger.info(\"fallback_reverted\", { from, to: state.originalSelector });\n\t\tthis.deps.emit({ type: \"retry_fallback_reverted\", from, to: state.originalSelector });\n\t\treturn true;\n\t}\n\n\t/**\n\t * A user-driven setThinkingLevel makes the current level a deliberate choice,\n\t * so the revert restore-rule must no longer treat it as fallback-applied.\n\t */\n\tnoteManualThinkingLevel(): void {\n\t\tif (this.state) this.state.lastAppliedThinkingLevel = undefined;\n\t}\n\n\t/** A user-driven model change abandons the fallback window entirely. */\n\tclearForManualModelChange(model: Model<Api>): void {\n\t\tif (this.state) {\n\t\t\tthis.deps.logger.info(\"fallback_cleared_manual\", { selector: formatSelector(model) });\n\t\t}\n\t\tthis.state = undefined;\n\t\tthis.deps.cooldowns.clear(formatSelector(model));\n\t}\n\n\tasync tryFallback(\n\t\treason: FallbackReason,\n\t\tfailure: { errorMessage?: string; retryAfterMs?: number },\n\t): Promise<boolean> {\n\t\tconst current = this.deps.getCurrentSelector();\n\t\tconst candidate = this.nextCandidate();\n\t\tif (!current || !candidate) return false;\n\t\tconst currentBase = formatSelector(current.model);\n\t\tif (reason === \"transient\" || reason === \"hard-error\") {\n\t\t\tthis.deps.cooldowns.note(currentBase, failure);\n\t\t\tthis.deps.logger.info(\"cooldown_noted\", { selector: currentBase, errorMessage: failure.errorMessage });\n\t\t}\n\n\t\tconst thinking = this.selectThinking(candidate.selector, candidate.model, current.thinkingLevel);\n\t\tawait this.deps.switchModel(candidate.model, thinking, \"fallback\");\n\t\tconst from = formatSelector(current.model);\n\t\tconst to = formatSelector(candidate.model);\n\t\tthis.state = {\n\t\t\tchainKey: candidate.chainKey,\n\t\t\toriginalSelector: this.state?.originalSelector ?? from,\n\t\t\toriginalThinkingLevel: this.state?.originalThinkingLevel ?? current.thinkingLevel,\n\t\t\tlastAppliedThinkingLevel: thinking,\n\t\t\tpinned: this.state?.pinned === true || reason === \"refusal\",\n\t\t};\n\t\tthis.deps.logger.info(\"fallback_applied\", { from, to, chainKey: candidate.chainKey, reason });\n\t\tthis.deps.emit({ type: \"retry_fallback_applied\", from, to, chainKey: candidate.chainKey, reason });\n\t\treturn true;\n\t}\n\n\tprivate nextCandidate(\n\t\treserve = true,\n\t): { chainKey: string; selector: FallbackSelector; model: Model<Api> } | undefined {\n\t\tconst settings = this.deps.getSettings();\n\t\tconst current = this.deps.getCurrentSelector();\n\t\tif (!settings.modelFallback || !current) return undefined;\n\t\tconst chains = canonicalizeFallbackChains(settings.chains, this.deps.registry);\n\t\tconst chainKey = resolveChainKey(current.model, current.thinkingLevel, chains) ?? this.state?.chainKey;\n\t\tconst entries = chainKey ? chains[chainKey] : undefined;\n\t\tif (!chainKey || !entries) {\n\t\t\tif (reserve) this.deps.logger.debug(\"no_chain\", { selector: formatSelector(current.model) });\n\t\t\treturn undefined;\n\t\t}\n\t\tfor (const raw of candidatesAfter(entries, formatSelector(current.model, current.thinkingLevel))) {\n\t\t\tconst selector = parseFallbackSelector(raw, this.deps.registry);\n\t\t\tif (!selector) {\n\t\t\t\tthis.skip(raw, \"unknown\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (selector.provider === current.model.provider && selector.id === current.model.id) {\n\t\t\t\tthis.skip(raw, \"self\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst base = baseSelector(selector);\n\t\t\tif (this.triedSelectors.has(base)) {\n\t\t\t\tthis.skip(raw, \"tried\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (this.deps.cooldowns.isSuppressed(base)) {\n\t\t\t\tthis.skip(raw, \"suppressed\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!this.deps.isAuthAvailable(selector.provider)) {\n\t\t\t\tthis.skip(raw, \"unauthenticated\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst model = this.deps.registry.find(selector.provider, selector.id);\n\t\t\tif (!model) {\n\t\t\t\tthis.skip(raw, \"unknown\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (reserve) this.triedSelectors.add(base);\n\t\t\treturn { chainKey, selector, model };\n\t\t}\n\t\tthis.lastExhaustedChainKey = chainKey;\n\t\tif (reserve) this.deps.logger.info(\"candidates_exhausted\", { chainKey });\n\t\treturn undefined;\n\t}\n\n\tprivate selectThinking(\n\t\tselector: FallbackSelector,\n\t\tmodel: Model<Api>,\n\t\tinherited: ThinkingLevel | undefined,\n\t): ThinkingLevel {\n\t\tconst requested = selector.thinkingLevel ?? inherited ?? \"off\";\n\t\tconst supported = getSupportedThinkingLevels(model);\n\t\treturn supported.includes(requested) ? requested : (supported[supported.length - 1] ?? \"off\");\n\t}\n\n\tprivate skip(candidate: string, skipReason: string): void {\n\t\tthis.deps.logger.debug(\"candidate_skipped\", { candidate, skipReason });\n\t}\n}\n"]}
@@ -1,21 +0,0 @@
1
- /**
2
- * Runtime-only selector suppression. A SelectorCooldowns instance belongs to one
3
- * AgentSession and is deliberately never persisted to settings or session files.
4
- * Callers provide canonical base selectors without a thinking suffix.
5
- */
6
- export declare class SelectorCooldowns {
7
- private readonly expiresAtBySelector;
8
- private readonly now;
9
- private readonly random;
10
- constructor(now: () => number, random?: () => number);
11
- note(baseSelector: string, failure: {
12
- retryAfterMs?: number;
13
- errorMessage?: string;
14
- }): void;
15
- isSuppressed(baseSelector: string): boolean;
16
- clear(baseSelector: string): void;
17
- clearAll(): void;
18
- private durationFor;
19
- private capacityJitterMs;
20
- }
21
- //# sourceMappingURL=cooldown.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cooldown.d.ts","sourceRoot":"","sources":["../../../src/core/retry-fallback/cooldown.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA6B;IACjE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IAEtC,YAAY,GAAG,EAAE,MAAM,MAAM,EAAE,MAAM,GAAE,MAAM,MAAoB,EAGhE;IAED,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAE1F;IAED,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAM1C;IAED,KAAK,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAEhC;IAED,QAAQ,IAAI,IAAI,CAEf;IAED,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,gBAAgB;CAGxB"}
@@ -1,49 +0,0 @@
1
- /**
2
- * Runtime-only selector suppression. A SelectorCooldowns instance belongs to one
3
- * AgentSession and is deliberately never persisted to settings or session files.
4
- * Callers provide canonical base selectors without a thinking suffix.
5
- */
6
- export class SelectorCooldowns {
7
- constructor(now, random = Math.random) {
8
- this.expiresAtBySelector = new Map();
9
- this.now = now;
10
- this.random = random;
11
- }
12
- note(baseSelector, failure) {
13
- this.expiresAtBySelector.set(baseSelector, this.now() + this.durationFor(failure));
14
- }
15
- isSuppressed(baseSelector) {
16
- const expiresAt = this.expiresAtBySelector.get(baseSelector);
17
- if (expiresAt === undefined)
18
- return false;
19
- if (this.now() < expiresAt)
20
- return true;
21
- this.expiresAtBySelector.delete(baseSelector);
22
- return false;
23
- }
24
- clear(baseSelector) {
25
- this.expiresAtBySelector.delete(baseSelector);
26
- }
27
- clearAll() {
28
- this.expiresAtBySelector.clear();
29
- }
30
- durationFor({ retryAfterMs, errorMessage }) {
31
- if (retryAfterMs !== undefined && Number.isFinite(retryAfterMs) && retryAfterMs > 0) {
32
- return retryAfterMs;
33
- }
34
- const message = errorMessage?.toLowerCase() ?? "";
35
- if (/usage[- ]limit|quota|insufficient_quota|billing/.test(message))
36
- return 30 * 60_000;
37
- if (/rate[ -]?limit|429|too many requests/.test(message))
38
- return 30_000;
39
- if (/overloaded|capacity/.test(message))
40
- return 45_000 + this.capacityJitterMs();
41
- if (/5xx|\b5\d\d\b|server|internal error/.test(message))
42
- return 20_000;
43
- return 5 * 60_000;
44
- }
45
- capacityJitterMs() {
46
- return Math.round(Math.min(1, Math.max(0, this.random())) * 30_000);
47
- }
48
- }
49
- //# sourceMappingURL=cooldown.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cooldown.js","sourceRoot":"","sources":["../../../src/core/retry-fallback/cooldown.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IAK7B,YAAY,GAAiB,EAAE,MAAM,GAAiB,IAAI,CAAC,MAAM;QAJhD,wBAAmB,GAAG,IAAI,GAAG,EAAkB,CAAC;QAKhE,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAED,IAAI,CAAC,YAAoB,EAAE,OAAyD;QACnF,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IACpF,CAAC;IAED,YAAY,CAAC,YAAoB;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC7D,IAAI,SAAS,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAC1C,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAC9C,OAAO,KAAK,CAAC;IACd,CAAC;IAED,KAAK,CAAC,YAAoB;QACzB,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAC/C,CAAC;IAED,QAAQ;QACP,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,CAAC;IAClC,CAAC;IAEO,WAAW,CAAC,EAAE,YAAY,EAAE,YAAY,EAAoD;QACnG,IAAI,YAAY,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrF,OAAO,YAAY,CAAC;QACrB,CAAC;QAED,MAAM,OAAO,GAAG,YAAY,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QAClD,IAAI,iDAAiD,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,GAAG,MAAM,CAAC;QACxF,IAAI,sCAAsC,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,MAAM,CAAC;QACxE,IAAI,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,MAAM,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACjF,IAAI,qCAAqC,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,MAAM,CAAC;QACvE,OAAO,CAAC,GAAG,MAAM,CAAC;IACnB,CAAC;IAEO,gBAAgB;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;IACrE,CAAC;CACD","sourcesContent":["/**\n * Runtime-only selector suppression. A SelectorCooldowns instance belongs to one\n * AgentSession and is deliberately never persisted to settings or session files.\n * Callers provide canonical base selectors without a thinking suffix.\n */\nexport class SelectorCooldowns {\n\tprivate readonly expiresAtBySelector = new Map<string, number>();\n\tprivate readonly now: () => number;\n\tprivate readonly random: () => number;\n\n\tconstructor(now: () => number, random: () => number = Math.random) {\n\t\tthis.now = now;\n\t\tthis.random = random;\n\t}\n\n\tnote(baseSelector: string, failure: { retryAfterMs?: number; errorMessage?: string }): void {\n\t\tthis.expiresAtBySelector.set(baseSelector, this.now() + this.durationFor(failure));\n\t}\n\n\tisSuppressed(baseSelector: string): boolean {\n\t\tconst expiresAt = this.expiresAtBySelector.get(baseSelector);\n\t\tif (expiresAt === undefined) return false;\n\t\tif (this.now() < expiresAt) return true;\n\t\tthis.expiresAtBySelector.delete(baseSelector);\n\t\treturn false;\n\t}\n\n\tclear(baseSelector: string): void {\n\t\tthis.expiresAtBySelector.delete(baseSelector);\n\t}\n\n\tclearAll(): void {\n\t\tthis.expiresAtBySelector.clear();\n\t}\n\n\tprivate durationFor({ retryAfterMs, errorMessage }: { retryAfterMs?: number; errorMessage?: string }): number {\n\t\tif (retryAfterMs !== undefined && Number.isFinite(retryAfterMs) && retryAfterMs > 0) {\n\t\t\treturn retryAfterMs;\n\t\t}\n\n\t\tconst message = errorMessage?.toLowerCase() ?? \"\";\n\t\tif (/usage[- ]limit|quota|insufficient_quota|billing/.test(message)) return 30 * 60_000;\n\t\tif (/rate[ -]?limit|429|too many requests/.test(message)) return 30_000;\n\t\tif (/overloaded|capacity/.test(message)) return 45_000 + this.capacityJitterMs();\n\t\tif (/5xx|\\b5\\d\\d\\b|server|internal error/.test(message)) return 20_000;\n\t\treturn 5 * 60_000;\n\t}\n\n\tprivate capacityJitterMs(): number {\n\t\treturn Math.round(Math.min(1, Math.max(0, this.random())) * 30_000);\n\t}\n}\n"]}
@@ -1,10 +0,0 @@
1
- export interface FallbackLogger {
2
- debug(event: string, data?: Record<string, unknown>): void;
3
- info(event: string, data?: Record<string, unknown>): void;
4
- warn(event: string, data?: Record<string, unknown>): void;
5
- }
6
- export interface FallbackLoggerOptions {
7
- maxBytes?: number;
8
- }
9
- export declare function createFallbackLogger(agentDir: string, options?: FallbackLoggerOptions): FallbackLogger;
10
- //# sourceMappingURL=log.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../../src/core/retry-fallback/log.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,cAAc;IAC9B,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3D,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1D,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1D;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,cAAc,CAsB1G"}
@@ -1,128 +0,0 @@
1
- import { chmodSync, closeSync, mkdirSync, openSync, renameSync, rmSync, statSync, writeSync } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- const DEFAULT_MAX_BYTES = 5 * 1024 * 1024;
4
- const MAX_STRING_LENGTH = 200;
5
- const BLOCKED_KEY = /^(?:__proto__|constructor|prototype|headers?|env(?:ironment)?|authorization|credential(?:s)?|password|secret|token|api_?key|client_?secret)$/i;
6
- const ALLOWED_DATA_KEY = /^(?:selector|candidate|currentSelector|originalSelector|from|to|model|chainKey|reason|skipReason|classification|thinkingLevel|durationMs|retryAfterMs|error|errorMessage|warning)$/;
7
- const SENSITIVE_TEXT = /((?:authorization\s*[:=]\s*(?:bearer|basic)\s+)|(?:bearer\s+)|(?:[?&](?:api[_-]?key|token|secret|password|auth(?:orization)?)=))[^\s&,"'}\]]+/gi;
8
- export function createFallbackLogger(agentDir, options = {}) {
9
- const filePath = join(agentDir, "logs", "fallback.log");
10
- const maxBytes = validMaxBytes(options.maxBytes);
11
- let reportedWriteFailure = false;
12
- function log(level, event, data) {
13
- try {
14
- const line = formatLine(level, event, data);
15
- writeLine(filePath, line, maxBytes);
16
- }
17
- catch (error) {
18
- if (!reportedWriteFailure) {
19
- reportedWriteFailure = true;
20
- console.error("Unable to write retry fallback debug log", error);
21
- }
22
- }
23
- }
24
- return {
25
- debug: (event, data) => log("debug", event, data),
26
- info: (event, data) => log("info", event, data),
27
- warn: (event, data) => log("warn", event, data),
28
- };
29
- }
30
- function validMaxBytes(value) {
31
- return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : DEFAULT_MAX_BYTES;
32
- }
33
- function formatLine(level, event, data) {
34
- const entry = {
35
- ts: new Date().toISOString(),
36
- level,
37
- event: safeText(event),
38
- };
39
- if (data !== undefined) {
40
- for (const [key, value] of safeEntries(data)) {
41
- if (ALLOWED_DATA_KEY.test(key) && !BLOCKED_KEY.test(key)) {
42
- const safeValue = serializeValue(value, new WeakSet());
43
- if (safeValue !== undefined)
44
- entry[key] = safeValue;
45
- }
46
- }
47
- }
48
- return JSON.stringify(entry);
49
- }
50
- function writeLine(filePath, line, maxBytes) {
51
- mkdirSync(dirname(filePath), { recursive: true, mode: 0o700 });
52
- const text = `${line}\n`;
53
- if (fileExceedsCap(filePath, Buffer.byteLength(text), maxBytes)) {
54
- rmSync(`${filePath}.1`, { force: true });
55
- renameSync(filePath, `${filePath}.1`);
56
- chmodSync(`${filePath}.1`, 0o600);
57
- }
58
- const descriptor = openSync(filePath, "a", 0o600);
59
- try {
60
- writeSync(descriptor, text);
61
- }
62
- finally {
63
- closeSync(descriptor);
64
- }
65
- chmodSync(filePath, 0o600);
66
- }
67
- function fileExceedsCap(filePath, incomingBytes, maxBytes) {
68
- try {
69
- return statSync(filePath).size + incomingBytes > maxBytes;
70
- }
71
- catch (error) {
72
- if (isMissingFileError(error))
73
- return false;
74
- throw error;
75
- }
76
- }
77
- function isMissingFileError(error) {
78
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
79
- }
80
- function serializeValue(value, seen) {
81
- if (typeof value === "string")
82
- return safeText(value);
83
- if (typeof value === "bigint")
84
- return value.toString();
85
- if (typeof value === "number" || typeof value === "boolean" || value === null)
86
- return value;
87
- if (typeof value === "undefined")
88
- return undefined;
89
- if (typeof value === "function" || typeof value === "symbol")
90
- return String(value);
91
- if (seen.has(value))
92
- return "[Circular]";
93
- seen.add(value);
94
- if (Array.isArray(value))
95
- return value.map((item) => serializeValue(item, seen) ?? null);
96
- const result = {};
97
- for (const [key, item] of safeEntries(value)) {
98
- if (!BLOCKED_KEY.test(key)) {
99
- const safeValue = serializeValue(item, seen);
100
- if (safeValue !== undefined)
101
- result[key] = safeValue;
102
- }
103
- }
104
- return result;
105
- }
106
- function safeEntries(value) {
107
- try {
108
- const entries = [];
109
- for (const key of Object.keys(value)) {
110
- try {
111
- const item = Reflect.get(value, key);
112
- entries.push([key, item]);
113
- }
114
- catch {
115
- entries.push([key, "[Unreadable]"]);
116
- }
117
- }
118
- return entries;
119
- }
120
- catch {
121
- return [["unserializable", "[Unreadable]"]];
122
- }
123
- }
124
- function safeText(value) {
125
- const redacted = value.replace(SENSITIVE_TEXT, "$1[redacted]");
126
- return redacted.length <= MAX_STRING_LENGTH ? redacted : `${redacted.slice(0, MAX_STRING_LENGTH - 3)}...`;
127
- }
128
- //# sourceMappingURL=log.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"log.js","sourceRoot":"","sources":["../../../src/core/retry-fallback/log.ts"],"names":[],"mappings":"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","sourcesContent":["import { chmodSync, closeSync, mkdirSync, openSync, renameSync, rmSync, statSync, writeSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nconst DEFAULT_MAX_BYTES = 5 * 1024 * 1024;\nconst MAX_STRING_LENGTH = 200;\nconst BLOCKED_KEY =\n\t/^(?:__proto__|constructor|prototype|headers?|env(?:ironment)?|authorization|credential(?:s)?|password|secret|token|api_?key|client_?secret)$/i;\nconst ALLOWED_DATA_KEY =\n\t/^(?:selector|candidate|currentSelector|originalSelector|from|to|model|chainKey|reason|skipReason|classification|thinkingLevel|durationMs|retryAfterMs|error|errorMessage|warning)$/;\nconst SENSITIVE_TEXT =\n\t/((?:authorization\\s*[:=]\\s*(?:bearer|basic)\\s+)|(?:bearer\\s+)|(?:[?&](?:api[_-]?key|token|secret|password|auth(?:orization)?)=))[^\\s&,\"'}\\]]+/gi;\n\nexport interface FallbackLogger {\n\tdebug(event: string, data?: Record<string, unknown>): void;\n\tinfo(event: string, data?: Record<string, unknown>): void;\n\twarn(event: string, data?: Record<string, unknown>): void;\n}\n\nexport interface FallbackLoggerOptions {\n\tmaxBytes?: number;\n}\n\nexport function createFallbackLogger(agentDir: string, options: FallbackLoggerOptions = {}): FallbackLogger {\n\tconst filePath = join(agentDir, \"logs\", \"fallback.log\");\n\tconst maxBytes = validMaxBytes(options.maxBytes);\n\tlet reportedWriteFailure = false;\n\n\tfunction log(level: \"debug\" | \"info\" | \"warn\", event: string, data?: Record<string, unknown>): void {\n\t\ttry {\n\t\t\tconst line = formatLine(level, event, data);\n\t\t\twriteLine(filePath, line, maxBytes);\n\t\t} catch (error) {\n\t\t\tif (!reportedWriteFailure) {\n\t\t\t\treportedWriteFailure = true;\n\t\t\t\tconsole.error(\"Unable to write retry fallback debug log\", error);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tdebug: (event, data) => log(\"debug\", event, data),\n\t\tinfo: (event, data) => log(\"info\", event, data),\n\t\twarn: (event, data) => log(\"warn\", event, data),\n\t};\n}\n\nfunction validMaxBytes(value: number | undefined): number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value > 0 ? Math.floor(value) : DEFAULT_MAX_BYTES;\n}\n\nfunction formatLine(\n\tlevel: \"debug\" | \"info\" | \"warn\",\n\tevent: string,\n\tdata: Record<string, unknown> | undefined,\n): string {\n\tconst entry: Record<string, unknown> = {\n\t\tts: new Date().toISOString(),\n\t\tlevel,\n\t\tevent: safeText(event),\n\t};\n\tif (data !== undefined) {\n\t\tfor (const [key, value] of safeEntries(data)) {\n\t\t\tif (ALLOWED_DATA_KEY.test(key) && !BLOCKED_KEY.test(key)) {\n\t\t\t\tconst safeValue = serializeValue(value, new WeakSet<object>());\n\t\t\t\tif (safeValue !== undefined) entry[key] = safeValue;\n\t\t\t}\n\t\t}\n\t}\n\treturn JSON.stringify(entry);\n}\n\nfunction writeLine(filePath: string, line: string, maxBytes: number): void {\n\tmkdirSync(dirname(filePath), { recursive: true, mode: 0o700 });\n\tconst text = `${line}\\n`;\n\tif (fileExceedsCap(filePath, Buffer.byteLength(text), maxBytes)) {\n\t\trmSync(`${filePath}.1`, { force: true });\n\t\trenameSync(filePath, `${filePath}.1`);\n\t\tchmodSync(`${filePath}.1`, 0o600);\n\t}\n\tconst descriptor = openSync(filePath, \"a\", 0o600);\n\ttry {\n\t\twriteSync(descriptor, text);\n\t} finally {\n\t\tcloseSync(descriptor);\n\t}\n\tchmodSync(filePath, 0o600);\n}\n\nfunction fileExceedsCap(filePath: string, incomingBytes: number, maxBytes: number): boolean {\n\ttry {\n\t\treturn statSync(filePath).size + incomingBytes > maxBytes;\n\t} catch (error) {\n\t\tif (isMissingFileError(error)) return false;\n\t\tthrow error;\n\t}\n}\n\nfunction isMissingFileError(error: unknown): boolean {\n\treturn typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\";\n}\n\nfunction serializeValue(value: unknown, seen: WeakSet<object>): unknown {\n\tif (typeof value === \"string\") return safeText(value);\n\tif (typeof value === \"bigint\") return value.toString();\n\tif (typeof value === \"number\" || typeof value === \"boolean\" || value === null) return value;\n\tif (typeof value === \"undefined\") return undefined;\n\tif (typeof value === \"function\" || typeof value === \"symbol\") return String(value);\n\tif (seen.has(value)) return \"[Circular]\";\n\tseen.add(value);\n\tif (Array.isArray(value)) return value.map((item) => serializeValue(item, seen) ?? null);\n\tconst result: Record<string, unknown> = {};\n\tfor (const [key, item] of safeEntries(value)) {\n\t\tif (!BLOCKED_KEY.test(key)) {\n\t\t\tconst safeValue = serializeValue(item, seen);\n\t\t\tif (safeValue !== undefined) result[key] = safeValue;\n\t\t}\n\t}\n\treturn result;\n}\n\nfunction safeEntries(value: object): Array<[string, unknown]> {\n\ttry {\n\t\tconst entries: Array<[string, unknown]> = [];\n\t\tfor (const key of Object.keys(value)) {\n\t\t\ttry {\n\t\t\t\tconst item: unknown = Reflect.get(value, key);\n\t\t\t\tentries.push([key, item]);\n\t\t\t} catch {\n\t\t\t\tentries.push([key, \"[Unreadable]\"]);\n\t\t\t}\n\t\t}\n\t\treturn entries;\n\t} catch {\n\t\treturn [[\"unserializable\", \"[Unreadable]\"]];\n\t}\n}\n\nfunction safeText(value: string): string {\n\tconst redacted = value.replace(SENSITIVE_TEXT, \"$1[redacted]\");\n\treturn redacted.length <= MAX_STRING_LENGTH ? redacted : `${redacted.slice(0, MAX_STRING_LENGTH - 3)}...`;\n}\n"]}
@@ -1,8 +0,0 @@
1
- import type { Api, Model } from "@earendil-works/pi-ai";
2
- export interface FallbackModelRegistry {
3
- find(provider: string, id: string): Model<Api> | undefined;
4
- getAll(): Model<Api>[];
5
- }
6
- /** Returns configuration warnings without changing malformed fallback-chain settings. */
7
- export declare function validateFallbackChains(chains: unknown, registry: FallbackModelRegistry): string[];
8
- //# sourceMappingURL=validate.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/core/retry-fallback/validate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAIxD,MAAM,WAAW,qBAAqB;IACrC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC3D,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;CACvB;AA2BD,yFAAyF;AACzF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,qBAAqB,GAAG,MAAM,EAAE,CA+CjG"}
@@ -1,63 +0,0 @@
1
- import { getSupportedThinkingLevels } from "../thinking-levels.js";
2
- import { baseSelector, parseFallbackSelector } from "./chains.js";
3
- function isPlainObject(value) {
4
- if (value === null || typeof value !== "object" || Array.isArray(value))
5
- return false;
6
- const prototype = Object.getPrototypeOf(value);
7
- return prototype === Object.prototype || prototype === null;
8
- }
9
- function invalidSelectorWarning(kind, selector, key) {
10
- const subject = kind === "key" ? `Fallback chain key "${selector}"` : `Fallback chain entry "${selector}" for "${key}"`;
11
- return `${subject} is not a valid or known model selector.`;
12
- }
13
- function validateThinkingLevel(selector, model, subject, warnings) {
14
- if (selector.thinkingLevel && !getSupportedThinkingLevels(model).includes(selector.thinkingLevel)) {
15
- warnings.push(`${subject} uses thinking level "${selector.thinkingLevel}", which is unsupported by ${selector.provider}/${selector.id}.`);
16
- }
17
- }
18
- /** Returns configuration warnings without changing malformed fallback-chain settings. */
19
- export function validateFallbackChains(chains, registry) {
20
- if (!isPlainObject(chains))
21
- return ["Fallback chains must be a plain object."];
22
- const warnings = [];
23
- const models = registry.getAll();
24
- for (const [key, entries] of Object.entries(chains)) {
25
- const hasProvider = key.includes("/");
26
- const hasWildcard = key.includes("*");
27
- if (!hasProvider) {
28
- warnings.push(`Fallback chain key "${key}" must use a provider/model selector; roles are unsupported.`);
29
- }
30
- if (hasWildcard)
31
- warnings.push(`Fallback chain key "${key}" cannot contain wildcards.`);
32
- const parsedKey = hasProvider && !hasWildcard ? parseFallbackSelector(key, models) : undefined;
33
- const keyModel = parsedKey ? registry.find(parsedKey.provider, parsedKey.id) : undefined;
34
- if (hasProvider && !hasWildcard && (!parsedKey || !keyModel)) {
35
- warnings.push(invalidSelectorWarning("key", key));
36
- }
37
- if (parsedKey && keyModel) {
38
- validateThinkingLevel(parsedKey, keyModel, `Fallback chain key "${key}"`, warnings);
39
- }
40
- if (!Array.isArray(entries) || entries.some((entry) => typeof entry !== "string")) {
41
- warnings.push(`Fallback chain "${key}" entries must be an array of strings.`);
42
- continue;
43
- }
44
- if (entries.length === 0) {
45
- warnings.push(`Fallback chain "${key}" must contain at least one entry.`);
46
- continue;
47
- }
48
- for (const entry of entries) {
49
- const parsedEntry = parseFallbackSelector(entry, models);
50
- const entryModel = parsedEntry ? registry.find(parsedEntry.provider, parsedEntry.id) : undefined;
51
- if (!parsedEntry || !entryModel) {
52
- warnings.push(invalidSelectorWarning("entry", entry, key));
53
- continue;
54
- }
55
- if (parsedKey && baseSelector(parsedEntry) === baseSelector(parsedKey)) {
56
- warnings.push(`Fallback chain entry "${entry}" for "${key}" cannot reference the same model.`);
57
- }
58
- validateThinkingLevel(parsedEntry, entryModel, `Fallback chain entry "${entry}"`, warnings);
59
- }
60
- }
61
- return warnings;
62
- }
63
- //# sourceMappingURL=validate.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/core/retry-fallback/validate.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { getSupportedThinkingLevels } from \"../thinking-levels.ts\";\nimport { baseSelector, parseFallbackSelector } from \"./chains.ts\";\n\nexport interface FallbackModelRegistry {\n\tfind(provider: string, id: string): Model<Api> | undefined;\n\tgetAll(): Model<Api>[];\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nfunction invalidSelectorWarning(kind: \"key\" | \"entry\", selector: string, key?: string): string {\n\tconst subject =\n\t\tkind === \"key\" ? `Fallback chain key \"${selector}\"` : `Fallback chain entry \"${selector}\" for \"${key}\"`;\n\treturn `${subject} is not a valid or known model selector.`;\n}\n\nfunction validateThinkingLevel(\n\tselector: { thinkingLevel?: ThinkingLevel; provider: string; id: string },\n\tmodel: Model<Api>,\n\tsubject: string,\n\twarnings: string[],\n): void {\n\tif (selector.thinkingLevel && !getSupportedThinkingLevels(model).includes(selector.thinkingLevel)) {\n\t\twarnings.push(\n\t\t\t`${subject} uses thinking level \"${selector.thinkingLevel}\", which is unsupported by ${selector.provider}/${selector.id}.`,\n\t\t);\n\t}\n}\n\n/** Returns configuration warnings without changing malformed fallback-chain settings. */\nexport function validateFallbackChains(chains: unknown, registry: FallbackModelRegistry): string[] {\n\tif (!isPlainObject(chains)) return [\"Fallback chains must be a plain object.\"];\n\n\tconst warnings: string[] = [];\n\tconst models = registry.getAll();\n\n\tfor (const [key, entries] of Object.entries(chains)) {\n\t\tconst hasProvider = key.includes(\"/\");\n\t\tconst hasWildcard = key.includes(\"*\");\n\t\tif (!hasProvider) {\n\t\t\twarnings.push(`Fallback chain key \"${key}\" must use a provider/model selector; roles are unsupported.`);\n\t\t}\n\t\tif (hasWildcard) warnings.push(`Fallback chain key \"${key}\" cannot contain wildcards.`);\n\n\t\tconst parsedKey = hasProvider && !hasWildcard ? parseFallbackSelector(key, models) : undefined;\n\t\tconst keyModel = parsedKey ? registry.find(parsedKey.provider, parsedKey.id) : undefined;\n\t\tif (hasProvider && !hasWildcard && (!parsedKey || !keyModel)) {\n\t\t\twarnings.push(invalidSelectorWarning(\"key\", key));\n\t\t}\n\t\tif (parsedKey && keyModel) {\n\t\t\tvalidateThinkingLevel(parsedKey, keyModel, `Fallback chain key \"${key}\"`, warnings);\n\t\t}\n\n\t\tif (!Array.isArray(entries) || entries.some((entry) => typeof entry !== \"string\")) {\n\t\t\twarnings.push(`Fallback chain \"${key}\" entries must be an array of strings.`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (entries.length === 0) {\n\t\t\twarnings.push(`Fallback chain \"${key}\" must contain at least one entry.`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const entry of entries) {\n\t\t\tconst parsedEntry = parseFallbackSelector(entry, models);\n\t\t\tconst entryModel = parsedEntry ? registry.find(parsedEntry.provider, parsedEntry.id) : undefined;\n\t\t\tif (!parsedEntry || !entryModel) {\n\t\t\t\twarnings.push(invalidSelectorWarning(\"entry\", entry, key));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (parsedKey && baseSelector(parsedEntry) === baseSelector(parsedKey)) {\n\t\t\t\twarnings.push(`Fallback chain entry \"${entry}\" for \"${key}\" cannot reference the same model.`);\n\t\t\t}\n\t\t\tvalidateThinkingLevel(parsedEntry, entryModel, `Fallback chain entry \"${entry}\"`, warnings);\n\t\t}\n\t}\n\n\treturn warnings;\n}\n"]}
@@ -1,4 +0,0 @@
1
- import type { AssistantMessage } from "../types.ts";
2
- /** Returns true when an assistant error was classified as a refusal or sensitive stop. */
3
- export declare function isClassifierRefusal(message: AssistantMessage): boolean;
4
- //# sourceMappingURL=stop-details.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stop-details.d.ts","sourceRoot":"","sources":["../../src/utils/stop-details.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,0FAA0F;AAC1F,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAKtE"}
@@ -1,6 +0,0 @@
1
- /** Returns true when an assistant error was classified as a refusal or sensitive stop. */
2
- export function isClassifierRefusal(message) {
3
- return (message.stopReason === "error" &&
4
- (message.stopDetails?.type === "refusal" || message.stopDetails?.type === "sensitive"));
5
- }
6
- //# sourceMappingURL=stop-details.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stop-details.js","sourceRoot":"","sources":["../../src/utils/stop-details.ts"],"names":[],"mappings":"AAEA,0FAA0F;AAC1F,MAAM,UAAU,mBAAmB,CAAC,OAAyB;IAC5D,OAAO,CACN,OAAO,CAAC,UAAU,KAAK,OAAO;QAC9B,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,WAAW,EAAE,IAAI,KAAK,WAAW,CAAC,CACtF,CAAC;AACH,CAAC","sourcesContent":["import type { AssistantMessage } from \"../types.ts\";\n\n/** Returns true when an assistant error was classified as a refusal or sensitive stop. */\nexport function isClassifierRefusal(message: AssistantMessage): boolean {\n\treturn (\n\t\tmessage.stopReason === \"error\" &&\n\t\t(message.stopDetails?.type === \"refusal\" || message.stopDetails?.type === \"sensitive\")\n\t);\n}\n"]}