@ai-agent-forge/agent-forge 0.86.4 → 0.86.6

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 (220) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/bundle/.build-manifest.json +470 -404
  3. package/dist/bundle/chunks/anthropic-messages-ALDZBUKI.js +6 -0
  4. package/dist/bundle/chunks/anthropic.js +2 -2
  5. package/dist/bundle/chunks/{azure-openai-responses-WQCZWFAH.js → azure-openai-responses-A2WJWZFB.js} +1 -1
  6. package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
  7. package/dist/bundle/chunks/chunk-A7GUOX2H.js +141 -0
  8. package/dist/bundle/chunks/{chunk-WGLBM2BP.js → chunk-CIX3FSBK.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-ZV3W36HK.js → chunk-EALJ5DDX.js} +99 -92
  10. package/dist/bundle/chunks/chunk-OO6DJ3CL.js +31 -0
  11. package/dist/bundle/chunks/{chunk-PE3XUHPT.js → chunk-SQFG22WN.js} +1 -1
  12. package/dist/bundle/chunks/{chunk-V46XUTK3.js → chunk-Y7HXTASS.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-3WE3W52L.js → chunk-YJCQVXW5.js} +1 -1
  14. package/dist/bundle/chunks/github-copilot.js +1 -1
  15. package/dist/bundle/chunks/{google-generative-ai-LQ375GYC.js → google-generative-ai-NIB4WONV.js} +1 -1
  16. package/dist/bundle/chunks/{google-vertex-HXSRAKEZ.js → google-vertex-DCPYUEUO.js} +1 -1
  17. package/dist/bundle/chunks/{mistral-conversations-CSNMFR4J.js → mistral-conversations-OC6LA5XL.js} +1 -1
  18. package/dist/bundle/chunks/{openai-codex-responses-YDJSZOIH.js → openai-codex-responses-IO2X4Y7L.js} +1 -1
  19. package/dist/bundle/chunks/openai-codex.js +2 -2
  20. package/dist/bundle/chunks/{openai-completions-UPRWTQPT.js → openai-completions-XYQQHETU.js} +1 -1
  21. package/dist/bundle/chunks/{openai-responses-O63W6HQ3.js → openai-responses-DLIRN3CI.js} +1 -1
  22. package/dist/bundle/chunks/{openrouter-images-G3GT5BVT.js → openrouter-images-G4GQRUSG.js} +1 -1
  23. package/dist/bundle/chunks/openrouter.js +2 -2
  24. package/dist/bundle/chunks/{pi-messages-SLF355GF.js → pi-messages-E6RRYBO7.js} +1 -1
  25. package/dist/bundle/chunks/radius.js +2 -2
  26. package/dist/bundle/chunks/{virtual-modules-O72ICTMQ.js → virtual-modules-3IZ4MYSQ.js} +1 -1
  27. package/dist/bundle/cli.js +1 -1
  28. package/dist/bundle/index.js +1 -1
  29. package/dist/bundle/rpc-entry.js +1 -1
  30. package/dist/capabilities/builtin.d.ts +4 -2
  31. package/dist/capabilities/builtin.d.ts.map +1 -1
  32. package/dist/capabilities/builtin.js +5 -1
  33. package/dist/capabilities/builtin.js.map +1 -1
  34. package/dist/cli/plugin-command.d.ts.map +1 -1
  35. package/dist/cli/plugin-command.js +51 -5
  36. package/dist/cli/plugin-command.js.map +1 -1
  37. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  38. package/dist/core/agent-session-compaction.js +13 -5
  39. package/dist/core/agent-session-compaction.js.map +1 -1
  40. package/dist/core/agent-session-internal.d.ts +2 -4
  41. package/dist/core/agent-session-internal.d.ts.map +1 -1
  42. package/dist/core/agent-session-internal.js.map +1 -1
  43. package/dist/core/agent-session-paths.d.ts +2 -0
  44. package/dist/core/agent-session-paths.d.ts.map +1 -1
  45. package/dist/core/agent-session-paths.js +2 -1
  46. package/dist/core/agent-session-paths.js.map +1 -1
  47. package/dist/core/agent-session-projection.d.ts +10 -4
  48. package/dist/core/agent-session-projection.d.ts.map +1 -1
  49. package/dist/core/agent-session-projection.js +17 -4
  50. package/dist/core/agent-session-projection.js.map +1 -1
  51. package/dist/core/agent-session.d.ts +19 -5
  52. package/dist/core/agent-session.d.ts.map +1 -1
  53. package/dist/core/agent-session.js +30 -4
  54. package/dist/core/agent-session.js.map +1 -1
  55. package/dist/core/extensions/bootstrap-lifecycle.d.ts +1 -1
  56. package/dist/core/extensions/bootstrap-lifecycle.d.ts.map +1 -1
  57. package/dist/core/extensions/bootstrap-lifecycle.js +5 -2
  58. package/dist/core/extensions/bootstrap-lifecycle.js.map +1 -1
  59. package/dist/core/extensions/capability-runtime-store.d.ts.map +1 -1
  60. package/dist/core/extensions/capability-runtime-store.js +1 -0
  61. package/dist/core/extensions/capability-runtime-store.js.map +1 -1
  62. package/dist/core/extensions/capability-runtime-types.d.ts +16 -1
  63. package/dist/core/extensions/capability-runtime-types.d.ts.map +1 -1
  64. package/dist/core/extensions/capability-runtime-types.js.map +1 -1
  65. package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
  66. package/dist/core/extensions/capability-runtime.js +38 -2
  67. package/dist/core/extensions/capability-runtime.js.map +1 -1
  68. package/dist/core/extensions/index.d.ts +1 -1
  69. package/dist/core/extensions/index.d.ts.map +1 -1
  70. package/dist/core/extensions/index.js.map +1 -1
  71. package/dist/core/extensions/lifecycle-catalog.d.ts +46 -0
  72. package/dist/core/extensions/lifecycle-catalog.d.ts.map +1 -1
  73. package/dist/core/extensions/lifecycle-catalog.js +101 -0
  74. package/dist/core/extensions/lifecycle-catalog.js.map +1 -1
  75. package/dist/core/extensions/provider-failover.d.ts +106 -0
  76. package/dist/core/extensions/provider-failover.d.ts.map +1 -0
  77. package/dist/core/extensions/provider-failover.js +692 -0
  78. package/dist/core/extensions/provider-failover.js.map +1 -0
  79. package/dist/core/facade/coding-agent-facade.d.ts +13 -6
  80. package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
  81. package/dist/core/facade/coding-agent-facade.js +3 -1
  82. package/dist/core/facade/coding-agent-facade.js.map +1 -1
  83. package/dist/core/keybindings.d.ts +6 -6
  84. package/dist/core/keybindings.d.ts.map +1 -1
  85. package/dist/core/keybindings.js +23 -6
  86. package/dist/core/keybindings.js.map +1 -1
  87. package/dist/core/model-config.d.ts +102 -0
  88. package/dist/core/model-config.d.ts.map +1 -1
  89. package/dist/core/model-config.js +46 -14
  90. package/dist/core/model-config.js.map +1 -1
  91. package/dist/core/model-resolver.d.ts.map +1 -1
  92. package/dist/core/model-resolver.js +1 -1
  93. package/dist/core/model-resolver.js.map +1 -1
  94. package/dist/core/model-runtime.d.ts +15 -0
  95. package/dist/core/model-runtime.d.ts.map +1 -1
  96. package/dist/core/model-runtime.js +30 -18
  97. package/dist/core/model-runtime.js.map +1 -1
  98. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  99. package/dist/core/remote-catalog-provider.js +4 -9
  100. package/dist/core/remote-catalog-provider.js.map +1 -1
  101. package/dist/core/sdk.d.ts.map +1 -1
  102. package/dist/core/sdk.js +107 -24
  103. package/dist/core/sdk.js.map +1 -1
  104. package/dist/core/session-manager.d.ts +2 -0
  105. package/dist/core/session-manager.d.ts.map +1 -1
  106. package/dist/core/session-manager.js +10 -5
  107. package/dist/core/session-manager.js.map +1 -1
  108. package/dist/core/settings-manager.d.ts +71 -5
  109. package/dist/core/settings-manager.d.ts.map +1 -1
  110. package/dist/core/settings-manager.js +138 -9
  111. package/dist/core/settings-manager.js.map +1 -1
  112. package/dist/core/slash-commands.d.ts.map +1 -1
  113. package/dist/core/slash-commands.js +17 -2
  114. package/dist/core/slash-commands.js.map +1 -1
  115. package/dist/core/tools/render-utils.d.ts +6 -0
  116. package/dist/core/tools/render-utils.d.ts.map +1 -1
  117. package/dist/core/tools/render-utils.js +26 -0
  118. package/dist/core/tools/render-utils.js.map +1 -1
  119. package/dist/core/tools/tool-definition.d.ts +21 -2
  120. package/dist/core/tools/tool-definition.d.ts.map +1 -1
  121. package/dist/core/tools/tool-definition.js.map +1 -1
  122. package/dist/main.d.ts.map +1 -1
  123. package/dist/main.js +3 -6
  124. package/dist/main.js.map +1 -1
  125. package/dist/modes/interactive/components/agents-view.d.ts +57 -0
  126. package/dist/modes/interactive/components/agents-view.d.ts.map +1 -0
  127. package/dist/modes/interactive/components/agents-view.js +260 -0
  128. package/dist/modes/interactive/components/agents-view.js.map +1 -0
  129. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  130. package/dist/modes/interactive/components/custom-editor.js +2 -2
  131. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  132. package/dist/modes/interactive/components/footer.d.ts +7 -0
  133. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  134. package/dist/modes/interactive/components/footer.js +51 -6
  135. package/dist/modes/interactive/components/footer.js.map +1 -1
  136. package/dist/modes/interactive/components/scoped-models-selector.d.ts +1 -1
  137. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  138. package/dist/modes/interactive/components/scoped-models-selector.js +1 -1
  139. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  140. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  141. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  142. package/dist/modes/interactive/components/settings-selector.js +12 -2
  143. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  144. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  145. package/dist/modes/interactive/components/thinking-selector.js +1 -1
  146. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  147. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  148. package/dist/modes/interactive/components/tool-execution.js +89 -10
  149. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  150. package/dist/modes/interactive/components/user-message-selector.d.ts +3 -0
  151. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  152. package/dist/modes/interactive/components/user-message-selector.js +9 -3
  153. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  154. package/dist/modes/interactive/components/workflow-view.d.ts +119 -0
  155. package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -0
  156. package/dist/modes/interactive/components/workflow-view.js +638 -0
  157. package/dist/modes/interactive/components/workflow-view.js.map +1 -0
  158. package/dist/modes/interactive/interactive-commands.d.ts +22 -0
  159. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  160. package/dist/modes/interactive/interactive-commands.js +56 -0
  161. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  162. package/dist/modes/interactive/interactive-mode.d.ts +51 -1
  163. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  164. package/dist/modes/interactive/interactive-mode.js +218 -37
  165. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  166. package/dist/modes/interactive/interactive-selectors.d.ts +2 -4
  167. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
  168. package/dist/modes/interactive/interactive-selectors.js +10 -1
  169. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  170. package/dist/modes/print-mode.d.ts.map +1 -1
  171. package/dist/modes/print-mode.js +5 -0
  172. package/dist/modes/print-mode.js.map +1 -1
  173. package/dist/modes/rpc/rpc-client.d.ts +3 -1
  174. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  175. package/dist/modes/rpc/rpc-client.js +4 -2
  176. package/dist/modes/rpc/rpc-client.js.map +1 -1
  177. package/dist/modes/rpc/rpc-types.d.ts +1 -0
  178. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  179. package/dist/modes/rpc/rpc-types.js.map +1 -1
  180. package/dist/plugins/ecosystem/bootstrap-factory-manifest.d.ts.map +1 -1
  181. package/dist/plugins/ecosystem/bootstrap-factory-manifest.js +7 -0
  182. package/dist/plugins/ecosystem/bootstrap-factory-manifest.js.map +1 -1
  183. package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
  184. package/dist/plugins/ecosystem/cli.js +1 -1
  185. package/dist/plugins/ecosystem/cli.js.map +1 -1
  186. package/dist/plugins/ecosystem/install-store-paths.d.ts +15 -0
  187. package/dist/plugins/ecosystem/install-store-paths.d.ts.map +1 -0
  188. package/dist/plugins/ecosystem/install-store-paths.js +58 -0
  189. package/dist/plugins/ecosystem/install-store-paths.js.map +1 -0
  190. package/dist/plugins/ecosystem/node-disk-registry-source.d.ts.map +1 -1
  191. package/dist/plugins/ecosystem/node-disk-registry-source.js +3 -8
  192. package/dist/plugins/ecosystem/node-disk-registry-source.js.map +1 -1
  193. package/dist/plugins/ecosystem/node-package-install-host.d.ts.map +1 -1
  194. package/dist/plugins/ecosystem/node-package-install-host.js +9 -1
  195. package/dist/plugins/ecosystem/node-package-install-host.js.map +1 -1
  196. package/dist/plugins/ecosystem/node-package-install-persistence.d.ts.map +1 -1
  197. package/dist/plugins/ecosystem/node-package-install-persistence.js +3 -8
  198. package/dist/plugins/ecosystem/node-package-install-persistence.js.map +1 -1
  199. package/dist/profile/plugin-profiles.d.ts +2 -0
  200. package/dist/profile/plugin-profiles.d.ts.map +1 -1
  201. package/dist/profile/plugin-profiles.js +4 -0
  202. package/dist/profile/plugin-profiles.js.map +1 -1
  203. package/dist/profiles/builtin-suites.d.ts +19 -2
  204. package/dist/profiles/builtin-suites.d.ts.map +1 -1
  205. package/dist/profiles/builtin-suites.js +20 -2
  206. package/dist/profiles/builtin-suites.js.map +1 -1
  207. package/dist/profiles/suite-loader.d.ts.map +1 -1
  208. package/dist/profiles/suite-loader.js +4 -1
  209. package/dist/profiles/suite-loader.js.map +1 -1
  210. package/dist/utils/clipboard.d.ts.map +1 -1
  211. package/dist/utils/clipboard.js +10 -10
  212. package/dist/utils/clipboard.js.map +1 -1
  213. package/docs/keybindings.md +8 -8
  214. package/docs/models.md +1 -1
  215. package/docs/rpc.md +3 -1
  216. package/docs/settings.md +2 -1
  217. package/package.json +4 -4
  218. package/dist/bundle/chunks/anthropic-messages-EVFQ6MLR.js +0 -6
  219. package/dist/bundle/chunks/chunk-F6SBZUJG.js +0 -141
  220. package/dist/bundle/chunks/chunk-NUHFSC37.js +0 -25
@@ -7,6 +7,10 @@ import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
7
7
  import { normalizePath, resolvePath } from "../utils/paths.js";
8
8
  import { stripBom } from "../utils/text.js";
9
9
  import { DEFAULT_HTTP_IDLE_TIMEOUT_MS, parseHttpIdleTimeoutMs } from "./http-dispatcher.js";
10
+ const DEFAULT_COMPACTION_TOKEN_SETTINGS = {
11
+ reserveTokens: 16384,
12
+ keepRecentTokens: 20000,
13
+ };
10
14
  function isMergeableObject(value) {
11
15
  return typeof value === "object" && value !== null && !Array.isArray(value);
12
16
  }
@@ -25,9 +29,47 @@ function deepMergeObjects(base, overrides) {
25
29
  }
26
30
  return result;
27
31
  }
32
+ /** Tools enabled at startup when `defaultTools` does not change them. */
33
+ export const DEFAULT_TOOL_NAMES = ["read", "bash", "edit", "write"];
34
+ function isToolModifier(entry) {
35
+ return typeof entry === "string" && (entry.startsWith("+") || entry.startsWith("-"));
36
+ }
37
+ /**
38
+ * Merge `defaultTools` of two settings layers. A list with plain tool names replaces the inherited
39
+ * one; a list of only `+name`/`-name` entries is appended, so it modifies the inherited selection.
40
+ */
41
+ function mergeDefaultTools(base, overrides) {
42
+ if (overrides === undefined)
43
+ return base;
44
+ // Settings files are not validated; a malformed value replaces instead of throwing here.
45
+ if (!Array.isArray(base) || !Array.isArray(overrides) || !overrides.every(isToolModifier))
46
+ return overrides;
47
+ return [...base, ...overrides];
48
+ }
49
+ /**
50
+ * Resolve a merged `defaultTools` list: plain names replace `DEFAULT_TOOL_NAMES`, then `+name` adds
51
+ * and `-name` removes a tool, in list order.
52
+ */
53
+ function resolveDefaultTools(entries) {
54
+ const plain = entries.filter((entry) => !isToolModifier(entry));
55
+ const tools = plain.length > 0 || entries.length === 0 ? plain : [...DEFAULT_TOOL_NAMES];
56
+ for (const entry of entries) {
57
+ if (!isToolModifier(entry))
58
+ continue;
59
+ const name = entry.slice(1);
60
+ const index = tools.indexOf(name);
61
+ if (entry.startsWith("+") && index === -1 && name)
62
+ tools.push(name);
63
+ else if (entry.startsWith("-") && index !== -1)
64
+ tools.splice(index, 1);
65
+ }
66
+ return tools;
67
+ }
28
68
  /** Deep merge settings: project/overrides take precedence, nested objects merge recursively */
29
69
  function deepMergeSettings(base, overrides) {
30
- return deepMergeObjects(base, overrides);
70
+ const merged = deepMergeObjects(base, overrides);
71
+ const defaultTools = mergeDefaultTools(base.defaultTools, overrides.defaultTools);
72
+ return defaultTools === undefined ? merged : { ...merged, defaultTools };
31
73
  }
32
74
  function parseTimeoutSetting(value, settingName) {
33
75
  const timeoutMs = parseHttpIdleTimeoutMs(value);
@@ -136,6 +178,7 @@ export class SettingsManager {
136
178
  modifiedProjectNestedFields = new Map(); // Track project nested field modifications
137
179
  globalSettingsLoadError = null; // Track if global settings file had parse errors
138
180
  projectSettingsLoadError = null; // Track if project settings file had parse errors
181
+ capabilitiesWarningRecorded = false; // One capabilities-structure warning per manager lifetime
139
182
  writeQueue = Promise.resolve();
140
183
  errors;
141
184
  settingsPaths;
@@ -448,6 +491,59 @@ export class SettingsManager {
448
491
  getMemoryModeSetting() {
449
492
  return this.settings.memory?.mode;
450
493
  }
494
+ /**
495
+ * 能力槽位配置节(供应商能力槽位设计 §3.1):返回合并层的原始
496
+ * `capabilities`。结构非法时记录一条 warning(经 drainErrors 以
497
+ * settings 诊断面呈现)并按 fail-closed 丢弃非法子节,不抛出、不崩溃;
498
+ * 槽位失效后由消费方(image-generation 插件)按 config_missing 报
499
+ * 可操作错误。warning 每实例至多记录一次。
500
+ */
501
+ getCapabilitiesSettings() {
502
+ const raw = this.settings.capabilities;
503
+ if (raw === undefined)
504
+ return undefined;
505
+ if (!isMergeableObject(raw)) {
506
+ this.recordCapabilitiesWarning("capabilities must be an object");
507
+ return undefined;
508
+ }
509
+ const imageGeneration = raw.imageGeneration;
510
+ if (imageGeneration === undefined)
511
+ return raw;
512
+ if (!isMergeableObject(imageGeneration)) {
513
+ this.recordCapabilitiesWarning("capabilities.imageGeneration must be an object");
514
+ return undefined;
515
+ }
516
+ const provider = imageGeneration.provider;
517
+ if (typeof provider !== "string" || provider.trim() === "") {
518
+ this.recordCapabilitiesWarning(`capabilities.imageGeneration.provider must be a non-empty string: ${String(provider)}`);
519
+ return undefined;
520
+ }
521
+ const model = imageGeneration.model;
522
+ if (model !== undefined && (typeof model !== "string" || model.trim() === "")) {
523
+ this.recordCapabilitiesWarning(`capabilities.imageGeneration.model must be a non-empty string when present: ${String(model)}`);
524
+ return undefined;
525
+ }
526
+ const slot = { provider, ...(model === undefined ? {} : { model }) };
527
+ return { ...raw, imageGeneration: slot };
528
+ }
529
+ /**
530
+ * 主备切换配置节(设计 §4.1):raw 读出,原样透传合并层对象。Phase 1
531
+ * 不做结构校验与默认值解析——那是 Phase 2 provider-failover 插件的
532
+ * 消费面;此处提前收窄会把非法值静默变成合法语义。
533
+ */
534
+ getFailoverSettings() {
535
+ const failover = this.settings.failover;
536
+ return failover === undefined ? undefined : { ...failover };
537
+ }
538
+ recordCapabilitiesWarning(message) {
539
+ if (this.capabilitiesWarningRecorded)
540
+ return;
541
+ this.capabilitiesWarningRecorded = true;
542
+ // 槽位在两层合并后读取,无法逐字段追溯来源层;capabilities 节存在
543
+ // 于哪层就归到哪层(project 层存在即以 project 呈现,与深合并优先级一致)。
544
+ const scope = isMergeableObject(this.projectSettings.capabilities) ? "project" : "global";
545
+ this.recordError(scope, new Error(`Invalid ${message}`));
546
+ }
451
547
  setDefaultProvider(provider) {
452
548
  this.globalSettings.defaultProvider = provider;
453
549
  this.markModified("defaultProvider");
@@ -547,11 +643,28 @@ export class SettingsManager {
547
643
  this.markModified("compaction", "enabled");
548
644
  this.save();
549
645
  }
550
- getCompactionReserveTokens() {
551
- return this.settings.compaction?.reserveTokens ?? 16384;
646
+ getCompactionTokenSetting(field, model) {
647
+ const compaction = this.settings.compaction;
648
+ const ordinary = compaction?.[field];
649
+ if (ordinary !== undefined && (typeof ordinary !== "number" || !Number.isSafeInteger(ordinary) || ordinary < 0)) {
650
+ throw new Error(`Invalid compaction.${field} setting: ${String(ordinary)}. Expected a non-negative safe integer.`);
651
+ }
652
+ const modelKey = model ? `${model.provider}/${model.id}` : undefined;
653
+ const entry = modelKey !== undefined ? compaction?.modelOverrides?.[modelKey] : undefined;
654
+ if (entry !== undefined && !isMergeableObject(entry)) {
655
+ throw new Error(`Invalid compaction.modelOverrides["${modelKey}"] setting: ${String(entry)}. Expected an object.`);
656
+ }
657
+ const override = entry?.[field];
658
+ if (override !== undefined && (typeof override !== "number" || !Number.isSafeInteger(override) || override < 0)) {
659
+ throw new Error(`Invalid compaction.modelOverrides["${modelKey}"].${field} setting: ${String(override)}. Expected a non-negative safe integer.`);
660
+ }
661
+ return override ?? ordinary ?? DEFAULT_COMPACTION_TOKEN_SETTINGS[field];
662
+ }
663
+ getCompactionReserveTokens(model) {
664
+ return this.getCompactionTokenSetting("reserveTokens", model);
552
665
  }
553
- getCompactionKeepRecentTokens() {
554
- return this.settings.compaction?.keepRecentTokens ?? 20000;
666
+ getCompactionKeepRecentTokens(model) {
667
+ return this.getCompactionTokenSetting("keepRecentTokens", model);
555
668
  }
556
669
  getSummarySelfCritique() {
557
670
  return this.settings.compaction?.summarySelfCritique ?? false;
@@ -559,11 +672,12 @@ export class SettingsManager {
559
672
  getMicrocompactEnabled() {
560
673
  return this.settings.compaction?.microcompactEnabled ?? false;
561
674
  }
562
- getCompactionSettings() {
675
+ /** Resolve each token setting through model override, ordinary setting, then built-in default. */
676
+ getCompactionSettings(model) {
563
677
  return {
564
678
  enabled: this.getCompactionEnabled(),
565
- reserveTokens: this.getCompactionReserveTokens(),
566
- keepRecentTokens: this.getCompactionKeepRecentTokens(),
679
+ reserveTokens: this.getCompactionReserveTokens(model),
680
+ keepRecentTokens: this.getCompactionKeepRecentTokens(model),
567
681
  microcompactEnabled: this.getMicrocompactEnabled(),
568
682
  summarySelfCritique: this.getSummarySelfCritique(),
569
683
  };
@@ -881,6 +995,18 @@ export class SettingsManager {
881
995
  this.markModified("fullscreenCopyOnSelect");
882
996
  this.save();
883
997
  }
998
+ getFullscreenWheelScrollLines() {
999
+ const lines = this.settings.fullscreenWheelScrollLines;
1000
+ return typeof lines === "number" && Number.isFinite(lines)
1001
+ ? Math.max(1, Math.min(100, Math.floor(lines)))
1002
+ : "auto";
1003
+ }
1004
+ setFullscreenWheelScrollLines(lines) {
1005
+ this.globalSettings.fullscreenWheelScrollLines =
1006
+ lines === "auto" ? lines : Math.max(1, Math.min(100, Math.floor(lines)));
1007
+ this.markModified("fullscreenWheelScrollLines");
1008
+ this.save();
1009
+ }
884
1010
  getImageAutoResize() {
885
1011
  return this.settings.images?.autoResize ?? true;
886
1012
  }
@@ -906,9 +1032,12 @@ export class SettingsManager {
906
1032
  getEnabledModels() {
907
1033
  return this.settings.enabledModels;
908
1034
  }
1035
+ /** The resolved `defaultTools` selection, or undefined when no settings layer sets it. */
909
1036
  getDefaultTools() {
910
1037
  const tools = this.settings.defaultTools;
911
- return tools ? [...tools] : undefined;
1038
+ if (tools === undefined)
1039
+ return undefined;
1040
+ return resolveDefaultTools(Array.isArray(tools) ? tools.filter((tool) => typeof tool === "string") : []);
912
1041
  }
913
1042
  setEnabledModels(patterns) {
914
1043
  this.globalSettings.enabledModels = patterns;