@proxysoul/soulforge 2.15.1 → 2.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4544,6 +4544,566 @@ var init_protocol = __esm(() => {
4544
4544
  HEARTH_MAX_FRAME_BYTES = 1024 * 1024;
4545
4545
  });
4546
4546
 
4547
+ // src/core/utils/ensure-soulforge-dir.ts
4548
+ import { execSync as execSync2 } from "child_process";
4549
+ import { appendFileSync as appendFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
4550
+ import { join as join6 } from "path";
4551
+ function ensureSoulforgeDir(cwd) {
4552
+ const dir = join6(cwd, ENTRY);
4553
+ if (!existsSync6(dir))
4554
+ mkdirSync5(dir, { recursive: true });
4555
+ if (!patched.has(cwd)) {
4556
+ patched.add(cwd);
4557
+ try {
4558
+ ensureGitignore(cwd);
4559
+ } catch {}
4560
+ }
4561
+ return dir;
4562
+ }
4563
+ function ensureGitignore(cwd) {
4564
+ const status = gitCheckIgnoreStatus(cwd);
4565
+ if (status !== 1)
4566
+ return;
4567
+ const gitignorePath = join6(cwd, ".gitignore");
4568
+ if (existsSync6(gitignorePath)) {
4569
+ const content = readFileSync6(gitignorePath, "utf-8");
4570
+ const eol = content.includes(`\r
4571
+ `) ? `\r
4572
+ ` : `
4573
+ `;
4574
+ const prefix = content.length > 0 && !content.endsWith(`
4575
+ `) ? eol : "";
4576
+ appendFileSync2(gitignorePath, `${prefix}.soulforge${eol}`);
4577
+ } else {
4578
+ writeFileSync5(gitignorePath, `.soulforge
4579
+ `);
4580
+ }
4581
+ }
4582
+ function gitCheckIgnoreStatus(cwd) {
4583
+ try {
4584
+ execSync2("git check-ignore -q .soulforge", { cwd, stdio: "pipe", timeout: 3000 });
4585
+ return 0;
4586
+ } catch (err2) {
4587
+ return err2.status ?? 128;
4588
+ }
4589
+ }
4590
+ var ENTRY = ".soulforge", patched;
4591
+ var init_ensure_soulforge_dir = __esm(() => {
4592
+ patched = new Set;
4593
+ });
4594
+
4595
+ // src/config/index.ts
4596
+ var exports_config2 = {};
4597
+ __export(exports_config2, {
4598
+ stripConfigKeys: () => stripConfigKeys,
4599
+ saveProjectConfig: () => saveProjectConfig,
4600
+ saveGlobalConfig: () => saveGlobalConfig,
4601
+ saveConfig: () => saveConfig,
4602
+ removeProjectConfigKeys: () => removeProjectConfigKeys,
4603
+ removeGlobalConfigKeys: () => removeGlobalConfigKeys,
4604
+ mergeConfigs: () => mergeConfigs,
4605
+ loadProjectConfig: () => loadProjectConfig,
4606
+ loadConfig: () => loadConfig,
4607
+ applyConfigPatch: () => applyConfigPatch,
4608
+ DEFAULT_CONFIG: () => DEFAULT_CONFIG
4609
+ });
4610
+ import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
4611
+ import { homedir as homedir6 } from "os";
4612
+ import { join as join7 } from "path";
4613
+ function mergeProviders(base, overlay) {
4614
+ if (!base && !overlay)
4615
+ return;
4616
+ if (!overlay)
4617
+ return base;
4618
+ if (!base)
4619
+ return overlay;
4620
+ const map = new Map(base.map((p) => [p.id, p]));
4621
+ for (const p of overlay)
4622
+ map.set(p.id, p);
4623
+ return [...map.values()];
4624
+ }
4625
+ function mergeMCPServers(base, overlay) {
4626
+ if (!base && !overlay)
4627
+ return;
4628
+ if (!overlay)
4629
+ return base;
4630
+ if (!base)
4631
+ return overlay;
4632
+ const map = new Map(base.map((s) => [s.name, s]));
4633
+ for (const s of overlay)
4634
+ map.set(s.name, s);
4635
+ return [...map.values()];
4636
+ }
4637
+ function loadConfig() {
4638
+ if (!existsSync7(CONFIG_DIR)) {
4639
+ mkdirSync6(CONFIG_DIR, { recursive: true, mode: 448 });
4640
+ }
4641
+ if (!existsSync7(CONFIG_FILE)) {
4642
+ writeFileSync6(CONFIG_FILE, JSON.stringify(DEFAULT_CONFIG, null, 2));
4643
+ return DEFAULT_CONFIG;
4644
+ }
4645
+ try {
4646
+ const raw = readFileSync7(CONFIG_FILE, "utf-8");
4647
+ return { ...DEFAULT_CONFIG, ...JSON.parse(raw) };
4648
+ } catch (err2) {
4649
+ logBackgroundError("config", `Failed to parse ${CONFIG_FILE}: ${err2 instanceof Error ? err2.message : String(err2)} \u2014 using defaults`);
4650
+ return DEFAULT_CONFIG;
4651
+ }
4652
+ }
4653
+ function loadProjectConfig(cwd) {
4654
+ const projectFile = join7(cwd, ".soulforge", "config.json");
4655
+ if (!existsSync7(projectFile))
4656
+ return null;
4657
+ try {
4658
+ const raw = readFileSync7(projectFile, "utf-8");
4659
+ return JSON.parse(raw);
4660
+ } catch (err2) {
4661
+ logBackgroundError("config", `Failed to parse ${projectFile}: ${err2 instanceof Error ? err2.message : String(err2)} \u2014 ignoring project config`);
4662
+ return null;
4663
+ }
4664
+ }
4665
+ function mergeConfigs(global2, project) {
4666
+ const layers = [global2];
4667
+ if (project)
4668
+ layers.push(project);
4669
+ let merged = { ...global2 };
4670
+ for (const layer of layers.slice(1)) {
4671
+ const ei = layer.editorIntegration ? { ...merged.editorIntegration, ...layer.editorIntegration } : merged.editorIntegration;
4672
+ const ci = layer.codeIntelligence ? { ...merged.codeIntelligence, ...layer.codeIntelligence } : merged.codeIntelligence;
4673
+ const th = layer.thinking ? { ...merged.thinking, ...layer.thinking } : merged.thinking;
4674
+ const perf = layer.performance ? { ...merged.performance, ...layer.performance } : merged.performance;
4675
+ const cm = layer.contextManagement ? { ...merged.contextManagement, ...layer.contextManagement } : merged.contextManagement;
4676
+ const comp = layer.compaction ? { ...merged.compaction, ...layer.compaction } : merged.compaction;
4677
+ const retry = layer.retry ? { ...merged.retry, ...layer.retry } : merged.retry;
4678
+ const providers = mergeProviders(merged.providers, layer.providers);
4679
+ const mcpServers = mergeMCPServers(merged.mcpServers, layer.mcpServers);
4680
+ merged = {
4681
+ ...merged,
4682
+ ...layer,
4683
+ editor: { ...merged.editor, ...layer.editor },
4684
+ theme: { ...merged.theme, ...layer.theme },
4685
+ editorIntegration: ei,
4686
+ codeIntelligence: ci,
4687
+ thinking: th,
4688
+ performance: perf,
4689
+ contextManagement: cm,
4690
+ compaction: comp,
4691
+ retry,
4692
+ providers,
4693
+ mcpServers
4694
+ };
4695
+ }
4696
+ return merged;
4697
+ }
4698
+ function saveConfig(config) {
4699
+ if (!existsSync7(CONFIG_DIR)) {
4700
+ mkdirSync6(CONFIG_DIR, { recursive: true, mode: 448 });
4701
+ }
4702
+ writeFileSync6(CONFIG_FILE, JSON.stringify(config, null, 2));
4703
+ }
4704
+ function saveProjectConfig(cwd, patch) {
4705
+ const dir = ensureSoulforgeDir(cwd);
4706
+ const file = join7(dir, "config.json");
4707
+ let existing = {};
4708
+ try {
4709
+ existing = JSON.parse(readFileSync7(file, "utf-8"));
4710
+ } catch {}
4711
+ const merged = { ...existing, ...patch };
4712
+ if (patch.thinking)
4713
+ merged.thinking = { ...existing.thinking, ...patch.thinking };
4714
+ if (patch.performance)
4715
+ merged.performance = { ...existing.performance, ...patch.performance };
4716
+ if (patch.contextManagement)
4717
+ merged.contextManagement = { ...existing.contextManagement, ...patch.contextManagement };
4718
+ if (patch.agentFeatures)
4719
+ merged.agentFeatures = { ...existing.agentFeatures, ...patch.agentFeatures };
4720
+ if (patch.retry)
4721
+ merged.retry = { ...existing.retry, ...patch.retry };
4722
+ writeFileSync6(file, JSON.stringify(merged, null, 2));
4723
+ }
4724
+ function saveGlobalConfig(patch) {
4725
+ if (!existsSync7(CONFIG_DIR))
4726
+ mkdirSync6(CONFIG_DIR, { recursive: true, mode: 448 });
4727
+ let existing = DEFAULT_CONFIG;
4728
+ try {
4729
+ existing = { ...DEFAULT_CONFIG, ...JSON.parse(readFileSync7(CONFIG_FILE, "utf-8")) };
4730
+ } catch {}
4731
+ const merged = { ...existing, ...patch };
4732
+ if (patch.thinking)
4733
+ merged.thinking = { ...existing.thinking, ...patch.thinking };
4734
+ if (patch.performance)
4735
+ merged.performance = { ...existing.performance, ...patch.performance };
4736
+ if (patch.contextManagement)
4737
+ merged.contextManagement = { ...existing.contextManagement, ...patch.contextManagement };
4738
+ if (patch.agentFeatures)
4739
+ merged.agentFeatures = { ...existing.agentFeatures, ...patch.agentFeatures };
4740
+ if (patch.retry)
4741
+ merged.retry = { ...existing.retry, ...patch.retry };
4742
+ writeFileSync6(CONFIG_FILE, JSON.stringify(merged, null, 2));
4743
+ }
4744
+ function removeProjectConfigKeys(cwd, keys) {
4745
+ const file = join7(cwd, ".soulforge", "config.json");
4746
+ if (!existsSync7(file))
4747
+ return;
4748
+ try {
4749
+ const existing = JSON.parse(readFileSync7(file, "utf-8"));
4750
+ for (const k of keys)
4751
+ delete existing[k];
4752
+ writeFileSync6(file, JSON.stringify(existing, null, 2));
4753
+ } catch {}
4754
+ }
4755
+ function removeGlobalConfigKeys(keys) {
4756
+ if (!existsSync7(CONFIG_FILE))
4757
+ return;
4758
+ try {
4759
+ const existing = JSON.parse(readFileSync7(CONFIG_FILE, "utf-8"));
4760
+ for (const k of keys)
4761
+ delete existing[k];
4762
+ writeFileSync6(CONFIG_FILE, JSON.stringify(existing, null, 2));
4763
+ } catch {}
4764
+ }
4765
+ function applyConfigPatch(base, patch) {
4766
+ const result = { ...base, ...patch };
4767
+ for (const key of NESTED_KEYS) {
4768
+ const b = base[key];
4769
+ const p = patch[key];
4770
+ if (p && b && typeof b === "object" && typeof p === "object") {
4771
+ result[key] = { ...b, ...p };
4772
+ }
4773
+ }
4774
+ return result;
4775
+ }
4776
+ function stripConfigKeys(config, keys) {
4777
+ const result = { ...config };
4778
+ for (const k of keys)
4779
+ delete result[k];
4780
+ return result;
4781
+ }
4782
+ var CONFIG_DIR, CONFIG_FILE, DEFAULT_CONFIG, NESTED_KEYS;
4783
+ var init_config2 = __esm(() => {
4784
+ init_ensure_soulforge_dir();
4785
+ init_errors();
4786
+ CONFIG_DIR = join7(homedir6(), ".soulforge");
4787
+ CONFIG_FILE = join7(CONFIG_DIR, "config.json");
4788
+ DEFAULT_CONFIG = {
4789
+ defaultModel: "none",
4790
+ routerRules: [],
4791
+ editor: {
4792
+ command: "nvim",
4793
+ args: []
4794
+ },
4795
+ theme: {
4796
+ name: "dark",
4797
+ transparent: true
4798
+ },
4799
+ nvimConfig: "default",
4800
+ editorIntegration: {
4801
+ diagnostics: true,
4802
+ symbols: true,
4803
+ hover: true,
4804
+ references: true,
4805
+ definition: true,
4806
+ codeActions: true,
4807
+ editorContext: true,
4808
+ rename: true,
4809
+ lspStatus: true,
4810
+ format: true,
4811
+ syncEditorOnEdit: false
4812
+ },
4813
+ codeExecution: true,
4814
+ webSearch: true,
4815
+ compaction: {
4816
+ strategy: "v2",
4817
+ triggerThreshold: 0.7,
4818
+ resetThreshold: 0.4,
4819
+ keepRecent: 4,
4820
+ maxToolResults: 30,
4821
+ llmExtraction: true
4822
+ }
4823
+ };
4824
+ NESTED_KEYS = [
4825
+ "editor",
4826
+ "theme",
4827
+ "editorIntegration",
4828
+ "codeIntelligence",
4829
+ "thinking",
4830
+ "performance",
4831
+ "contextManagement",
4832
+ "agentFeatures",
4833
+ "compaction",
4834
+ "retry"
4835
+ ];
4836
+ });
4837
+
4838
+ // src/hearth/provider-commands.ts
4839
+ function showBool(v, fallback = false) {
4840
+ return v ?? fallback ? "on" : "off";
4841
+ }
4842
+ function parseBool(raw) {
4843
+ const v = raw.trim().toLowerCase();
4844
+ if (v === "on" || v === "true" || v === "1" || v === "yes")
4845
+ return true;
4846
+ if (v === "off" || v === "false" || v === "0" || v === "no")
4847
+ return false;
4848
+ return null;
4849
+ }
4850
+ function findSetting(cmdName) {
4851
+ const bare = cmdName.startsWith("/") ? cmdName.slice(1) : cmdName;
4852
+ return SETTINGS.find((s) => s.cmd === bare);
4853
+ }
4854
+ function validateSettingValue(setting, raw) {
4855
+ const v = raw.trim();
4856
+ if (!v)
4857
+ return { ok: false, error: "missing value" };
4858
+ if (setting.type === "toggle") {
4859
+ const b = parseBool(v);
4860
+ if (b === null)
4861
+ return { ok: false, error: `expected on|off, got "${v}"` };
4862
+ return { ok: true, value: b ? "on" : "off" };
4863
+ }
4864
+ if (setting.type === "cycle") {
4865
+ const lower = v.toLowerCase();
4866
+ const match = setting.options?.find((o) => o.toLowerCase() === lower);
4867
+ if (!match) {
4868
+ return {
4869
+ ok: false,
4870
+ error: `expected ${setting.options?.join("|") ?? "(none)"} \u2014 got "${v}"`
4871
+ };
4872
+ }
4873
+ return { ok: true, value: match };
4874
+ }
4875
+ const n = Number.parseInt(v, 10);
4876
+ if (!Number.isFinite(n) || n < 1024) {
4877
+ return { ok: false, error: "expected integer \u2265 1024" };
4878
+ }
4879
+ return { ok: true, value: String(n) };
4880
+ }
4881
+ function renderSettingsOverview(cfg) {
4882
+ const lines = ["\u2501\u2501 Provider settings \u2501\u2501"];
4883
+ for (const s of SETTINGS) {
4884
+ lines.push(`/${s.cmd.padEnd(15)} ${s.read(cfg).padEnd(10)} ${s.label}`);
4885
+ }
4886
+ lines.push("");
4887
+ lines.push("set: /<cmd> <value>");
4888
+ lines.push("show: /<cmd>");
4889
+ return lines.join(`
4890
+ `);
4891
+ }
4892
+ async function handleSettingsCommand(cmdName, args2, notify, opts = {}) {
4893
+ const load = opts.load ?? loadConfig;
4894
+ const save = opts.save ?? saveGlobalConfig;
4895
+ if (cmdName === "/settings") {
4896
+ await notify(renderSettingsOverview(load()));
4897
+ return true;
4898
+ }
4899
+ const setting = findSetting(cmdName);
4900
+ if (!setting)
4901
+ return false;
4902
+ const raw = args2.join(" ").trim();
4903
+ if (!raw) {
4904
+ const current = setting.read(load());
4905
+ const opts2 = setting.options?.join("|") ?? (setting.type === "toggle" ? "on|off" : "<int>");
4906
+ await notify(`/${setting.cmd}: ${current}
4907
+ options: ${opts2}`);
4908
+ return true;
4909
+ }
4910
+ const parsed = validateSettingValue(setting, raw);
4911
+ if (!parsed.ok) {
4912
+ await notify(`\u2717 ${parsed.error}`);
4913
+ return true;
4914
+ }
4915
+ try {
4916
+ save(setting.patch(parsed.value));
4917
+ } catch (err2) {
4918
+ await notify(`\u2717 save failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
4919
+ return true;
4920
+ }
4921
+ await notify(`\u2713 ${setting.cmd} \u2192 ${parsed.value}`);
4922
+ return true;
4923
+ }
4924
+ function settingsHelpLines() {
4925
+ return [
4926
+ "\u2501\u2501 Provider settings \u2501\u2501",
4927
+ "/settings show all current values",
4928
+ "/thinking [mode] off | auto | enabled | adaptive | disabled",
4929
+ "/budget [N] thinking budget tokens (\u22651024)",
4930
+ "/effort [level] off | low | medium | high | xhigh | max",
4931
+ "/speed [mode] off | standard | fast (Opus 4.6)",
4932
+ "/reasoning [level] OpenAI reasoning effort",
4933
+ "/tier [tier] OpenAI service tier (flex|priority|auto\u2026)",
4934
+ "/sendreasoning on|off send reasoning across turns",
4935
+ "/toolstream on|off stream tool args incrementally",
4936
+ "/seqtools on|off sequential tool use",
4937
+ "/codeexec on|off code execution tool",
4938
+ "/websearch on|off web search tool",
4939
+ "/computeruse on|off computer use tool",
4940
+ "/compact on|off server-side context compaction",
4941
+ "/cleartools on|off clear old tool results (server)",
4942
+ "/clearthinking on|off preserve thinking blocks",
4943
+ "/pruning [target] none | main | subagents | both"
4944
+ ];
4945
+ }
4946
+ var THINKING_MODES, EFFORT_LEVELS, SPEEDS, OAI_EFFORTS, SERVICE_TIERS, PRUNING, SETTINGS, SETTINGS_COMMAND_NAMES;
4947
+ var init_provider_commands = __esm(() => {
4948
+ init_config2();
4949
+ THINKING_MODES = ["off", "disabled", "auto", "adaptive", "enabled"];
4950
+ EFFORT_LEVELS = ["off", "low", "medium", "high", "xhigh", "max"];
4951
+ SPEEDS = ["off", "standard", "fast"];
4952
+ OAI_EFFORTS = ["off", "none", "minimal", "low", "medium", "high", "xhigh"];
4953
+ SERVICE_TIERS = ["off", "auto", "default", "flex", "priority"];
4954
+ PRUNING = ["none", "main", "subagents", "both"];
4955
+ SETTINGS = [
4956
+ {
4957
+ cmd: "thinking",
4958
+ label: "thinking mode",
4959
+ type: "cycle",
4960
+ options: THINKING_MODES,
4961
+ read: (c) => c.thinking?.mode ?? "off",
4962
+ patch: (raw) => ({ thinking: { mode: raw } })
4963
+ },
4964
+ {
4965
+ cmd: "budget",
4966
+ label: "thinking budget tokens",
4967
+ type: "budget",
4968
+ read: (c) => String(c.thinking?.budgetTokens ?? 1e4),
4969
+ patch: (raw) => ({
4970
+ thinking: { mode: "enabled", budgetTokens: Number.parseInt(raw, 10) }
4971
+ })
4972
+ },
4973
+ {
4974
+ cmd: "effort",
4975
+ label: "reasoning effort",
4976
+ type: "cycle",
4977
+ options: EFFORT_LEVELS,
4978
+ read: (c) => c.performance?.effort ?? "off",
4979
+ patch: (raw) => ({
4980
+ performance: { effort: raw }
4981
+ })
4982
+ },
4983
+ {
4984
+ cmd: "speed",
4985
+ label: "speed (Opus 4.6)",
4986
+ type: "cycle",
4987
+ options: SPEEDS,
4988
+ read: (c) => c.performance?.speed ?? "off",
4989
+ patch: (raw) => ({
4990
+ performance: { speed: raw }
4991
+ })
4992
+ },
4993
+ {
4994
+ cmd: "reasoning",
4995
+ label: "OpenAI reasoning effort",
4996
+ type: "cycle",
4997
+ options: OAI_EFFORTS,
4998
+ read: (c) => c.performance?.openaiReasoningEffort ?? "off",
4999
+ patch: (raw) => ({
5000
+ performance: { openaiReasoningEffort: raw }
5001
+ })
5002
+ },
5003
+ {
5004
+ cmd: "tier",
5005
+ label: "OpenAI service tier",
5006
+ type: "cycle",
5007
+ options: SERVICE_TIERS,
5008
+ read: (c) => c.performance?.serviceTier ?? "off",
5009
+ patch: (raw) => ({
5010
+ performance: { serviceTier: raw }
5011
+ })
5012
+ },
5013
+ {
5014
+ cmd: "sendreasoning",
5015
+ label: "send reasoning across turns",
5016
+ type: "toggle",
5017
+ read: (c) => showBool(c.performance?.sendReasoning),
5018
+ patch: (raw) => ({
5019
+ performance: { sendReasoning: parseBool(raw) ?? false }
5020
+ })
5021
+ },
5022
+ {
5023
+ cmd: "toolstream",
5024
+ label: "tool arg streaming",
5025
+ type: "toggle",
5026
+ read: (c) => showBool(c.performance?.toolStreaming, true),
5027
+ patch: (raw) => ({
5028
+ performance: { toolStreaming: parseBool(raw) ?? true }
5029
+ })
5030
+ },
5031
+ {
5032
+ cmd: "seqtools",
5033
+ label: "sequential tool use",
5034
+ type: "toggle",
5035
+ read: (c) => showBool(c.performance?.disableParallelToolUse),
5036
+ patch: (raw) => ({
5037
+ performance: { disableParallelToolUse: parseBool(raw) ?? false }
5038
+ })
5039
+ },
5040
+ {
5041
+ cmd: "codeexec",
5042
+ label: "code execution tool",
5043
+ type: "toggle",
5044
+ read: (c) => showBool(c.codeExecution, true),
5045
+ patch: (raw) => ({ codeExecution: parseBool(raw) ?? true })
5046
+ },
5047
+ {
5048
+ cmd: "websearch",
5049
+ label: "web search tool",
5050
+ type: "toggle",
5051
+ read: (c) => showBool(c.webSearch, true),
5052
+ patch: (raw) => ({ webSearch: parseBool(raw) ?? true })
5053
+ },
5054
+ {
5055
+ cmd: "computeruse",
5056
+ label: "computer use tool",
5057
+ type: "toggle",
5058
+ read: (c) => showBool(c.computerUse),
5059
+ patch: (raw) => ({ computerUse: parseBool(raw) ?? false })
5060
+ },
5061
+ {
5062
+ cmd: "compact",
5063
+ label: "server-side compaction",
5064
+ type: "toggle",
5065
+ read: (c) => showBool(c.contextManagement?.compact),
5066
+ patch: (raw) => ({
5067
+ contextManagement: { compact: parseBool(raw) ?? false }
5068
+ })
5069
+ },
5070
+ {
5071
+ cmd: "cleartools",
5072
+ label: "clear old tool results (server)",
5073
+ type: "toggle",
5074
+ read: (c) => showBool(c.contextManagement?.clearToolUses),
5075
+ patch: (raw) => ({
5076
+ contextManagement: { clearToolUses: parseBool(raw) ?? false }
5077
+ })
5078
+ },
5079
+ {
5080
+ cmd: "clearthinking",
5081
+ label: "preserve thinking blocks",
5082
+ type: "toggle",
5083
+ read: (c) => showBool(c.contextManagement?.clearThinking, true),
5084
+ patch: (raw) => ({
5085
+ contextManagement: { clearThinking: parseBool(raw) ?? true }
5086
+ })
5087
+ },
5088
+ {
5089
+ cmd: "pruning",
5090
+ label: "tool-result pruning target",
5091
+ type: "cycle",
5092
+ options: PRUNING,
5093
+ read: (c) => c.contextManagement?.pruningTarget ?? "none",
5094
+ patch: (raw) => ({
5095
+ contextManagement: {
5096
+ pruningTarget: raw
5097
+ }
5098
+ })
5099
+ }
5100
+ ];
5101
+ SETTINGS_COMMAND_NAMES = [
5102
+ ...SETTINGS.map((s) => `/${s.cmd}`),
5103
+ "/settings"
5104
+ ];
5105
+ });
5106
+
4547
5107
  // src/hearth/redact.ts
4548
5108
  var exports_redact = {};
4549
5109
  __export(exports_redact, {
@@ -5678,9 +6238,9 @@ data: ${payload}
5678
6238
  });
5679
6239
 
5680
6240
  // src/hearth/adapters/telegram.ts
5681
- import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
5682
- import { homedir as homedir6 } from "os";
5683
- import { dirname as dirname3, join as join6 } from "path";
6241
+ import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
6242
+ import { homedir as homedir7 } from "os";
6243
+ import { dirname as dirname3, join as join8 } from "path";
5684
6244
  function sleep2(ms) {
5685
6245
  return new Promise((resolve2) => setTimeout(resolve2, ms));
5686
6246
  }
@@ -5801,14 +6361,14 @@ var init_telegram = __esm(() => {
5801
6361
  this.loadCallbackState();
5802
6362
  }
5803
6363
  callbackStatePath() {
5804
- return join6(homedir6(), ".soulforge", `hearth-callbacks-${this.botId}.json`);
6364
+ return join8(homedir7(), ".soulforge", `hearth-callbacks-${this.botId}.json`);
5805
6365
  }
5806
6366
  loadCallbackState() {
5807
6367
  const path = this.callbackStatePath();
5808
- if (!existsSync6(path))
6368
+ if (!existsSync8(path))
5809
6369
  return;
5810
6370
  try {
5811
- const raw = readFileSync6(path, "utf-8");
6371
+ const raw = readFileSync8(path, "utf-8");
5812
6372
  const parsed = JSON.parse(raw);
5813
6373
  for (const [chatId, entry] of Object.entries(parsed)) {
5814
6374
  this.lastCallbackByChat.set(chatId, entry);
@@ -5818,11 +6378,11 @@ var init_telegram = __esm(() => {
5818
6378
  persistCallbackState() {
5819
6379
  try {
5820
6380
  const path = this.callbackStatePath();
5821
- mkdirSync5(dirname3(path), { recursive: true, mode: 448 });
6381
+ mkdirSync7(dirname3(path), { recursive: true, mode: 448 });
5822
6382
  const obj = {};
5823
6383
  for (const [k, v] of this.lastCallbackByChat)
5824
6384
  obj[k] = v;
5825
- writeFileSync5(path, JSON.stringify(obj), { mode: 384 });
6385
+ writeFileSync7(path, JSON.stringify(obj), { mode: 384 });
5826
6386
  } catch {}
5827
6387
  }
5828
6388
  getRendererFor(externalId) {
@@ -6525,297 +7085,6 @@ var init_surface_host = __esm(() => {
6525
7085
  init_surface_factory();
6526
7086
  });
6527
7087
 
6528
- // src/core/utils/ensure-soulforge-dir.ts
6529
- import { execSync as execSync2 } from "child_process";
6530
- import { appendFileSync as appendFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
6531
- import { join as join7 } from "path";
6532
- function ensureSoulforgeDir(cwd) {
6533
- const dir = join7(cwd, ENTRY);
6534
- if (!existsSync7(dir))
6535
- mkdirSync6(dir, { recursive: true });
6536
- if (!patched.has(cwd)) {
6537
- patched.add(cwd);
6538
- try {
6539
- ensureGitignore(cwd);
6540
- } catch {}
6541
- }
6542
- return dir;
6543
- }
6544
- function ensureGitignore(cwd) {
6545
- const status = gitCheckIgnoreStatus(cwd);
6546
- if (status !== 1)
6547
- return;
6548
- const gitignorePath = join7(cwd, ".gitignore");
6549
- if (existsSync7(gitignorePath)) {
6550
- const content = readFileSync7(gitignorePath, "utf-8");
6551
- const eol = content.includes(`\r
6552
- `) ? `\r
6553
- ` : `
6554
- `;
6555
- const prefix = content.length > 0 && !content.endsWith(`
6556
- `) ? eol : "";
6557
- appendFileSync2(gitignorePath, `${prefix}.soulforge${eol}`);
6558
- } else {
6559
- writeFileSync6(gitignorePath, `.soulforge
6560
- `);
6561
- }
6562
- }
6563
- function gitCheckIgnoreStatus(cwd) {
6564
- try {
6565
- execSync2("git check-ignore -q .soulforge", { cwd, stdio: "pipe", timeout: 3000 });
6566
- return 0;
6567
- } catch (err2) {
6568
- return err2.status ?? 128;
6569
- }
6570
- }
6571
- var ENTRY = ".soulforge", patched;
6572
- var init_ensure_soulforge_dir = __esm(() => {
6573
- patched = new Set;
6574
- });
6575
-
6576
- // src/config/index.ts
6577
- var exports_config2 = {};
6578
- __export(exports_config2, {
6579
- stripConfigKeys: () => stripConfigKeys,
6580
- saveProjectConfig: () => saveProjectConfig,
6581
- saveGlobalConfig: () => saveGlobalConfig,
6582
- saveConfig: () => saveConfig,
6583
- removeProjectConfigKeys: () => removeProjectConfigKeys,
6584
- removeGlobalConfigKeys: () => removeGlobalConfigKeys,
6585
- mergeConfigs: () => mergeConfigs,
6586
- loadProjectConfig: () => loadProjectConfig,
6587
- loadConfig: () => loadConfig,
6588
- applyConfigPatch: () => applyConfigPatch,
6589
- DEFAULT_CONFIG: () => DEFAULT_CONFIG
6590
- });
6591
- import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
6592
- import { homedir as homedir7 } from "os";
6593
- import { join as join8 } from "path";
6594
- function mergeProviders(base, overlay) {
6595
- if (!base && !overlay)
6596
- return;
6597
- if (!overlay)
6598
- return base;
6599
- if (!base)
6600
- return overlay;
6601
- const map = new Map(base.map((p) => [p.id, p]));
6602
- for (const p of overlay)
6603
- map.set(p.id, p);
6604
- return [...map.values()];
6605
- }
6606
- function mergeMCPServers(base, overlay) {
6607
- if (!base && !overlay)
6608
- return;
6609
- if (!overlay)
6610
- return base;
6611
- if (!base)
6612
- return overlay;
6613
- const map = new Map(base.map((s) => [s.name, s]));
6614
- for (const s of overlay)
6615
- map.set(s.name, s);
6616
- return [...map.values()];
6617
- }
6618
- function loadConfig() {
6619
- if (!existsSync8(CONFIG_DIR)) {
6620
- mkdirSync7(CONFIG_DIR, { recursive: true, mode: 448 });
6621
- }
6622
- if (!existsSync8(CONFIG_FILE)) {
6623
- writeFileSync7(CONFIG_FILE, JSON.stringify(DEFAULT_CONFIG, null, 2));
6624
- return DEFAULT_CONFIG;
6625
- }
6626
- try {
6627
- const raw = readFileSync8(CONFIG_FILE, "utf-8");
6628
- return { ...DEFAULT_CONFIG, ...JSON.parse(raw) };
6629
- } catch (err2) {
6630
- logBackgroundError("config", `Failed to parse ${CONFIG_FILE}: ${err2 instanceof Error ? err2.message : String(err2)} \u2014 using defaults`);
6631
- return DEFAULT_CONFIG;
6632
- }
6633
- }
6634
- function loadProjectConfig(cwd) {
6635
- const projectFile = join8(cwd, ".soulforge", "config.json");
6636
- if (!existsSync8(projectFile))
6637
- return null;
6638
- try {
6639
- const raw = readFileSync8(projectFile, "utf-8");
6640
- return JSON.parse(raw);
6641
- } catch (err2) {
6642
- logBackgroundError("config", `Failed to parse ${projectFile}: ${err2 instanceof Error ? err2.message : String(err2)} \u2014 ignoring project config`);
6643
- return null;
6644
- }
6645
- }
6646
- function mergeConfigs(global2, project) {
6647
- const layers = [global2];
6648
- if (project)
6649
- layers.push(project);
6650
- let merged = { ...global2 };
6651
- for (const layer of layers.slice(1)) {
6652
- const ei = layer.editorIntegration ? { ...merged.editorIntegration, ...layer.editorIntegration } : merged.editorIntegration;
6653
- const ci = layer.codeIntelligence ? { ...merged.codeIntelligence, ...layer.codeIntelligence } : merged.codeIntelligence;
6654
- const th = layer.thinking ? { ...merged.thinking, ...layer.thinking } : merged.thinking;
6655
- const perf = layer.performance ? { ...merged.performance, ...layer.performance } : merged.performance;
6656
- const cm = layer.contextManagement ? { ...merged.contextManagement, ...layer.contextManagement } : merged.contextManagement;
6657
- const comp = layer.compaction ? { ...merged.compaction, ...layer.compaction } : merged.compaction;
6658
- const retry = layer.retry ? { ...merged.retry, ...layer.retry } : merged.retry;
6659
- const providers = mergeProviders(merged.providers, layer.providers);
6660
- const mcpServers = mergeMCPServers(merged.mcpServers, layer.mcpServers);
6661
- merged = {
6662
- ...merged,
6663
- ...layer,
6664
- editor: { ...merged.editor, ...layer.editor },
6665
- theme: { ...merged.theme, ...layer.theme },
6666
- editorIntegration: ei,
6667
- codeIntelligence: ci,
6668
- thinking: th,
6669
- performance: perf,
6670
- contextManagement: cm,
6671
- compaction: comp,
6672
- retry,
6673
- providers,
6674
- mcpServers
6675
- };
6676
- }
6677
- return merged;
6678
- }
6679
- function saveConfig(config) {
6680
- if (!existsSync8(CONFIG_DIR)) {
6681
- mkdirSync7(CONFIG_DIR, { recursive: true, mode: 448 });
6682
- }
6683
- writeFileSync7(CONFIG_FILE, JSON.stringify(config, null, 2));
6684
- }
6685
- function saveProjectConfig(cwd, patch) {
6686
- const dir = ensureSoulforgeDir(cwd);
6687
- const file = join8(dir, "config.json");
6688
- let existing = {};
6689
- try {
6690
- existing = JSON.parse(readFileSync8(file, "utf-8"));
6691
- } catch {}
6692
- const merged = { ...existing, ...patch };
6693
- if (patch.thinking)
6694
- merged.thinking = { ...existing.thinking, ...patch.thinking };
6695
- if (patch.performance)
6696
- merged.performance = { ...existing.performance, ...patch.performance };
6697
- if (patch.contextManagement)
6698
- merged.contextManagement = { ...existing.contextManagement, ...patch.contextManagement };
6699
- if (patch.agentFeatures)
6700
- merged.agentFeatures = { ...existing.agentFeatures, ...patch.agentFeatures };
6701
- if (patch.retry)
6702
- merged.retry = { ...existing.retry, ...patch.retry };
6703
- writeFileSync7(file, JSON.stringify(merged, null, 2));
6704
- }
6705
- function saveGlobalConfig(patch) {
6706
- if (!existsSync8(CONFIG_DIR))
6707
- mkdirSync7(CONFIG_DIR, { recursive: true, mode: 448 });
6708
- let existing = DEFAULT_CONFIG;
6709
- try {
6710
- existing = { ...DEFAULT_CONFIG, ...JSON.parse(readFileSync8(CONFIG_FILE, "utf-8")) };
6711
- } catch {}
6712
- const merged = { ...existing, ...patch };
6713
- if (patch.thinking)
6714
- merged.thinking = { ...existing.thinking, ...patch.thinking };
6715
- if (patch.performance)
6716
- merged.performance = { ...existing.performance, ...patch.performance };
6717
- if (patch.contextManagement)
6718
- merged.contextManagement = { ...existing.contextManagement, ...patch.contextManagement };
6719
- if (patch.agentFeatures)
6720
- merged.agentFeatures = { ...existing.agentFeatures, ...patch.agentFeatures };
6721
- if (patch.retry)
6722
- merged.retry = { ...existing.retry, ...patch.retry };
6723
- writeFileSync7(CONFIG_FILE, JSON.stringify(merged, null, 2));
6724
- }
6725
- function removeProjectConfigKeys(cwd, keys) {
6726
- const file = join8(cwd, ".soulforge", "config.json");
6727
- if (!existsSync8(file))
6728
- return;
6729
- try {
6730
- const existing = JSON.parse(readFileSync8(file, "utf-8"));
6731
- for (const k of keys)
6732
- delete existing[k];
6733
- writeFileSync7(file, JSON.stringify(existing, null, 2));
6734
- } catch {}
6735
- }
6736
- function removeGlobalConfigKeys(keys) {
6737
- if (!existsSync8(CONFIG_FILE))
6738
- return;
6739
- try {
6740
- const existing = JSON.parse(readFileSync8(CONFIG_FILE, "utf-8"));
6741
- for (const k of keys)
6742
- delete existing[k];
6743
- writeFileSync7(CONFIG_FILE, JSON.stringify(existing, null, 2));
6744
- } catch {}
6745
- }
6746
- function applyConfigPatch(base, patch) {
6747
- const result = { ...base, ...patch };
6748
- for (const key of NESTED_KEYS) {
6749
- const b = base[key];
6750
- const p = patch[key];
6751
- if (p && b && typeof b === "object" && typeof p === "object") {
6752
- result[key] = { ...b, ...p };
6753
- }
6754
- }
6755
- return result;
6756
- }
6757
- function stripConfigKeys(config, keys) {
6758
- const result = { ...config };
6759
- for (const k of keys)
6760
- delete result[k];
6761
- return result;
6762
- }
6763
- var CONFIG_DIR, CONFIG_FILE, DEFAULT_CONFIG, NESTED_KEYS;
6764
- var init_config2 = __esm(() => {
6765
- init_ensure_soulforge_dir();
6766
- init_errors();
6767
- CONFIG_DIR = join8(homedir7(), ".soulforge");
6768
- CONFIG_FILE = join8(CONFIG_DIR, "config.json");
6769
- DEFAULT_CONFIG = {
6770
- defaultModel: "none",
6771
- routerRules: [],
6772
- editor: {
6773
- command: "nvim",
6774
- args: []
6775
- },
6776
- theme: {
6777
- name: "dark",
6778
- transparent: true
6779
- },
6780
- nvimConfig: "default",
6781
- editorIntegration: {
6782
- diagnostics: true,
6783
- symbols: true,
6784
- hover: true,
6785
- references: true,
6786
- definition: true,
6787
- codeActions: true,
6788
- editorContext: true,
6789
- rename: true,
6790
- lspStatus: true,
6791
- format: true,
6792
- syncEditorOnEdit: false
6793
- },
6794
- codeExecution: true,
6795
- webSearch: true,
6796
- compaction: {
6797
- strategy: "v2",
6798
- triggerThreshold: 0.7,
6799
- resetThreshold: 0.4,
6800
- keepRecent: 4,
6801
- maxToolResults: 30,
6802
- llmExtraction: true
6803
- }
6804
- };
6805
- NESTED_KEYS = [
6806
- "editor",
6807
- "theme",
6808
- "editorIntegration",
6809
- "codeIntelligence",
6810
- "thinking",
6811
- "performance",
6812
- "contextManagement",
6813
- "agentFeatures",
6814
- "compaction",
6815
- "retry"
6816
- ];
6817
- });
6818
-
6819
7088
  // src/stores/workers.ts
6820
7089
  var exports_workers = {};
6821
7090
  __export(exports_workers, {
@@ -62231,7 +62500,7 @@ var package_default;
62231
62500
  var init_package = __esm(() => {
62232
62501
  package_default = {
62233
62502
  name: "@proxysoul/soulforge",
62234
- version: "2.15.1",
62503
+ version: "2.15.2",
62235
62504
  description: "Graph-powered code intelligence \u2014 multi-agent coding with codebase-aware AI",
62236
62505
  repository: {
62237
62506
  type: "git",
@@ -62680,6 +62949,74 @@ var init_version = __esm(() => {
62680
62949
  CURRENT_VERSION = _currentVersion;
62681
62950
  });
62682
62951
 
62952
+ // src/core/llm/compat-reasoning.ts
62953
+ function parseProvider(modelId) {
62954
+ const slash = modelId.indexOf("/");
62955
+ if (slash === -1)
62956
+ return { provider: "", model: modelId };
62957
+ return { provider: modelId.slice(0, slash), model: modelId.slice(slash + 1) };
62958
+ }
62959
+ function baseModel(modelId) {
62960
+ const slash = modelId.lastIndexOf("/");
62961
+ return (slash >= 0 ? modelId.slice(slash + 1) : modelId).toLowerCase();
62962
+ }
62963
+ function getCompatReasoningBody(modelId, config2) {
62964
+ const { provider } = parseProvider(modelId);
62965
+ if (!COMPAT_PROVIDERS.has(provider))
62966
+ return {};
62967
+ const base = baseModel(modelId);
62968
+ let effort = config2.performance?.compatReasoningEffort;
62969
+ if (provider === "groq") {
62970
+ const g = config2.performance?.groqReasoningEffort;
62971
+ if (g)
62972
+ effort = g === "off" ? "off" : g;
62973
+ }
62974
+ if (!effort || effort === "off") {
62975
+ const e = config2.performance?.effort;
62976
+ if (e && e !== "off") {
62977
+ effort = e === "max" ? "xhigh" : e;
62978
+ }
62979
+ }
62980
+ if (!effort || effort === "off")
62981
+ return {};
62982
+ const isClaude = base.startsWith("claude");
62983
+ if (isClaude && provider === "opencode-zen") {
62984
+ const explicitBudget = config2.thinking?.budgetTokens;
62985
+ const budget = explicitBudget ?? { low: 2048, medium: 5000, high: 1e4, xhigh: 20000 }[effort] ?? 5000;
62986
+ return { thinking: { type: "enabled", budget_tokens: budget } };
62987
+ }
62988
+ if (isClaude && provider !== "proxy") {
62989
+ return {};
62990
+ }
62991
+ if (provider === "groq" && /qwen3/.test(base)) {
62992
+ return { reasoning_effort: "default" };
62993
+ }
62994
+ const isDashscope = /qwen|glm-|kimi-/.test(base);
62995
+ const body2 = {
62996
+ reasoning_effort: effort,
62997
+ reasoning: { effort }
62998
+ };
62999
+ if (isDashscope)
63000
+ body2.enable_thinking = true;
63001
+ return body2;
63002
+ }
63003
+ var COMPAT_PROVIDERS;
63004
+ var init_compat_reasoning = __esm(() => {
63005
+ COMPAT_PROVIDERS = new Set([
63006
+ "deepseek",
63007
+ "groq",
63008
+ "fireworks",
63009
+ "minimax",
63010
+ "copilot",
63011
+ "github-models",
63012
+ "opencode-go",
63013
+ "opencode-zen",
63014
+ "lmstudio",
63015
+ "ollama",
63016
+ "proxy"
63017
+ ]);
63018
+ });
63019
+
62683
63020
  // src/core/llm/providers/copilot.ts
62684
63021
  async function exchangeToken(githubToken) {
62685
63022
  if (cachedBearer && Date.now() / 1000 < cachedBearer.expiresAt - 60) {
@@ -62736,7 +63073,8 @@ function detectInitiator(body2) {
62736
63073
  } catch {}
62737
63074
  return "user";
62738
63075
  }
62739
- function createCopilotFetch(githubToken) {
63076
+ function createCopilotFetch(githubToken, reasoningBody) {
63077
+ const injectReasoning = Object.keys(reasoningBody).length > 0;
62740
63078
  return async (url2, init2) => {
62741
63079
  let bearer;
62742
63080
  try {
@@ -62745,18 +63083,25 @@ function createCopilotFetch(githubToken) {
62745
63083
  invalidateBearer();
62746
63084
  bearer = await exchangeToken(githubToken);
62747
63085
  }
63086
+ let patchedBody = init2?.body;
63087
+ if (injectReasoning && typeof init2?.body === "string") {
63088
+ try {
63089
+ const parsed = JSON.parse(init2.body);
63090
+ patchedBody = JSON.stringify({ ...parsed, ...reasoningBody });
63091
+ } catch {}
63092
+ }
62748
63093
  const buildHeaders = (token) => {
62749
63094
  const h = new Headers(init2?.headers);
62750
63095
  h.set("Authorization", `Bearer ${token}`);
62751
63096
  h.set("X-Request-Id", crypto.randomUUID());
62752
- h.set("X-Initiator", detectInitiator(init2?.body));
63097
+ h.set("X-Initiator", detectInitiator(patchedBody));
62753
63098
  return h;
62754
63099
  };
62755
- const res = await fetch(url2, { ...init2, headers: buildHeaders(bearer) });
63100
+ const res = await fetch(url2, { ...init2, body: patchedBody, headers: buildHeaders(bearer) });
62756
63101
  if (res.status === 401) {
62757
63102
  invalidateBearer();
62758
63103
  const retryBearer = await exchangeToken(githubToken);
62759
- return fetch(url2, { ...init2, headers: buildHeaders(retryBearer) });
63104
+ return fetch(url2, { ...init2, body: patchedBody, headers: buildHeaders(retryBearer) });
62760
63105
  }
62761
63106
  return res;
62762
63107
  };
@@ -62773,7 +63118,8 @@ function assertChatCompletionsSupported(modelId) {
62773
63118
  function createCopilotModel(modelId) {
62774
63119
  assertChatCompletionsSupported(modelId);
62775
63120
  const githubToken = getGitHubToken();
62776
- const copilotFetch = createCopilotFetch(githubToken);
63121
+ const reasoningBody = getCompatReasoningBody(`copilot/${modelId}`, loadConfig());
63122
+ const copilotFetch = createCopilotFetch(githubToken, reasoningBody);
62777
63123
  const client = createOpenAI({
62778
63124
  baseURL: COPILOT_API,
62779
63125
  apiKey: "copilot",
@@ -62785,8 +63131,10 @@ function createCopilotModel(modelId) {
62785
63131
  var ENV_VAR = "COPILOT_API_KEY", COPILOT_API = "https://api.githubcopilot.com", TOKEN_EXCHANGE = "https://api.github.com/copilot_internal/v2/token", COPILOT_CHAT_VERSION = "0.26.7", COPILOT_API_VERSION = "2025-04-01", COPILOT_HEADERS, cachedBearer = null, bearerInflight = null, supportedEndpoints, copilot;
62786
63132
  var init_copilot = __esm(() => {
62787
63133
  init_dist8();
63134
+ init_config2();
62788
63135
  init_secrets();
62789
63136
  init_version();
63137
+ init_compat_reasoning();
62790
63138
  COPILOT_HEADERS = {
62791
63139
  "Editor-Version": "vscode/1.95.0",
62792
63140
  "Editor-Plugin-Version": `copilot-chat/${COPILOT_CHAT_VERSION}`,
@@ -64417,27 +64765,21 @@ var init_dist9 = __esm(() => {
64417
64765
  });
64418
64766
  });
64419
64767
 
64420
- // src/core/llm/providers/custom.ts
64421
- function normalizeModels(models) {
64422
- if (!models || models.length === 0)
64423
- return [];
64424
- return models.map((m) => typeof m === "string" ? { id: m, name: m } : m);
64425
- }
64426
- function buildReasoningBody(reasoning) {
64427
- if (!reasoning)
64428
- return {};
64768
+ // src/core/llm/providers/reasoning-fetch.ts
64769
+ function buildOpenAICompatReasoningBody(effort, extras) {
64429
64770
  const body2 = {};
64430
- if (reasoning.effort) {
64431
- body2.reasoning = { effort: reasoning.effort };
64771
+ if (effort && effort !== "off") {
64772
+ body2.reasoning_effort = effort;
64773
+ body2.reasoning = { effort };
64432
64774
  }
64433
- if (reasoning.enabled !== undefined) {
64434
- body2.enable_thinking = reasoning.enabled;
64775
+ if (extras?.enabled !== undefined) {
64776
+ body2.enable_thinking = extras.enabled;
64435
64777
  }
64436
- if (reasoning.budget !== undefined) {
64437
- body2.thinking_budget = reasoning.budget;
64778
+ if (extras?.budget !== undefined) {
64779
+ body2.thinking_budget = extras.budget;
64438
64780
  }
64439
- if (reasoning.extraParams) {
64440
- Object.assign(body2, reasoning.extraParams);
64781
+ if (extras?.extraParams) {
64782
+ Object.assign(body2, extras.extraParams);
64441
64783
  }
64442
64784
  return body2;
64443
64785
  }
@@ -64460,6 +64802,22 @@ function createReasoningFetchWrapper(reasoningBody) {
64460
64802
  return fetch(input, patchedInit);
64461
64803
  };
64462
64804
  }
64805
+
64806
+ // src/core/llm/providers/custom.ts
64807
+ function normalizeModels(models) {
64808
+ if (!models || models.length === 0)
64809
+ return [];
64810
+ return models.map((m) => typeof m === "string" ? { id: m, name: m } : m);
64811
+ }
64812
+ function buildReasoningBody(reasoning) {
64813
+ if (!reasoning)
64814
+ return {};
64815
+ return buildOpenAICompatReasoningBody(reasoning.effort, {
64816
+ enabled: reasoning.enabled,
64817
+ budget: reasoning.budget,
64818
+ extraParams: reasoning.extraParams
64819
+ });
64820
+ }
64463
64821
  function buildCustomProvider(config2) {
64464
64822
  const envVar = config2.envVar ?? "";
64465
64823
  const reasoningBody = buildReasoningBody(config2.reasoning);
@@ -64523,7 +64881,9 @@ var init_custom = __esm(() => {
64523
64881
  var deepseek;
64524
64882
  var init_deepseek = __esm(() => {
64525
64883
  init_dist9();
64884
+ init_config2();
64526
64885
  init_secrets();
64886
+ init_compat_reasoning();
64527
64887
  deepseek = {
64528
64888
  id: "deepseek",
64529
64889
  name: "DeepSeek",
@@ -64538,10 +64898,13 @@ var init_deepseek = __esm(() => {
64538
64898
  if (!apiKey) {
64539
64899
  throw new Error("DEEPSEEK_API_KEY is not set");
64540
64900
  }
64901
+ const reasoningBody = getCompatReasoningBody(`deepseek/${modelId}`, loadConfig());
64902
+ const reasoningFetch = createReasoningFetchWrapper(reasoningBody);
64541
64903
  const provider = createOpenAICompatible({
64542
64904
  name: "deepseek",
64543
64905
  baseURL: "https://api.deepseek.com/v1",
64544
- apiKey
64906
+ apiKey,
64907
+ ...reasoningFetch ? { fetch: reasoningFetch } : {}
64545
64908
  });
64546
64909
  return provider.chatModel(modelId);
64547
64910
  },
@@ -64892,7 +65255,9 @@ var init_dist10 = __esm(() => {
64892
65255
  var fireworks2;
64893
65256
  var init_fireworks = __esm(() => {
64894
65257
  init_dist10();
65258
+ init_config2();
64895
65259
  init_secrets();
65260
+ init_compat_reasoning();
64896
65261
  fireworks2 = {
64897
65262
  id: "fireworks",
64898
65263
  name: "Fireworks",
@@ -64907,7 +65272,12 @@ var init_fireworks = __esm(() => {
64907
65272
  if (!apiKey) {
64908
65273
  throw new Error("FIREWORKS_API_KEY is not set");
64909
65274
  }
64910
- return createFireworks({ apiKey })(modelId);
65275
+ const reasoningBody = getCompatReasoningBody(`fireworks/${modelId}`, loadConfig());
65276
+ const reasoningFetch = createReasoningFetchWrapper(reasoningBody);
65277
+ return createFireworks({
65278
+ apiKey,
65279
+ ...reasoningFetch ? { fetch: reasoningFetch } : {}
65280
+ })(modelId);
64911
65281
  },
64912
65282
  async fetchModels() {
64913
65283
  const apiKey = getProviderApiKey("FIREWORKS_API_KEY");
@@ -64947,7 +65317,9 @@ var init_fireworks = __esm(() => {
64947
65317
  var ENV_VAR2 = "GITHUB_MODELS_API_KEY", BASE_URL = "https://models.github.ai/inference", CATALOG_URL = "https://models.github.ai/catalog/models", GH_HEADERS, githubModels;
64948
65318
  var init_github_models = __esm(() => {
64949
65319
  init_dist8();
65320
+ init_config2();
64950
65321
  init_secrets();
65322
+ init_compat_reasoning();
64951
65323
  GH_HEADERS = {
64952
65324
  "X-GitHub-Api-Version": "2026-03-10",
64953
65325
  Accept: "application/vnd.github+json"
@@ -64966,7 +65338,14 @@ var init_github_models = __esm(() => {
64966
65338
  if (!apiKey) {
64967
65339
  throw new Error(`${ENV_VAR2} is not set. Create a fine-grained PAT with models:read at github.com/settings/tokens`);
64968
65340
  }
64969
- return createOpenAI({ baseURL: BASE_URL, apiKey, headers: GH_HEADERS }).chat(modelId);
65341
+ const reasoningBody = getCompatReasoningBody(`github-models/${modelId}`, loadConfig());
65342
+ const reasoningFetch = createReasoningFetchWrapper(reasoningBody);
65343
+ return createOpenAI({
65344
+ baseURL: BASE_URL,
65345
+ apiKey,
65346
+ headers: GH_HEADERS,
65347
+ ...reasoningFetch ? { fetch: reasoningFetch } : {}
65348
+ }).chat(modelId);
64970
65349
  },
64971
65350
  async fetchModels() {
64972
65351
  const apiKey = getProviderApiKey(ENV_VAR2);
@@ -68637,7 +69016,9 @@ var init_dist12 = __esm(() => {
68637
69016
  var groq2;
68638
69017
  var init_groq = __esm(() => {
68639
69018
  init_dist12();
69019
+ init_config2();
68640
69020
  init_secrets();
69021
+ init_compat_reasoning();
68641
69022
  groq2 = {
68642
69023
  id: "groq",
68643
69024
  name: "Groq",
@@ -68652,7 +69033,12 @@ var init_groq = __esm(() => {
68652
69033
  if (!apiKey) {
68653
69034
  throw new Error("GROQ_API_KEY is not set");
68654
69035
  }
68655
- return createGroq({ apiKey })(modelId);
69036
+ const reasoningBody = getCompatReasoningBody(`groq/${modelId}`, loadConfig());
69037
+ const reasoningFetch = createReasoningFetchWrapper(reasoningBody);
69038
+ return createGroq({
69039
+ apiKey,
69040
+ ...reasoningFetch ? { fetch: reasoningFetch } : {}
69041
+ })(modelId);
68656
69042
  },
68657
69043
  async fetchModels() {
68658
69044
  const apiKey = getProviderApiKey("GROQ_API_KEY");
@@ -72257,6 +72643,8 @@ function authHeaders() {
72257
72643
  var lmstudio;
72258
72644
  var init_lmstudio = __esm(() => {
72259
72645
  init_dist8();
72646
+ init_config2();
72647
+ init_compat_reasoning();
72260
72648
  lmstudio = {
72261
72649
  id: "lmstudio",
72262
72650
  name: "LM Studio",
@@ -72266,9 +72654,12 @@ var init_lmstudio = __esm(() => {
72266
72654
  asciiIcon: "L",
72267
72655
  description: "Local models via LM Studio \u2014 no key needed",
72268
72656
  createModel(modelId) {
72657
+ const reasoningBody = getCompatReasoningBody(`lmstudio/${modelId}`, loadConfig());
72658
+ const reasoningFetch = createReasoningFetchWrapper(reasoningBody);
72269
72659
  const client = createOpenAI({
72270
72660
  baseURL: openaiBase(),
72271
- apiKey: getApiToken()
72661
+ apiKey: getApiToken(),
72662
+ ...reasoningFetch ? { fetch: reasoningFetch } : {}
72272
72663
  });
72273
72664
  return client.chat(modelId);
72274
72665
  },
@@ -80526,7 +80917,9 @@ var init_dist19 = __esm(() => {
80526
80917
  var minimax2;
80527
80918
  var init_minimax = __esm(() => {
80528
80919
  init_dist19();
80920
+ init_config2();
80529
80921
  init_secrets();
80922
+ init_compat_reasoning();
80530
80923
  minimax2 = {
80531
80924
  id: "minimax",
80532
80925
  name: "MiniMax",
@@ -80541,7 +80934,12 @@ var init_minimax = __esm(() => {
80541
80934
  if (!apiKey) {
80542
80935
  throw new Error("MINIMAX_API_KEY is not set");
80543
80936
  }
80544
- return createMinimaxAnthropic({ apiKey })(modelId);
80937
+ const reasoningBody = getCompatReasoningBody(`minimax/${modelId}`, loadConfig());
80938
+ const reasoningFetch = createReasoningFetchWrapper(reasoningBody);
80939
+ return createMinimaxAnthropic({
80940
+ apiKey,
80941
+ ...reasoningFetch ? { fetch: reasoningFetch } : {}
80942
+ })(modelId);
80545
80943
  },
80546
80944
  async fetchModels() {
80547
80945
  return null;
@@ -81415,6 +81813,8 @@ function getOllamaHost() {
81415
81813
  var ollama;
81416
81814
  var init_ollama = __esm(() => {
81417
81815
  init_dist8();
81816
+ init_config2();
81817
+ init_compat_reasoning();
81418
81818
  ollama = {
81419
81819
  id: "ollama",
81420
81820
  name: "Ollama",
@@ -81423,9 +81823,12 @@ var init_ollama = __esm(() => {
81423
81823
  asciiIcon: "O",
81424
81824
  description: "Local models \u2014 no key needed",
81425
81825
  createModel(modelId) {
81826
+ const reasoningBody = getCompatReasoningBody(`ollama/${modelId}`, loadConfig());
81827
+ const reasoningFetch = createReasoningFetchWrapper(reasoningBody);
81426
81828
  const client = createOpenAI({
81427
81829
  baseURL: `${getOllamaHost()}/v1`,
81428
- apiKey: "ollama"
81830
+ apiKey: "ollama",
81831
+ ...reasoningFetch ? { fetch: reasoningFetch } : {}
81429
81832
  });
81430
81833
  return client.chat(modelId);
81431
81834
  },
@@ -81542,7 +81945,9 @@ var init_openai = __esm(() => {
81542
81945
  var BASE_URL2 = "https://opencode.ai/zen/go/v1", opencodeGo;
81543
81946
  var init_opencode_go = __esm(() => {
81544
81947
  init_dist9();
81948
+ init_config2();
81545
81949
  init_secrets();
81950
+ init_compat_reasoning();
81546
81951
  opencodeGo = {
81547
81952
  id: "opencode-go",
81548
81953
  name: "OpenCode Go",
@@ -81557,10 +81962,13 @@ var init_opencode_go = __esm(() => {
81557
81962
  if (!apiKey) {
81558
81963
  throw new Error("OPENCODE_GO_API_KEY is not set");
81559
81964
  }
81965
+ const reasoningBody = getCompatReasoningBody(`opencode-go/${modelId}`, loadConfig());
81966
+ const reasoningFetch = createReasoningFetchWrapper(reasoningBody);
81560
81967
  const provider = createOpenAICompatible({
81561
81968
  name: "opencode-go",
81562
81969
  baseURL: BASE_URL2,
81563
- apiKey
81970
+ apiKey,
81971
+ ...reasoningFetch ? { fetch: reasoningFetch } : {}
81564
81972
  });
81565
81973
  return provider.chatModel(modelId);
81566
81974
  },
@@ -81592,7 +82000,9 @@ var init_opencode_go = __esm(() => {
81592
82000
  var BASE_URL3 = "https://opencode.ai/zen/v1", opencodeZen;
81593
82001
  var init_opencode_zen = __esm(() => {
81594
82002
  init_dist9();
82003
+ init_config2();
81595
82004
  init_secrets();
82005
+ init_compat_reasoning();
81596
82006
  init_context_windows();
81597
82007
  opencodeZen = {
81598
82008
  id: "opencode-zen",
@@ -81609,10 +82019,13 @@ var init_opencode_zen = __esm(() => {
81609
82019
  if (!apiKey) {
81610
82020
  throw new Error("OPENCODE_ZEN_API_KEY is not set");
81611
82021
  }
82022
+ const reasoningBody = getCompatReasoningBody(`opencode-zen/${modelId}`, loadConfig());
82023
+ const reasoningFetch = createReasoningFetchWrapper(reasoningBody);
81612
82024
  const provider = createOpenAICompatible({
81613
82025
  name: "opencode-zen",
81614
82026
  baseURL: BASE_URL3,
81615
- apiKey
82027
+ apiKey,
82028
+ ...reasoningFetch ? { fetch: reasoningFetch } : {}
81616
82029
  });
81617
82030
  return provider.chatModel(modelId);
81618
82031
  },
@@ -87677,8 +88090,10 @@ var baseURL, proxy2;
87677
88090
  var init_proxy = __esm(() => {
87678
88091
  init_dist6();
87679
88092
  init_dist8();
88093
+ init_config2();
87680
88094
  init_key_resolver();
87681
88095
  init_lifecycle();
88096
+ init_compat_reasoning();
87682
88097
  init_context_windows();
87683
88098
  baseURL = process.env.PROXY_API_URL || "http://127.0.0.1:8317/v1";
87684
88099
  proxy2 = {
@@ -87693,7 +88108,13 @@ var init_proxy = __esm(() => {
87693
88108
  if (isAnthropicModel(modelId)) {
87694
88109
  return createAnthropic({ baseURL, apiKey })(modelId);
87695
88110
  }
87696
- return createOpenAI({ baseURL, apiKey }).chat(modelId);
88111
+ const reasoningBody = getCompatReasoningBody(`proxy/${modelId}`, loadConfig());
88112
+ const reasoningFetch = createReasoningFetchWrapper(reasoningBody);
88113
+ return createOpenAI({
88114
+ baseURL,
88115
+ apiKey,
88116
+ ...reasoningFetch ? { fetch: reasoningFetch } : {}
88117
+ }).chat(modelId);
87697
88118
  },
87698
88119
  async fetchModels() {
87699
88120
  return null;
@@ -91420,13 +91841,18 @@ function extractBaseModel(modelId) {
91420
91841
  return (slash >= 0 ? modelId.slice(slash + 1) : modelId).toLowerCase();
91421
91842
  }
91422
91843
  function getClaudeGen(model) {
91423
- if (!model.startsWith("claude"))
91844
+ let m = model;
91845
+ if (m.startsWith("us."))
91846
+ m = m.slice(3);
91847
+ if (m.startsWith("anthropic."))
91848
+ m = m.slice("anthropic.".length);
91849
+ if (!m.startsWith("claude"))
91424
91850
  return "non-claude";
91425
91851
  for (const p of LEGACY_PREFIXES) {
91426
- if (model.startsWith(p))
91852
+ if (m.startsWith(p))
91427
91853
  return "legacy";
91428
91854
  }
91429
- if (model.startsWith("claude-3.5") || model.startsWith("claude-3-5"))
91855
+ if (m.startsWith("claude-3.5") || m.startsWith("claude-3-5"))
91430
91856
  return "3.5";
91431
91857
  return "4+";
91432
91858
  }
@@ -91434,17 +91860,25 @@ function detectModelFamily(modelId) {
91434
91860
  const { provider } = parseModelId(modelId);
91435
91861
  if (provider === "anthropic")
91436
91862
  return "claude";
91437
- if (provider === "openai" || provider === "xai")
91863
+ if (provider === "openai")
91438
91864
  return "openai";
91865
+ if (provider === "xai")
91866
+ return "xai";
91439
91867
  if (provider === "google")
91440
91868
  return "google";
91869
+ if (provider === "deepseek")
91870
+ return "deepseek";
91441
91871
  const base = extractBaseModel(modelId);
91442
- if (base.startsWith("claude"))
91872
+ if (base.startsWith("claude") || base.startsWith("anthropic.claude"))
91443
91873
  return "claude";
91444
91874
  if (base.startsWith("gpt-") || base.startsWith("o1") || base.startsWith("o3") || base.startsWith("o4"))
91445
91875
  return "openai";
91446
91876
  if (base.startsWith("gemini"))
91447
91877
  return "google";
91878
+ if (base.startsWith("grok"))
91879
+ return "xai";
91880
+ if (base.startsWith("deepseek"))
91881
+ return "deepseek";
91448
91882
  const model = parseModelId(modelId).model;
91449
91883
  if (model.startsWith("anthropic/"))
91450
91884
  return "claude";
@@ -91452,88 +91886,96 @@ function detectModelFamily(modelId) {
91452
91886
  return "openai";
91453
91887
  if (model.startsWith("google/"))
91454
91888
  return "google";
91889
+ if (model.startsWith("x-ai/") || model.startsWith("xai/"))
91890
+ return "xai";
91891
+ if (model.startsWith("deepseek/"))
91892
+ return "deepseek";
91455
91893
  return "other";
91456
91894
  }
91457
91895
  function getModelCapabilities3(modelId) {
91458
91896
  const base = extractBaseModel(modelId);
91459
91897
  const family = detectModelFamily(modelId);
91898
+ const BASE = {
91899
+ provider: "other",
91900
+ thinking: false,
91901
+ adaptiveThinking: false,
91902
+ effort: false,
91903
+ speed: false,
91904
+ contextManagement: false,
91905
+ interleavedThinking: false,
91906
+ openaiReasoning: false,
91907
+ openaiServiceTier: false,
91908
+ googleThinking: false,
91909
+ googleThinkingLevel: false,
91910
+ xaiReasoning: false,
91911
+ deepseekThinking: false,
91912
+ openrouterReasoning: false,
91913
+ compatReasoning: false
91914
+ };
91460
91915
  if (family === "openai") {
91461
91916
  const isReasoning = base.startsWith("o1") || base.startsWith("o3") || base.startsWith("o4") || base.startsWith("gpt-5");
91462
91917
  return {
91918
+ ...BASE,
91463
91919
  provider: "openai",
91464
- thinking: false,
91465
- adaptiveThinking: false,
91466
- effort: false,
91467
- speed: false,
91468
- contextManagement: false,
91469
- interleavedThinking: false,
91470
91920
  openaiReasoning: isReasoning,
91471
91921
  openaiServiceTier: true
91472
91922
  };
91473
91923
  }
91474
91924
  if (family === "google") {
91925
+ const isGemini3 = /gemini-3(\.|-|$)/.test(base);
91926
+ const isGemini25 = /gemini-2\.5/.test(base);
91927
+ const supportsThinking = isGemini3 || isGemini25;
91475
91928
  return {
91929
+ ...BASE,
91476
91930
  provider: "google",
91477
- thinking: false,
91478
- adaptiveThinking: false,
91479
- effort: false,
91480
- speed: false,
91481
- contextManagement: false,
91482
- interleavedThinking: false,
91483
- openaiReasoning: false,
91484
- openaiServiceTier: false
91931
+ googleThinking: supportsThinking,
91932
+ googleThinkingLevel: isGemini3
91933
+ };
91934
+ }
91935
+ if (family === "xai") {
91936
+ const isReasoning = base.startsWith("grok-3-mini") || base.startsWith("grok-4") || base.includes("reasoning");
91937
+ return {
91938
+ ...BASE,
91939
+ provider: "xai",
91940
+ xaiReasoning: isReasoning
91941
+ };
91942
+ }
91943
+ if (family === "deepseek") {
91944
+ const isChat = base === "deepseek-chat" || base.startsWith("deepseek-v3");
91945
+ return {
91946
+ ...BASE,
91947
+ provider: "deepseek",
91948
+ deepseekThinking: isChat,
91949
+ compatReasoning: true
91485
91950
  };
91486
91951
  }
91487
91952
  if (family !== "claude") {
91953
+ const isCompatReasoning = /qwen3/.test(base) || /glm-(4\.[5-9]|[5-9])/.test(base) || /kimi-(k2|thinking)/.test(base) || /gpt-oss/.test(base) || /deepseek-r1/.test(base) || /minimax-m[2-9]/.test(base);
91488
91954
  return {
91489
- provider: "other",
91490
- thinking: false,
91491
- adaptiveThinking: false,
91492
- effort: false,
91493
- speed: false,
91494
- contextManagement: false,
91495
- interleavedThinking: false,
91496
- openaiReasoning: false,
91497
- openaiServiceTier: false
91955
+ ...BASE,
91956
+ compatReasoning: isCompatReasoning
91498
91957
  };
91499
91958
  }
91500
91959
  const gen = getClaudeGen(base);
91501
91960
  if (gen === "legacy") {
91502
- return {
91503
- provider: "anthropic",
91504
- thinking: false,
91505
- adaptiveThinking: false,
91506
- effort: false,
91507
- speed: false,
91508
- contextManagement: false,
91509
- interleavedThinking: false,
91510
- openaiReasoning: false,
91511
- openaiServiceTier: false
91512
- };
91961
+ return { ...BASE, provider: "anthropic" };
91513
91962
  }
91514
91963
  if (gen === "3.5") {
91515
91964
  return {
91965
+ ...BASE,
91516
91966
  provider: "anthropic",
91517
- thinking: true,
91518
- adaptiveThinking: false,
91519
- effort: false,
91520
- speed: false,
91521
- contextManagement: false,
91522
- interleavedThinking: false,
91523
- openaiReasoning: false,
91524
- openaiServiceTier: false
91967
+ thinking: true
91525
91968
  };
91526
91969
  }
91527
91970
  return {
91971
+ ...BASE,
91528
91972
  provider: "anthropic",
91529
91973
  thinking: true,
91530
91974
  adaptiveThinking: true,
91531
91975
  effort: !base.includes("haiku"),
91532
91976
  speed: base.includes("opus"),
91533
91977
  contextManagement: !base.includes("haiku"),
91534
- interleavedThinking: true,
91535
- openaiReasoning: false,
91536
- openaiServiceTier: false
91978
+ interleavedThinking: true
91537
91979
  };
91538
91980
  }
91539
91981
  function getProviderConstraints(providerId) {
@@ -91555,6 +91997,12 @@ function getEffectiveCaps(modelId) {
91555
91997
  ...model,
91556
91998
  anthropicOptions: pc.anthropicOptions && family === "claude",
91557
91999
  openaiOptions: pc.openaiOptions && family === "openai",
92000
+ googleOptions: pc.googleOptions && family === "google" && model.googleThinking,
92001
+ xaiOptions: pc.xaiOptions && family === "xai" && model.xaiReasoning,
92002
+ deepseekOptions: pc.deepseekOptions && family === "deepseek" && model.deepseekThinking,
92003
+ openrouterOptions: pc.openrouterOptions,
92004
+ bedrockOptions: pc.bedrockOptions && family === "claude",
92005
+ compatReasoningBody: pc.compatReasoningBody && (model.compatReasoning || model.deepseekThinking),
91558
92006
  adaptiveThinking: model.adaptiveThinking && pc.adaptiveThinking,
91559
92007
  effort: model.effort && pc.effort,
91560
92008
  speed: model.speed && pc.speed,
@@ -91657,9 +92105,6 @@ function getAnthropicToolVersions(modelId) {
91657
92105
  }
91658
92106
  return { computerUse, textEditor, programmaticToolCalling };
91659
92107
  }
91660
- function supportsAnthropicOptions(modelId) {
91661
- return getEffectiveCaps(modelId).anthropicOptions;
91662
- }
91663
92108
  function buildContextEdits(config2, contextWindow, thinkingEnabled) {
91664
92109
  const edits = [];
91665
92110
  if (config2?.clearThinking !== false && thinkingEnabled) {
@@ -91753,6 +92198,14 @@ function buildOpenAIOptions(caps, config2) {
91753
92198
  if (effort && effort !== "off") {
91754
92199
  opts.reasoningEffort = effort;
91755
92200
  }
92201
+ const summary = config2.performance?.openaiReasoningSummary;
92202
+ if (summary && summary !== "off") {
92203
+ opts.reasoningSummary = summary;
92204
+ }
92205
+ const verbosity = config2.performance?.openaiVerbosity;
92206
+ if (verbosity && verbosity !== "off") {
92207
+ opts.verbosity = verbosity;
92208
+ }
91756
92209
  }
91757
92210
  if (caps.openaiServiceTier) {
91758
92211
  const tier = config2.performance?.serviceTier;
@@ -91783,6 +92236,42 @@ async function buildProviderOptions(modelId, config2) {
91783
92236
  providerOptions.openai = result.opts;
91784
92237
  }
91785
92238
  }
92239
+ if (caps.googleOptions) {
92240
+ const result = buildGoogleOptions(modelId, caps, config2);
92241
+ if (Object.keys(result.opts).length > 0) {
92242
+ providerOptions.google = result.opts;
92243
+ }
92244
+ }
92245
+ if (caps.xaiOptions) {
92246
+ const result = buildXaiOptions(caps, config2);
92247
+ if (Object.keys(result.opts).length > 0) {
92248
+ providerOptions.xai = result.opts;
92249
+ }
92250
+ }
92251
+ if (caps.deepseekOptions) {
92252
+ const result = buildDeepseekOptions(caps, config2);
92253
+ if (Object.keys(result.opts).length > 0) {
92254
+ providerOptions.deepseek = result.opts;
92255
+ }
92256
+ }
92257
+ if (caps.openrouterOptions) {
92258
+ const result = buildOpenRouterOptions(caps, config2);
92259
+ if (Object.keys(result.opts).length > 0) {
92260
+ providerOptions.openrouter = result.opts;
92261
+ }
92262
+ }
92263
+ if (caps.bedrockOptions) {
92264
+ const result = buildBedrockOptions(modelId, caps, config2);
92265
+ if (Object.keys(result.opts).length > 0) {
92266
+ providerOptions.bedrock = result.opts;
92267
+ }
92268
+ }
92269
+ if (parseModelId(modelId).provider === "groq") {
92270
+ const result = buildGroqOptions(config2);
92271
+ if (Object.keys(result.opts).length > 0) {
92272
+ providerOptions.groq = result.opts;
92273
+ }
92274
+ }
91786
92275
  const { provider } = parseModelId(modelId);
91787
92276
  const customProvider2 = provider ? getProvider(provider) : null;
91788
92277
  if (customProvider2?.custom && customProvider2.customReasoning) {
@@ -91811,16 +92300,37 @@ async function buildProviderOptions(modelId, config2) {
91811
92300
  };
91812
92301
  }
91813
92302
  function degradeProviderOptions(modelId, level) {
91814
- if (level >= 2 || !supportsAnthropicOptions(modelId)) {
92303
+ if (level >= 2) {
91815
92304
  return { providerOptions: {}, headers: undefined, contextWindow: 0 };
91816
92305
  }
91817
- const caps = getModelCapabilities3(modelId);
91818
- const opts = {};
91819
- if (caps.thinking) {
91820
- opts.thinking = { type: "enabled", budgetTokens: 5000 };
92306
+ const caps = getEffectiveCaps(modelId);
92307
+ const providerOptions = {};
92308
+ if (caps.anthropicOptions && caps.thinking) {
92309
+ const opts = { thinking: { type: "enabled", budgetTokens: 5000 } };
92310
+ providerOptions.anthropic = opts;
92311
+ }
92312
+ if (caps.openaiOptions && caps.openaiReasoning) {
92313
+ providerOptions.openai = { reasoningEffort: "low" };
92314
+ }
92315
+ if (caps.googleOptions && caps.googleThinking) {
92316
+ providerOptions.google = caps.googleThinkingLevel ? { thinkingConfig: { thinkingLevel: "low" } } : { thinkingConfig: { thinkingBudget: 1024 } };
92317
+ }
92318
+ if (caps.xaiOptions && caps.xaiReasoning) {
92319
+ providerOptions.xai = { reasoningEffort: "low" };
92320
+ }
92321
+ if (caps.deepseekOptions && caps.deepseekThinking) {
92322
+ providerOptions.deepseek = { thinking: { type: "enabled" } };
92323
+ }
92324
+ if (caps.openrouterOptions) {
92325
+ providerOptions.openrouter = { reasoning: { effort: "low" } };
92326
+ }
92327
+ if (caps.bedrockOptions && caps.thinking) {
92328
+ providerOptions.bedrock = {
92329
+ reasoningConfig: { type: "enabled", budgetTokens: 5000 }
92330
+ };
91821
92331
  }
91822
92332
  return {
91823
- providerOptions: { anthropic: opts },
92333
+ providerOptions,
91824
92334
  headers: undefined,
91825
92335
  contextWindow: 0
91826
92336
  };
@@ -91830,13 +92340,167 @@ function isProviderOptionsError(error48) {
91830
92340
  const lower = msg.toLowerCase();
91831
92341
  return lower.includes("not supported") || lower.includes("not available") || lower.includes("does not support") || lower.includes("invalid parameter") || lower.includes("inputschema") || lower.includes("thinking is not supported") || lower.includes("adaptive thinking") || lower.includes("clear_thinking") || lower.includes("context management") || lower.includes("unknown parameter") || lower.includes("temperature is deprecated");
91832
92342
  }
91833
- var ANTHROPIC_FULL, OPENAI_FULL, GATEWAY_FULL, PROVIDER_CONSTRAINTS, NO_SUPPORT, LEGACY_PREFIXES, CACHE_EPHEMERAL, EPHEMERAL_CACHE;
92343
+ function buildGoogleOptions(modelId, caps, config2) {
92344
+ const opts = {};
92345
+ if (!caps.googleThinking)
92346
+ return { opts };
92347
+ const thinkingConfig = {};
92348
+ if (caps.googleThinkingLevel) {
92349
+ const level = config2.performance?.googleThinkingLevel;
92350
+ if (level && level !== "off") {
92351
+ thinkingConfig.thinkingLevel = level;
92352
+ } else if (config2.performance?.effort && config2.performance.effort !== "off") {
92353
+ const e = config2.performance.effort;
92354
+ const mapped = e === "max" || e === "xhigh" ? "high" : e === "high" || e === "medium" || e === "low" ? e : null;
92355
+ if (mapped)
92356
+ thinkingConfig.thinkingLevel = mapped;
92357
+ }
92358
+ } else {
92359
+ const budget = config2.performance?.googleThinkingBudget;
92360
+ if (typeof budget === "number") {
92361
+ thinkingConfig.thinkingBudget = budget;
92362
+ } else if (budget !== "off" && config2.performance?.effort && config2.performance.effort !== "off") {
92363
+ const map2 = {
92364
+ low: 1024,
92365
+ medium: 4096,
92366
+ high: 8192,
92367
+ xhigh: 16384,
92368
+ max: 24576
92369
+ };
92370
+ const v = map2[config2.performance.effort];
92371
+ if (v !== undefined)
92372
+ thinkingConfig.thinkingBudget = v;
92373
+ }
92374
+ }
92375
+ if (config2.performance?.googleIncludeThoughts) {
92376
+ thinkingConfig.includeThoughts = true;
92377
+ }
92378
+ if (Object.keys(thinkingConfig).length > 0) {
92379
+ opts.thinkingConfig = thinkingConfig;
92380
+ }
92381
+ return { opts };
92382
+ }
92383
+ function buildXaiOptions(caps, config2) {
92384
+ const opts = {};
92385
+ if (!caps.xaiReasoning)
92386
+ return { opts };
92387
+ const explicit = config2.performance?.xaiReasoningEffort;
92388
+ if (explicit && explicit !== "off") {
92389
+ opts.reasoningEffort = explicit === "medium" ? "high" : explicit;
92390
+ return { opts };
92391
+ }
92392
+ const e = config2.performance?.effort;
92393
+ if (e && e !== "off") {
92394
+ opts.reasoningEffort = e === "low" ? "low" : "high";
92395
+ }
92396
+ return { opts };
92397
+ }
92398
+ function buildDeepseekOptions(caps, config2) {
92399
+ const opts = {};
92400
+ if (!caps.deepseekThinking)
92401
+ return { opts };
92402
+ const explicit = config2.performance?.deepseekThinking;
92403
+ if (explicit === "enabled") {
92404
+ opts.thinking = { type: "enabled" };
92405
+ return { opts };
92406
+ }
92407
+ if (explicit === "off")
92408
+ return { opts };
92409
+ if (config2.performance?.effort && config2.performance.effort !== "off") {
92410
+ opts.thinking = { type: "enabled" };
92411
+ }
92412
+ return { opts };
92413
+ }
92414
+ function buildOpenRouterOptions(caps, config2) {
92415
+ const opts = {};
92416
+ if (!caps.openrouterOptions)
92417
+ return { opts };
92418
+ const reasoning = {};
92419
+ const explicitEffort = config2.performance?.openrouterReasoningEffort;
92420
+ const explicitMax = config2.performance?.openrouterReasoningMaxTokens;
92421
+ if (explicitMax !== undefined && explicitMax !== "off") {
92422
+ reasoning.max_tokens = explicitMax;
92423
+ } else if (explicitEffort && explicitEffort !== "off") {
92424
+ reasoning.effort = explicitEffort;
92425
+ } else if (config2.thinking?.mode === "enabled" && typeof config2.thinking?.budgetTokens === "number") {
92426
+ reasoning.max_tokens = config2.thinking.budgetTokens;
92427
+ } else {
92428
+ const e = config2.performance?.effort;
92429
+ if (e && e !== "off") {
92430
+ const mapped = {
92431
+ low: "low",
92432
+ medium: "medium",
92433
+ high: "high",
92434
+ xhigh: "xhigh",
92435
+ max: "xhigh"
92436
+ };
92437
+ const v = mapped[e];
92438
+ if (v)
92439
+ reasoning.effort = v;
92440
+ }
92441
+ }
92442
+ if (config2.performance?.openrouterExcludeReasoning) {
92443
+ reasoning.exclude = true;
92444
+ }
92445
+ if (Object.keys(reasoning).length > 0) {
92446
+ opts.reasoning = reasoning;
92447
+ }
92448
+ return { opts };
92449
+ }
92450
+ function buildBedrockOptions(modelId, caps, config2) {
92451
+ const opts = {};
92452
+ if (!caps.bedrockOptions)
92453
+ return { opts };
92454
+ const reasoningConfig = {};
92455
+ const mode = config2.thinking?.mode ?? "off";
92456
+ if (mode === "auto" || mode === "adaptive") {
92457
+ reasoningConfig.type = "adaptive";
92458
+ } else if (mode === "enabled") {
92459
+ reasoningConfig.type = "enabled";
92460
+ if (config2.thinking?.budgetTokens) {
92461
+ reasoningConfig.budgetTokens = config2.thinking.budgetTokens;
92462
+ }
92463
+ }
92464
+ if (caps.effort && config2.performance?.effort && config2.performance.effort !== "off") {
92465
+ const clamped = clampEffort(modelId, config2.performance.effort);
92466
+ if (clamped)
92467
+ reasoningConfig.maxReasoningEffort = clamped;
92468
+ }
92469
+ if (Object.keys(reasoningConfig).length > 0) {
92470
+ opts.reasoningConfig = reasoningConfig;
92471
+ }
92472
+ return { opts };
92473
+ }
92474
+ function buildGroqOptions(config2) {
92475
+ const opts = {};
92476
+ const fmt = config2.performance?.groqReasoningFormat;
92477
+ if (fmt && fmt !== "off") {
92478
+ opts.reasoningFormat = fmt;
92479
+ }
92480
+ return { opts };
92481
+ }
92482
+ var NO_SUPPORT, ANTHROPIC_FULL, OPENAI_FULL, GOOGLE_FULL, XAI_FULL, DEEPSEEK_FULL, OPENROUTER_FULL, GATEWAY_FULL, COMPAT_ONLY, PROVIDER_CONSTRAINTS, LEGACY_PREFIXES, CACHE_EPHEMERAL, EPHEMERAL_CACHE;
91834
92483
  var init_provider_options = __esm(() => {
91835
92484
  init_models();
91836
92485
  init_providers();
92486
+ NO_SUPPORT = {
92487
+ anthropicOptions: false,
92488
+ openaiOptions: false,
92489
+ googleOptions: false,
92490
+ xaiOptions: false,
92491
+ deepseekOptions: false,
92492
+ openrouterOptions: false,
92493
+ bedrockOptions: false,
92494
+ effort: false,
92495
+ speed: false,
92496
+ contextManagement: false,
92497
+ adaptiveThinking: false,
92498
+ interleavedThinking: false,
92499
+ compatReasoningBody: false
92500
+ };
91837
92501
  ANTHROPIC_FULL = {
92502
+ ...NO_SUPPORT,
91838
92503
  anthropicOptions: true,
91839
- openaiOptions: false,
91840
92504
  effort: true,
91841
92505
  speed: true,
91842
92506
  contextManagement: true,
@@ -91844,43 +92508,82 @@ var init_provider_options = __esm(() => {
91844
92508
  interleavedThinking: true
91845
92509
  };
91846
92510
  OPENAI_FULL = {
91847
- anthropicOptions: false,
92511
+ ...NO_SUPPORT,
92512
+ openaiOptions: true
92513
+ };
92514
+ GOOGLE_FULL = {
92515
+ ...NO_SUPPORT,
92516
+ googleOptions: true
92517
+ };
92518
+ XAI_FULL = {
92519
+ ...NO_SUPPORT,
92520
+ xaiOptions: true
92521
+ };
92522
+ DEEPSEEK_FULL = {
92523
+ ...NO_SUPPORT,
92524
+ deepseekOptions: true,
92525
+ compatReasoningBody: true
92526
+ };
92527
+ OPENROUTER_FULL = {
92528
+ ...NO_SUPPORT,
92529
+ openrouterOptions: true,
92530
+ anthropicOptions: true,
91848
92531
  openaiOptions: true,
91849
- effort: false,
91850
- speed: false,
91851
- contextManagement: false,
91852
- adaptiveThinking: false,
91853
- interleavedThinking: false
92532
+ googleOptions: true,
92533
+ xaiOptions: true,
92534
+ deepseekOptions: true,
92535
+ effort: true,
92536
+ speed: true,
92537
+ adaptiveThinking: true,
92538
+ interleavedThinking: true
91854
92539
  };
91855
92540
  GATEWAY_FULL = {
91856
92541
  anthropicOptions: true,
91857
92542
  openaiOptions: true,
92543
+ googleOptions: true,
92544
+ xaiOptions: true,
92545
+ deepseekOptions: true,
92546
+ openrouterOptions: false,
92547
+ bedrockOptions: false,
91858
92548
  effort: true,
91859
92549
  speed: true,
91860
92550
  contextManagement: true,
91861
92551
  adaptiveThinking: true,
91862
- interleavedThinking: true
92552
+ interleavedThinking: true,
92553
+ compatReasoningBody: false
92554
+ };
92555
+ COMPAT_ONLY = {
92556
+ ...NO_SUPPORT,
92557
+ compatReasoningBody: true
91863
92558
  };
91864
92559
  PROVIDER_CONSTRAINTS = {
91865
92560
  anthropic: ANTHROPIC_FULL,
91866
92561
  proxy: GATEWAY_FULL,
91867
92562
  openai: OPENAI_FULL,
91868
- xai: OPENAI_FULL,
92563
+ xai: XAI_FULL,
92564
+ google: GOOGLE_FULL,
92565
+ deepseek: DEEPSEEK_FULL,
92566
+ openrouter: OPENROUTER_FULL,
92567
+ groq: COMPAT_ONLY,
92568
+ fireworks: COMPAT_ONLY,
92569
+ minimax: COMPAT_ONLY,
92570
+ copilot: COMPAT_ONLY,
92571
+ "github-models": COMPAT_ONLY,
92572
+ "opencode-zen": { ...GATEWAY_FULL, compatReasoningBody: true },
92573
+ "opencode-go": COMPAT_ONLY,
92574
+ lmstudio: COMPAT_ONLY,
92575
+ ollama: COMPAT_ONLY,
91869
92576
  vercel_gateway: GATEWAY_FULL,
91870
92577
  llmgateway: GATEWAY_FULL,
91871
- opencode_zen: GATEWAY_FULL,
91872
- opencode_go: GATEWAY_FULL,
91873
- openrouter: GATEWAY_FULL,
91874
- bedrock: GATEWAY_FULL
91875
- };
91876
- NO_SUPPORT = {
91877
- anthropicOptions: false,
91878
- openaiOptions: false,
91879
- effort: false,
91880
- speed: false,
91881
- contextManagement: false,
91882
- adaptiveThinking: false,
91883
- interleavedThinking: false
92578
+ bedrock: {
92579
+ ...NO_SUPPORT,
92580
+ bedrockOptions: true,
92581
+ effort: true,
92582
+ speed: false,
92583
+ contextManagement: false,
92584
+ adaptiveThinking: true,
92585
+ interleavedThinking: false
92586
+ }
91884
92587
  };
91885
92588
  LEGACY_PREFIXES = [
91886
92589
  "claude-3-haiku",
@@ -406659,7 +407362,11 @@ For non-TS/JS files (JSON, YAML, Markdown, config) or raw text outside any symbo
406659
407362
 
406660
407363
  Recall fires automatically before each user turn \u2014 prompt + edited files \u2192 top-3 relevant memories injected as <recalled_memories> stubs (summary + id + signals + "\u21B3 has details" marker), \u2264600 chars typical. Cached, deduped, never re-injected in one session. When a stub's "\u21B3 has details" marker matters to the current task, call memory(action:"get", id:<8-char prefix>) to read the full body.
406661
407364
 
406662
- Auto-recall is signal-driven and misses generic or single-word prompts. Before any action where convention matters and nothing was surfaced \u2014 first commit of a session, adopting a framework/tool, changing config layout, writing tests in an unfamiliar area, picking a naming style \u2014 run memory(action:"search", query:<topic>) once. Cheap, deterministic, beats guessing. WRITE proactively, SEARCH when convention matters and nothing was recalled.
407365
+ Auto-recall is signal-driven and misses generic or single-word prompts. Before any action where convention matters and nothing was surfaced \u2014 first commit of a session, adopting a framework/tool, changing config layout, writing tests in an unfamiliar area, picking a naming style \u2014 run memory(action:"search", query:<topic>) once. Cheap, deterministic, beats guessing.
407366
+
407367
+ SEARCH KEYWORDS \u2014 fall back to memory(search) when about to do any of these and recall was empty: commit message shape, lint/format choice, test framework conventions, package manager (bun/npm/pnpm/yarn), import style, file naming, error-handling pattern, logger choice, state-management library, dispatch/agent setup, prompt-engineering rules. One search beats one wrong guess.
407368
+
407369
+ WRITE proactively, SEARCH when convention matters and nothing was recalled.
406663
407370
 
406664
407371
  WHY WRITES MATTER \u2014 the system multiplies them:
406665
407372
  - Soul Map stable file_id \u2192 memory on \`src/jwt.ts\` survives renames and refactors.
@@ -406670,6 +407377,13 @@ WHY WRITES MATTER \u2014 the system multiplies them:
406670
407377
 
406671
407378
  WHEN TO WRITE \u2014 the three triggers (fire on ANY of these, not just user-prompted ones):
406672
407379
  1. USER STATES A PREFERENCE OR DIRECTIVE. "use bun not npm", "be terse", "always run tests after edits" \u2192 pref. Write immediately, scope:"global" if it's not project-specific.
407380
+ INFER FROM CUES \u2014 don't wait for the word "remember". A preference exists whenever the user's correction or instruction implies a standing rule, not a one-shot fix. Cues that mean "this is durable":
407381
+ \u2022 Corrective tone about HOW you did something ("be more concise", "stop narrating", "use bullets") \u2014 the correction itself IS the rule.
407382
+ \u2022 Generalising language: "always", "never", "from now on", "by default", "prefer", "in this repo we\u2026", "we don't\u2026".
407383
+ \u2022 Imperative meta-instructions about workflow, style, tooling, formatting, naming \u2014 anything orthogonal to the current task.
407384
+ \u2022 User repeats or rephrases the same correction \u2192 it's a rule you missed last time. Write it now.
407385
+ \u2022 User asks "why didn't you\u2026?" about a behavior \u2014 they had an expectation. Capture the expectation.
407386
+ The literal word "remember" is just one cue among many. The test: "Would future-me want this surfaced next session?" If yes \u2192 write. Mid-instruction corrections ("commit it, and be concise") split into two acts: do the task, write the rule.
406673
407387
  2. A CHOICE GETS MADE WITH A REASON. "switching to zustand because redux is too much boilerplate", "postgres not mysql for the JSON ops" \u2192 decision. The WHY is what future you needs (the Soul Map shows the WHAT). Capture the rationale in details.
406674
407388
  3. SHARP-EDGE DISCOVERED. Bug that took >5min to diagnose, non-obvious quirk, "don't touch X because Y", a workaround for a flaky test \u2192 gotcha. Include the symptom + the fix location.
406675
407389
 
@@ -406731,7 +407445,7 @@ Use dedicated tools over shell for file reads, searches, definitions, and edits.
406731
407445
  For TS/JS (.ts/.tsx/.js/.jsx/.mts/.cts/.mjs/.cjs): \`ast_edit\` is the default \u2014 ts-morph locates symbols by {target, name}, no oldString/line drift. Use \`edit_file\`/\`multi_edit\` only for non-TS/JS or raw text outside any symbol (always pass \`lineStart\` from read output).
406732
407446
  Batch independent tool calls in one parallel block. Use the \`git\` tool for git, \`soul_vision\` for images.
406733
407447
 
406734
- \`memory\` is your across-session brain \u2014 auto-recall fires before each user turn (top-3 stubs, \u2264600 chars typical; call memory(get, id) to read full body when "\u21B3 has details" matters). Use it like a primary tool, not a last resort: every write earns its keep when a future ambiguous prompt triggers the right recall. WRITE on (1) user preference/directive \u2192 pref, (2) choice with rationale \u2192 decision, (3) sharp edge that took effort to find \u2192 gotcha. Always set \`file_paths\` for file-scoped memories \u2014 strongest recall signal, co-change-aware. On similar_hints (\u226585% cosine), \`get\` the existing entry; refinement \u2192 merge_topics:true, contradiction \u2192 supersede. On recall conflict with the current request, raise it before acting. Soft-delete only; \u22643 surfaced per turn hard cap means a bad write won't poison context.
407448
+ \`memory\` is your across-session brain \u2014 auto-recall fires before each user turn (top-3 stubs, \u2264600 chars typical; call memory(get, id) to read full body when "\u21B3 has details" matters). Use it like a primary tool, not a last resort: every write earns its keep when a future ambiguous prompt triggers the right recall. WRITE on (1) user preference/directive \u2192 pref. Infer from cues, don't wait for "remember": corrective tone about HOW you worked ("be terse", "stop narrating"), generalising language ("always/never/by default/we don't"), repeated corrections, or "why didn't you\u2026?" questions all signal a standing rule. Mid-instruction corrections ("commit it, and be concise") split into two acts: do the task, write the rule. (2) choice with rationale \u2192 decision, (3) sharp edge that took effort to find \u2192 gotcha. SEARCH fallback: when about to commit, pick a framework/lib, name a file, or apply any convention and recall was empty, run memory(search, query) once before guessing. Always set \`file_paths\` for file-scoped memories \u2014 strongest recall signal, co-change-aware. On similar_hints (\u226585% cosine), \`get\` the existing entry; refinement \u2192 merge_topics:true, contradiction \u2192 supersede. On recall conflict with the current request, raise it before acting. Soft-delete only; \u22643 surfaced per turn hard cap means a bad write won't poison context.
406735
407449
  </tool_usage>`;
406736
407450
 
406737
407451
  // src/core/prompts/shared/index.ts
@@ -406780,6 +407494,8 @@ var init_builder = __esm(() => {
406780
407494
  claude: CLAUDE_PROMPT,
406781
407495
  openai: OPENAI_PROMPT,
406782
407496
  google: GOOGLE_PROMPT,
407497
+ xai: OPENAI_PROMPT,
407498
+ deepseek: OPENAI_PROMPT,
406783
407499
  other: DEFAULT_PROMPT
406784
407500
  };
406785
407501
  });
@@ -429107,6 +429823,11 @@ class HearthDaemon {
429107
429823
  return;
429108
429824
  const ws = this.workspaces.get(surfaceId, msg.externalId);
429109
429825
  const hasBridge = hearthBridge.getBinding(surfaceId, msg.externalId) !== null;
429826
+ if (SETTINGS_COMMAND_NAMES.includes(cmd.name)) {
429827
+ const handled = await handleSettingsCommand(cmd.name, cmd.args, (text3) => surface.notify(msg.externalId, text3));
429828
+ if (handled)
429829
+ return;
429830
+ }
429110
429831
  if (hasBridge) {
429111
429832
  switch (cmd.name) {
429112
429833
  case "/tabs":
@@ -429499,6 +430220,9 @@ class HearthDaemon {
429499
430220
  "\u2501\u2501 Pairing \u2501\u2501",
429500
430221
  "/pair [CODE] pair this chat",
429501
430222
  "/unpair revoke",
430223
+ "",
430224
+ ...settingsHelpLines(),
430225
+ "",
429502
430226
  "/help this list"
429503
430227
  ].join(`
429504
430228
  `));
@@ -429714,6 +430438,7 @@ var init_daemon = __esm(() => {
429714
430438
  init_pairing();
429715
430439
  init_peer_auth();
429716
430440
  init_protocol();
430441
+ init_provider_commands();
429717
430442
  init_redact();
429718
430443
  init_surface_host();
429719
430444
  init_workspace();
@@ -478306,6 +479031,11 @@ class TuiHost {
478306
479031
  const surface = this.host.getSurface(surfaceId);
478307
479032
  if (!surface)
478308
479033
  return;
479034
+ if (SETTINGS_COMMAND_NAMES.includes(cmd.name)) {
479035
+ const handled = await handleSettingsCommand(cmd.name, cmd.args, (text3) => surface.notify(msg.externalId, text3));
479036
+ if (handled)
479037
+ return;
479038
+ }
478309
479039
  switch (cmd.name) {
478310
479040
  case "/tabs":
478311
479041
  case "/list": {
@@ -478851,6 +479581,9 @@ class TuiHost {
478851
479581
  "\u2501\u2501 Pairing \u2501\u2501",
478852
479582
  "/pair [CODE] pair this chat \xB7 redeem a code",
478853
479583
  "/unpair revoke pairing",
479584
+ "",
479585
+ ...settingsHelpLines(),
479586
+ "",
478854
479587
  "/help this list"
478855
479588
  ].join(`
478856
479589
  `));
@@ -478928,6 +479661,7 @@ var init_tui_host = __esm(() => {
478928
479661
  init_config();
478929
479662
  init_pairing();
478930
479663
  init_protocol();
479664
+ init_provider_commands();
478931
479665
  init_redact();
478932
479666
  init_surface_host();
478933
479667
  });
@@ -496528,7 +497262,7 @@ var init_LockInStreamView = __esm(async () => {
496528
497262
  const dispatchCalls = import_react42.useMemo(() => {
496529
497263
  const next = liveToolCalls.filter((tc) => SUBAGENT_NAMES.has(tc.toolName));
496530
497264
  const prev = dispatchRef.current;
496531
- if (prev.length === next.length && prev.every((p2, i4) => p2 === next[i4] || p2.id === next[i4]?.id)) {
497265
+ if (prev.length === next.length && prev.every((p2, i4) => next[i4] !== undefined && p2.id === next[i4]?.id && p2.state === next[i4]?.state && p2.args === next[i4]?.args && p2.result === next[i4]?.result && p2.error === next[i4]?.error && p2.progressText === next[i4]?.progressText)) {
496532
497266
  return prev;
496533
497267
  }
496534
497268
  dispatchRef.current = next;
@@ -518784,6 +519518,32 @@ function readValuesFromLayer(layer) {
518784
519518
  v4.openaiReasoningEffort = layer.performance.openaiReasoningEffort;
518785
519519
  if (layer.performance?.serviceTier !== undefined)
518786
519520
  v4.serviceTier = layer.performance.serviceTier;
519521
+ if (layer.performance?.googleThinkingLevel !== undefined)
519522
+ v4.googleThinkingLevel = layer.performance.googleThinkingLevel;
519523
+ if (layer.performance?.googleThinkingBudget !== undefined)
519524
+ v4.googleThinkingBudget = String(layer.performance.googleThinkingBudget);
519525
+ if (layer.performance?.googleIncludeThoughts !== undefined)
519526
+ v4.googleIncludeThoughts = layer.performance.googleIncludeThoughts;
519527
+ if (layer.performance?.xaiReasoningEffort !== undefined)
519528
+ v4.xaiReasoningEffort = layer.performance.xaiReasoningEffort;
519529
+ if (layer.performance?.deepseekThinking !== undefined)
519530
+ v4.deepseekThinking = layer.performance.deepseekThinking;
519531
+ if (layer.performance?.openrouterReasoningEffort !== undefined)
519532
+ v4.openrouterReasoningEffort = layer.performance.openrouterReasoningEffort;
519533
+ if (layer.performance?.openrouterReasoningMaxTokens !== undefined)
519534
+ v4.openrouterReasoningMaxTokens = String(layer.performance.openrouterReasoningMaxTokens);
519535
+ if (layer.performance?.openrouterExcludeReasoning !== undefined)
519536
+ v4.openrouterExcludeReasoning = layer.performance.openrouterExcludeReasoning;
519537
+ if (layer.performance?.compatReasoningEffort !== undefined)
519538
+ v4.compatReasoningEffort = layer.performance.compatReasoningEffort;
519539
+ if (layer.performance?.groqReasoningEffort !== undefined)
519540
+ v4.groqReasoningEffort = layer.performance.groqReasoningEffort;
519541
+ if (layer.performance?.openaiReasoningSummary !== undefined)
519542
+ v4.openaiReasoningSummary = layer.performance.openaiReasoningSummary;
519543
+ if (layer.performance?.openaiVerbosity !== undefined)
519544
+ v4.openaiVerbosity = layer.performance.openaiVerbosity;
519545
+ if (layer.performance?.groqReasoningFormat !== undefined)
519546
+ v4.groqReasoningFormat = layer.performance.groqReasoningFormat;
518787
519547
  if (layer.codeExecution !== undefined)
518788
519548
  v4.codeExecution = layer.codeExecution;
518789
519549
  if (layer.computerUse !== undefined)
@@ -518829,6 +519589,36 @@ function buildPatch(key3, value) {
518829
519589
  return { performance: { openaiReasoningEffort: value } };
518830
519590
  case "serviceTier":
518831
519591
  return { performance: { serviceTier: value } };
519592
+ case "googleThinkingLevel":
519593
+ return { performance: { googleThinkingLevel: value } };
519594
+ case "googleThinkingBudget": {
519595
+ const v4 = value === "off" ? "off" : Number(value);
519596
+ return { performance: { googleThinkingBudget: v4 } };
519597
+ }
519598
+ case "googleIncludeThoughts":
519599
+ return { performance: { googleIncludeThoughts: value } };
519600
+ case "xaiReasoningEffort":
519601
+ return { performance: { xaiReasoningEffort: value } };
519602
+ case "deepseekThinking":
519603
+ return { performance: { deepseekThinking: value } };
519604
+ case "openrouterReasoningEffort":
519605
+ return { performance: { openrouterReasoningEffort: value } };
519606
+ case "openrouterReasoningMaxTokens": {
519607
+ const v4 = value === "off" ? "off" : Number(value);
519608
+ return { performance: { openrouterReasoningMaxTokens: v4 } };
519609
+ }
519610
+ case "openrouterExcludeReasoning":
519611
+ return { performance: { openrouterExcludeReasoning: value } };
519612
+ case "compatReasoningEffort":
519613
+ return { performance: { compatReasoningEffort: value } };
519614
+ case "groqReasoningEffort":
519615
+ return { performance: { groqReasoningEffort: value } };
519616
+ case "openaiReasoningSummary":
519617
+ return { performance: { openaiReasoningSummary: value } };
519618
+ case "openaiVerbosity":
519619
+ return { performance: { openaiVerbosity: value } };
519620
+ case "groqReasoningFormat":
519621
+ return { performance: { groqReasoningFormat: value } };
518832
519622
  case "codeExecution":
518833
519623
  return { codeExecution: value };
518834
519624
  case "computerUse":
@@ -518873,7 +519663,7 @@ function ProviderSettings({
518873
519663
  const { width: termCols, height: termRows } = useTerminalDimensions();
518874
519664
  const containerRows = termRows - 2;
518875
519665
  const popupWidth = Math.min(MAX_POPUP_WIDTH4, Math.floor(termCols * 0.85));
518876
- const maxVisible = Math.max(4, Math.floor(containerRows * 0.85) - CHROME_ROWS6);
519666
+ const maxVisible = Math.max(6, Math.floor(containerRows * 0.85) - CHROME_ROWS6);
518877
519667
  const t2 = useTheme();
518878
519668
  const [tab, setTab] = import_react136.useState("claude");
518879
519669
  const [cursor, setCursor] = import_react136.useState(0);
@@ -518881,12 +519671,13 @@ function ProviderSettings({
518881
519671
  const vals = effectiveValues(globalConfig2, projectConfig);
518882
519672
  const items = TAB_ITEMS[tab];
518883
519673
  const tabIdx = TABS5.indexOf(tab);
519674
+ const firstRowIdx = items.findIndex((i4) => i4.type !== "section" && i4.type !== "info");
518884
519675
  import_react136.useEffect(() => {
518885
519676
  if (visible)
518886
519677
  setScope(detectInitialScope(projectConfig));
518887
519678
  }, [visible, projectConfig]);
518888
519679
  import_react136.useEffect(() => {
518889
- setCursor(0);
519680
+ setCursor(Math.max(0, firstRowIdx));
518890
519681
  }, [tab]);
518891
519682
  const isBudgetDisabled = vals.thinkingMode !== "enabled";
518892
519683
  const isThinkingDisabled = vals.thinkingMode === "off" || vals.thinkingMode === "disabled";
@@ -518897,6 +519688,19 @@ function ProviderSettings({
518897
519688
  return isThinkingDisabled;
518898
519689
  return false;
518899
519690
  };
519691
+ const stepCursor = (dir) => {
519692
+ if (items.length === 0)
519693
+ return;
519694
+ let next = cursor;
519695
+ for (let i4 = 0;i4 < items.length; i4++) {
519696
+ next = (next + dir + items.length) % items.length;
519697
+ const it = items[next];
519698
+ if (it && it.type !== "section" && it.type !== "info") {
519699
+ setCursor(next);
519700
+ return;
519701
+ }
519702
+ }
519703
+ };
518900
519704
  const cycleValue = (item) => {
518901
519705
  if (item.type === "toggle") {
518902
519706
  if (isItemDisabled(item.key))
@@ -518935,16 +519739,16 @@ function ProviderSettings({
518935
519739
  return;
518936
519740
  }
518937
519741
  if (evt.name === "up") {
518938
- setCursor((c) => c > 0 ? c - 1 : items.length - 1);
519742
+ stepCursor(-1);
518939
519743
  return;
518940
519744
  }
518941
519745
  if (evt.name === "down") {
518942
- setCursor((c) => c < items.length - 1 ? c + 1 : 0);
519746
+ stepCursor(1);
518943
519747
  return;
518944
519748
  }
518945
519749
  if (evt.name === "return" || evt.name === " ") {
518946
519750
  const item = items[cursor];
518947
- if (item)
519751
+ if (item && item.type !== "section" && item.type !== "info")
518948
519752
  cycleValue(item);
518949
519753
  return;
518950
519754
  }
@@ -518973,6 +519777,9 @@ function ProviderSettings({
518973
519777
  const sidebarW = 22;
518974
519778
  const contentW = popupWidth - sidebarW - 3;
518975
519779
  const labelW = 22;
519780
+ const focusedItem = items[cursor];
519781
+ const focusedRow = focusedItem && focusedItem.type !== "section" && focusedItem.type !== "info" ? focusedItem : null;
519782
+ const focusedDisabled = focusedRow ? isItemDisabled(focusedRow.key) : false;
518976
519783
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PremiumPopup, {
518977
519784
  visible,
518978
519785
  width: popupWidth,
@@ -518981,14 +519788,25 @@ function ProviderSettings({
518981
519788
  titleIcon: "system",
518982
519789
  tabs: [
518983
519790
  { id: "claude", label: "Claude", icon: "ai", blurb: "thinking \xB7 reasoning \xB7 beta" },
518984
- { id: "openai", label: "OpenAI", icon: "ai", blurb: "reasoning effort \xB7 summary" },
518985
- { id: "general", label: "General", icon: "cloud", blurb: "shared provider options" }
519791
+ { id: "openai", label: "OpenAI", icon: "ai", blurb: "reasoning \xB7 service tier" },
519792
+ { id: "google", label: "Gemini", icon: "ai", blurb: "thinking level \xB7 budget" },
519793
+ { id: "xai", label: "Grok", icon: "ai", blurb: "reasoning effort" },
519794
+ { id: "deepseek", label: "DeepSeek", icon: "ai", blurb: "thinking toggle" },
519795
+ { id: "openrouter", label: "OpenRouter", icon: "cloud", blurb: "unified reasoning" },
519796
+ {
519797
+ id: "compat",
519798
+ label: "Other",
519799
+ icon: "cloud",
519800
+ blurb: "Groq \xB7 OpenCode \xB7 Fireworks \xB7 LM Studio \xB7 Ollama \u2026"
519801
+ },
519802
+ { id: "general", label: "General", icon: "cloud", blurb: "shared options" }
518986
519803
  ],
518987
519804
  activeTab: tab,
518988
519805
  footerHints: [
518989
- { key: "Tab", label: "switch tab" },
519806
+ { key: "Tab", label: "tab" },
518990
519807
  { key: "\u2191\u2193", label: "nav" },
518991
- { key: "Enter/\u2190\u2192", label: "cycle" },
519808
+ { key: "Enter", label: "cycle" },
519809
+ { key: "\u2190\u2192", label: "scope" },
518992
519810
  { key: "Esc", label: "close" }
518993
519811
  ],
518994
519812
  children: [
@@ -519006,140 +519824,144 @@ function ProviderSettings({
519006
519824
  items,
519007
519825
  selectedIndex: cursor,
519008
519826
  width: contentW,
519009
- maxRows: Math.max(1, Math.floor(maxVisible / 3)),
519010
- rowHeight: 3,
519011
- keyExtractor: (item) => item.key,
519827
+ maxRows: maxVisible,
519828
+ rowHeight: 1,
519829
+ keyExtractor: (item, idx) => item.type === "section" ? `sec-${idx}-${item.label}` : item.type === "info" ? `info-${idx}` : item.key,
519012
519830
  renderItem: (item, { selected }) => {
519831
+ if (item.type === "section") {
519832
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519833
+ flexDirection: "row",
519834
+ backgroundColor: t2.bgPopup,
519835
+ paddingX: 1,
519836
+ children: [
519837
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519838
+ bg: t2.bgPopup,
519839
+ fg: t2.textMuted,
519840
+ attributes: 1,
519841
+ children: item.label.toUpperCase()
519842
+ }, undefined, false, undefined, this),
519843
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519844
+ bg: t2.bgPopup,
519845
+ fg: t2.textFaint,
519846
+ children: [
519847
+ " ",
519848
+ "\u2500".repeat(Math.max(0, contentW - item.label.length - 6))
519849
+ ]
519850
+ }, undefined, true, undefined, this)
519851
+ ]
519852
+ }, undefined, true, undefined, this);
519853
+ }
519854
+ if (item.type === "info") {
519855
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519856
+ flexDirection: "row",
519857
+ backgroundColor: t2.bgPopup,
519858
+ paddingX: 1,
519859
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519860
+ bg: t2.bgPopup,
519861
+ fg: t2.textFaint,
519862
+ children: [
519863
+ "\u2139 ",
519864
+ item.text
519865
+ ]
519866
+ }, undefined, true, undefined, this)
519867
+ }, undefined, false, undefined, this);
519868
+ }
519013
519869
  const disabled = isItemDisabled(item.key);
519014
519870
  const bg2 = selected ? t2.bgPopupHighlight : t2.bgPopup;
519015
519871
  const raw2 = vals[item.key];
519016
519872
  const srcScope = detectValueScope(item.key, projectConfig);
519017
- const srcTag = srcScope === "project" ? "proj" : "glob";
519018
- const srcColor = srcScope === "project" ? t2.info : t2.textMuted;
519019
- const caption = /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519020
- bg: bg2,
519021
- fg: t2.textFaint,
519022
- children: [
519023
- " ",
519024
- item.desc
519025
- ]
519026
- }, undefined, true, undefined, this);
519873
+ const showScope = srcScope === "project";
519027
519874
  let body4;
519028
519875
  if (item.type === "toggle") {
519876
+ const on = !!raw2;
519029
519877
  body4 = /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519030
519878
  flexDirection: "row",
519031
519879
  backgroundColor: bg2,
519032
519880
  children: [
519033
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Toggle, {
519034
- label: item.label,
519035
- on: !!raw2,
519036
- focused: selected && !disabled,
519037
- bg: bg2
519881
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519882
+ bg: bg2,
519883
+ fg: selected ? t2.brand : t2.textFaint,
519884
+ children: selected ? "\u25B8 " : " "
519885
+ }, undefined, false, undefined, this),
519886
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519887
+ bg: bg2,
519888
+ fg: disabled ? t2.textDim : selected ? t2.brand : t2.textPrimary,
519889
+ attributes: selected ? 1 : undefined,
519890
+ children: item.label.padEnd(labelW)
519891
+ }, undefined, false, undefined, this),
519892
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519893
+ bg: bg2,
519894
+ fg: disabled ? t2.textDim : on ? t2.success : t2.textDim,
519895
+ children: on ? "\u25CF on " : "\u25CB off"
519038
519896
  }, undefined, false, undefined, this),
519039
519897
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519040
519898
  flexGrow: 1,
519041
519899
  backgroundColor: bg2
519042
519900
  }, undefined, false, undefined, this),
519043
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519901
+ showScope ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519044
519902
  bg: bg2,
519045
- fg: srcColor,
519046
- children: [
519047
- srcTag,
519048
- " "
519049
- ]
519050
- }, undefined, true, undefined, this)
519903
+ fg: t2.info,
519904
+ children: "proj"
519905
+ }, undefined, false, undefined, this) : null
519051
519906
  ]
519052
519907
  }, undefined, true, undefined, this);
519053
519908
  } else {
519054
519909
  const opts = item.options ?? [];
519055
519910
  const currentValue = item.type === "budget" ? String(vals.budgetTokens) : String(raw2);
519056
- const optsFit = opts.length > 0 && opts.join(" ").length + labelW + 4 <= contentW - 10;
519057
- if (optsFit) {
519058
- body4 = /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519059
- flexDirection: "row",
519060
- backgroundColor: bg2,
519061
- children: [
519062
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SegmentedControl, {
519063
- label: item.label,
519064
- labelWidth: labelW,
519065
- options: opts.map((o3) => ({ value: o3, label: o3 })),
519066
- value: currentValue,
519067
- focused: selected && !disabled,
519068
- bg: bg2
519069
- }, undefined, false, undefined, this),
519070
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519071
- flexGrow: 1,
519072
- backgroundColor: bg2
519073
- }, undefined, false, undefined, this),
519074
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519075
- bg: bg2,
519076
- fg: srcColor,
519077
- children: [
519078
- srcTag,
519079
- " "
519080
- ]
519081
- }, undefined, true, undefined, this)
519082
- ]
519083
- }, undefined, true, undefined, this);
519084
- } else {
519085
- const valColor = disabled ? t2.textFaint : raw2 === "off" ? t2.textMuted : t2.brandAlt;
519086
- body4 = /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519087
- flexDirection: "row",
519088
- backgroundColor: bg2,
519089
- children: [
519090
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519091
- bg: bg2,
519092
- fg: selected ? t2.brand : t2.textFaint,
519093
- children: selected ? "\u25B8 " : " "
519094
- }, undefined, false, undefined, this),
519095
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519096
- bg: bg2,
519097
- fg: disabled ? t2.textFaint : selected ? t2.brand : t2.textPrimary,
519098
- attributes: selected ? 1 : undefined,
519099
- children: item.label.padEnd(labelW)
519100
- }, undefined, false, undefined, this),
519101
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519102
- bg: bg2,
519103
- fg: valColor,
519104
- attributes: 1,
519105
- children: [
519106
- "[",
519107
- currentValue,
519108
- "]"
519109
- ]
519110
- }, undefined, true, undefined, this),
519111
- selected && !disabled ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519112
- bg: bg2,
519113
- fg: t2.textDim,
519114
- children: " \u2190 \u2192"
519115
- }, undefined, false, undefined, this) : null,
519116
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519117
- flexGrow: 1,
519118
- backgroundColor: bg2
519119
- }, undefined, false, undefined, this),
519120
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519121
- bg: bg2,
519122
- fg: srcColor,
519123
- children: [
519124
- srcTag,
519125
- " "
519126
- ]
519127
- }, undefined, true, undefined, this)
519128
- ]
519129
- }, undefined, true, undefined, this);
519130
- }
519911
+ const valColor = disabled ? t2.textDim : currentValue === "off" ? t2.textMuted : t2.brandAlt;
519912
+ body4 = /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519913
+ flexDirection: "row",
519914
+ backgroundColor: bg2,
519915
+ children: [
519916
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519917
+ bg: bg2,
519918
+ fg: selected ? t2.brand : t2.textFaint,
519919
+ children: selected ? "\u25B8 " : " "
519920
+ }, undefined, false, undefined, this),
519921
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519922
+ bg: bg2,
519923
+ fg: disabled ? t2.textDim : selected ? t2.brand : t2.textPrimary,
519924
+ attributes: selected ? 1 : undefined,
519925
+ children: item.label.padEnd(labelW)
519926
+ }, undefined, false, undefined, this),
519927
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519928
+ bg: bg2,
519929
+ fg: valColor,
519930
+ attributes: 1,
519931
+ children: [
519932
+ "[",
519933
+ currentValue,
519934
+ "]"
519935
+ ]
519936
+ }, undefined, true, undefined, this),
519937
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519938
+ bg: bg2,
519939
+ fg: t2.textFaint,
519940
+ children: [
519941
+ " ",
519942
+ opts.filter((o3) => o3 !== currentValue).slice(0, 4).join(" \xB7 ")
519943
+ ]
519944
+ }, undefined, true, undefined, this),
519945
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519946
+ flexGrow: 1,
519947
+ backgroundColor: bg2
519948
+ }, undefined, false, undefined, this),
519949
+ showScope ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519950
+ bg: bg2,
519951
+ fg: t2.info,
519952
+ children: "proj"
519953
+ }, undefined, false, undefined, this) : null
519954
+ ]
519955
+ }, undefined, true, undefined, this);
519131
519956
  }
519132
519957
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519133
- flexDirection: "column",
519958
+ flexDirection: "row",
519134
519959
  flexShrink: 0,
519135
519960
  backgroundColor: bg2,
519136
519961
  paddingX: 1,
519137
- height: 3,
519138
- children: [
519139
- body4,
519140
- caption
519141
- ]
519142
- }, undefined, true, undefined, this);
519962
+ height: 1,
519963
+ children: body4
519964
+ }, undefined, false, undefined, this);
519143
519965
  }
519144
519966
  }, undefined, false, undefined, this)
519145
519967
  }, undefined, false, undefined, this),
@@ -519147,20 +519969,44 @@ function ProviderSettings({
519147
519969
  width: contentW
519148
519970
  }, undefined, false, undefined, this),
519149
519971
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519972
+ flexDirection: "column",
519150
519973
  paddingX: 2,
519151
519974
  paddingY: 1,
519152
519975
  backgroundColor: t2.bgPopup,
519153
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SegmentedControl, {
519154
- label: "Save to",
519155
- labelWidth: 8,
519156
- options: CONFIG_SCOPES.map((s2) => ({ value: s2, label: s2 })),
519157
- value: scope
519158
- }, undefined, false, undefined, this)
519159
- }, undefined, false, undefined, this)
519976
+ children: [
519977
+ focusedRow ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519978
+ flexDirection: "row",
519979
+ backgroundColor: t2.bgPopup,
519980
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519981
+ bg: t2.bgPopup,
519982
+ fg: focusedDisabled ? t2.textDim : t2.textMuted,
519983
+ children: focusedRow.desc
519984
+ }, undefined, false, undefined, this)
519985
+ }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519986
+ flexDirection: "row",
519987
+ backgroundColor: t2.bgPopup,
519988
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
519989
+ bg: t2.bgPopup,
519990
+ fg: t2.textFaint,
519991
+ children: " "
519992
+ }, undefined, false, undefined, this)
519993
+ }, undefined, false, undefined, this),
519994
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
519995
+ flexDirection: "row",
519996
+ backgroundColor: t2.bgPopup,
519997
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SegmentedControl, {
519998
+ label: "Save to",
519999
+ labelWidth: 8,
520000
+ options: CONFIG_SCOPES.map((s2) => ({ value: s2, label: s2 })),
520001
+ value: scope
520002
+ }, undefined, false, undefined, this)
520003
+ }, undefined, false, undefined, this)
520004
+ ]
520005
+ }, undefined, true, undefined, this)
519160
520006
  ]
519161
520007
  }, undefined, true, undefined, this);
519162
520008
  }
519163
- var import_react136, MAX_POPUP_WIDTH4 = 110, CHROME_ROWS6 = 10, TABS5, CLAUDE_ITEMS, OPENAI_ITEMS, GENERAL_ITEMS, TAB_ITEMS, DEFAULTS;
520009
+ var import_react136, MAX_POPUP_WIDTH4 = 110, CHROME_ROWS6 = 10, TABS5, CLAUDE_ITEMS, OPENAI_ITEMS, GENERAL_ITEMS, GOOGLE_ITEMS, XAI_ITEMS, DEEPSEEK_ITEMS, OPENROUTER_ITEMS, COMPAT_ITEMS, TAB_ITEMS, DEFAULTS;
519164
520010
  var init_ProviderSettings = __esm(async () => {
519165
520011
  init_theme();
519166
520012
  init_shared2();
@@ -519168,125 +520014,279 @@ var init_ProviderSettings = __esm(async () => {
519168
520014
  init_jsx_dev_runtime();
519169
520015
  await init_react2();
519170
520016
  import_react136 = __toESM(require_react(), 1);
519171
- TABS5 = ["claude", "openai", "general"];
520017
+ TABS5 = [
520018
+ "claude",
520019
+ "openai",
520020
+ "google",
520021
+ "xai",
520022
+ "deepseek",
520023
+ "openrouter",
520024
+ "compat",
520025
+ "general"
520026
+ ];
519172
520027
  CLAUDE_ITEMS = [
520028
+ { type: "section", label: "Reasoning" },
519173
520029
  {
519174
520030
  key: "thinkingMode",
519175
520031
  label: "Thinking",
519176
- desc: "off | auto (adaptive) | enabled (fixed budget)",
520032
+ desc: "Extended thinking mode. auto = adaptive \xB7 enabled = fixed budget",
519177
520033
  type: "cycle",
519178
- options: ["off", "disabled", "auto", "adaptive", "enabled"]
520034
+ options: ["off", "auto", "adaptive", "enabled"]
519179
520035
  },
519180
520036
  {
519181
520037
  key: "budgetTokens",
519182
- label: "Budget Tokens",
519183
- desc: "Token budget for enabled thinking mode",
520038
+ label: "Budget",
520039
+ desc: "Token budget when thinking = enabled",
519184
520040
  type: "budget",
519185
520041
  options: ["1024", "2048", "5000", "10000", "20000"]
519186
520042
  },
519187
- {
519188
- key: "clearThinking",
519189
- label: "Preserve Thinking",
519190
- desc: "Keep all thinking blocks across turns for better cache hits. Off = Anthropic default (only last turn kept). Requires thinking enabled.",
519191
- type: "toggle"
519192
- },
519193
520043
  {
519194
520044
  key: "effort",
519195
520045
  label: "Effort",
519196
- desc: "Reasoning depth \u2014 affects thinking, text, and tool calls",
520046
+ desc: "Reasoning depth across thinking, text, and tool calls",
519197
520047
  type: "cycle",
519198
520048
  options: ["off", "low", "medium", "high", "xhigh", "max"]
519199
520049
  },
520050
+ {
520051
+ key: "clearThinking",
520052
+ label: "Preserve thinking",
520053
+ desc: "Keep thinking blocks across turns for cache hits (requires thinking on)",
520054
+ type: "toggle"
520055
+ },
520056
+ { type: "section", label: "Performance" },
519200
520057
  {
519201
520058
  key: "speed",
519202
520059
  label: "Speed",
519203
- desc: "Opus 4.6 \u2014 2.5x faster output (standard | fast)",
520060
+ desc: "Opus 4.6 only \u2014 2.5\xD7 faster output",
519204
520061
  type: "cycle",
519205
520062
  options: ["off", "standard", "fast"]
519206
520063
  },
519207
520064
  {
519208
- key: "codeExecution",
519209
- label: "Code Execution",
519210
- desc: "Programmatic tool calling \u2014 batches reads in Python, saves tokens",
520065
+ key: "toolStreaming",
520066
+ label: "Tool streaming",
520067
+ desc: "Stream tool call args incrementally",
519211
520068
  type: "toggle"
519212
520069
  },
519213
520070
  {
519214
- key: "computerUse",
519215
- label: "Computer Use",
519216
- desc: "Keyboard/mouse/screenshot control",
520071
+ key: "sendReasoning",
520072
+ label: "Send reasoning",
520073
+ desc: "Include reasoning content in multi-turn requests",
519217
520074
  type: "toggle"
519218
520075
  },
520076
+ { type: "section", label: "Beta tools" },
519219
520077
  {
519220
- key: "anthropicTextEditor",
519221
- label: "Anthropic Text Editor",
519222
- desc: "Anthropic's str_replace editor tool",
520078
+ key: "codeExecution",
520079
+ label: "Code execution",
520080
+ desc: "Programmatic tool calling \u2014 batches reads in Python",
519223
520081
  type: "toggle"
519224
520082
  },
519225
520083
  {
519226
- key: "toolStreaming",
519227
- label: "Tool Streaming",
519228
- desc: "Stream tool call args incrementally (disable to debug)",
520084
+ key: "computerUse",
520085
+ label: "Computer use",
520086
+ desc: "Keyboard / mouse / screenshot control",
519229
520087
  type: "toggle"
519230
520088
  },
519231
520089
  {
519232
- key: "sendReasoning",
519233
- label: "Send Reasoning",
519234
- desc: "Include reasoning content in multi-turn requests",
520090
+ key: "anthropicTextEditor",
520091
+ label: "Text editor",
520092
+ desc: "Anthropic str_replace editor tool",
519235
520093
  type: "toggle"
519236
520094
  },
520095
+ { type: "section", label: "Server context" },
519237
520096
  {
519238
520097
  key: "compact",
519239
- label: "Server Compaction",
519240
- desc: "Anthropic server-side context compaction (200K+ models)",
520098
+ label: "Server compaction",
520099
+ desc: "Anthropic server-side compaction (200K+ models)",
519241
520100
  type: "toggle"
519242
520101
  },
519243
520102
  {
519244
520103
  key: "clearToolUses",
519245
- label: "Clear Tool Uses",
519246
- desc: "Server-side \u2014 clear old tool results at 65% context. \u26A0\uFE0F Busts prompt cache when triggered",
520104
+ label: "Clear old tool uses",
520105
+ desc: "Drop old tool results at 65% ctx. Busts prompt cache when it fires",
519247
520106
  type: "toggle"
519248
520107
  }
519249
520108
  ];
519250
520109
  OPENAI_ITEMS = [
520110
+ { type: "section", label: "Reasoning" },
519251
520111
  {
519252
520112
  key: "openaiReasoningEffort",
519253
- label: "Reasoning Effort",
519254
- desc: "For o3, o4, gpt-5 \u2014 controls reasoning depth",
520113
+ label: "Effort",
520114
+ desc: "o3 \xB7 o4 \xB7 gpt-5 \u2014 reasoning depth",
519255
520115
  type: "cycle",
519256
520116
  options: ["off", "none", "minimal", "low", "medium", "high", "xhigh"]
519257
520117
  },
520118
+ {
520119
+ key: "openaiReasoningSummary",
520120
+ label: "Reasoning summary",
520121
+ desc: "Include synthesized reasoning summary in the response",
520122
+ type: "cycle",
520123
+ options: ["off", "auto", "detailed"]
520124
+ },
520125
+ {
520126
+ key: "openaiVerbosity",
520127
+ label: "Verbosity",
520128
+ desc: "gpt-5+ \u2014 controls answer length",
520129
+ type: "cycle",
520130
+ options: ["off", "low", "medium", "high"]
520131
+ },
520132
+ { type: "section", label: "Service" },
519258
520133
  {
519259
520134
  key: "serviceTier",
519260
- label: "Service Tier",
519261
- desc: "flex = 50% cheaper | priority = fastest (Enterprise)",
520135
+ label: "Service tier",
520136
+ desc: "flex = 50% cheaper \xB7 priority = fastest (Enterprise)",
519262
520137
  type: "cycle",
519263
520138
  options: ["off", "auto", "default", "flex", "priority"]
519264
520139
  }
519265
520140
  ];
519266
520141
  GENERAL_ITEMS = [
520142
+ { type: "section", label: "Tools" },
519267
520143
  {
519268
520144
  key: "disableParallelToolUse",
519269
- label: "Sequential Tools",
519270
- desc: "One tool at a time instead of parallel (all providers)",
520145
+ label: "Sequential tools",
520146
+ desc: "Run tools one at a time instead of parallel (all providers)",
519271
520147
  type: "toggle"
519272
520148
  },
519273
520149
  {
519274
520150
  key: "webSearch",
519275
- label: "Web Search",
519276
- desc: "Allow web search tool",
520151
+ label: "Web search",
520152
+ desc: "Allow the web search tool",
519277
520153
  type: "toggle"
519278
520154
  },
520155
+ { type: "section", label: "Context" },
519279
520156
  {
519280
520157
  key: "pruning",
519281
- label: "Tool Result Pruning",
519282
- desc: "Client-side \u2014 compact old tool results: main | subagents | both | none",
520158
+ label: "Tool result pruning",
520159
+ desc: "Client-side \u2014 compact old tool results",
519283
520160
  type: "cycle",
519284
520161
  options: ["none", "main", "subagents", "both"]
519285
520162
  }
519286
520163
  ];
520164
+ GOOGLE_ITEMS = [
520165
+ {
520166
+ type: "info",
520167
+ text: "Gemini 3 / 3.1 use thinkingLevel \xB7 Gemini 2.5 uses thinkingBudget. Only one applies per model."
520168
+ },
520169
+ { type: "section", label: "Gemini 3+" },
520170
+ {
520171
+ key: "googleThinkingLevel",
520172
+ label: "Thinking level",
520173
+ desc: "Gemini 3 / 3.1 \u2014 depth of internal reasoning",
520174
+ type: "cycle",
520175
+ options: ["off", "minimal", "low", "medium", "high"]
520176
+ },
520177
+ { type: "section", label: "Gemini 2.5" },
520178
+ {
520179
+ key: "googleThinkingBudget",
520180
+ label: "Thinking budget",
520181
+ desc: "Token budget for Gemini 2.5 thinking. 0 = disabled",
520182
+ type: "cycle",
520183
+ options: ["off", "0", "1024", "4096", "8192", "16384", "24576"]
520184
+ },
520185
+ { type: "section", label: "Output" },
520186
+ {
520187
+ key: "googleIncludeThoughts",
520188
+ label: "Include thoughts",
520189
+ desc: "Return thought summaries in the response",
520190
+ type: "toggle"
520191
+ }
520192
+ ];
520193
+ XAI_ITEMS = [
520194
+ {
520195
+ type: "info",
520196
+ text: "Applies to: grok-3-mini \xB7 grok-4 \xB7 grok-4.1 \xB7 grok-4.20 \xB7 *-reasoning. Chat API clamps to low|high \u2014 medium auto-maps to high."
520197
+ },
520198
+ { type: "section", label: "Reasoning" },
520199
+ {
520200
+ key: "xaiReasoningEffort",
520201
+ label: "Effort",
520202
+ desc: "Chat: low/high \xB7 Responses API: low/medium/high",
520203
+ type: "cycle",
520204
+ options: ["off", "low", "medium", "high"]
520205
+ }
520206
+ ];
520207
+ DEEPSEEK_ITEMS = [
520208
+ {
520209
+ type: "info",
520210
+ text: "Applies to deepseek-chat only. deepseek-reasoner always thinks (no toggle)."
520211
+ },
520212
+ { type: "section", label: "Reasoning" },
520213
+ {
520214
+ key: "deepseekThinking",
520215
+ label: "Thinking",
520216
+ desc: "Enable chain-of-thought generation on deepseek-chat",
520217
+ type: "cycle",
520218
+ options: ["off", "enabled"]
520219
+ }
520220
+ ];
520221
+ OPENROUTER_ITEMS = [
520222
+ {
520223
+ type: "info",
520224
+ text: "Unified shape \u2014 OpenRouter maps to each upstream's native API (Anthropic budget, OpenAI effort, Gemini level). Inherits Claude budget by default."
520225
+ },
520226
+ { type: "section", label: "Unified reasoning" },
520227
+ {
520228
+ key: "openrouterReasoningEffort",
520229
+ label: "Effort",
520230
+ desc: "Mapped to upstream's native shape (Anthropic budget \xB7 OpenAI effort \xB7 Gemini level)",
520231
+ type: "cycle",
520232
+ options: ["off", "minimal", "low", "medium", "high", "xhigh", "none"]
520233
+ },
520234
+ {
520235
+ key: "openrouterReasoningMaxTokens",
520236
+ label: "Max tokens",
520237
+ desc: "Anthropic-style budget. Takes priority over Effort when set.",
520238
+ type: "cycle",
520239
+ options: ["off", "1024", "2048", "4096", "8192", "16384"]
520240
+ },
520241
+ { type: "section", label: "Output" },
520242
+ {
520243
+ key: "openrouterExcludeReasoning",
520244
+ label: "Hide reasoning",
520245
+ desc: "Model still reasons but tokens are not returned",
520246
+ type: "toggle"
520247
+ }
520248
+ ];
520249
+ COMPAT_ITEMS = [
520250
+ {
520251
+ type: "info",
520252
+ text: "Applies to: Groq \xB7 Fireworks \xB7 OpenCode Zen \xB7 OpenCode Go \xB7 LM Studio \xB7 Ollama \xB7 Copilot \xB7 GitHub Models \xB7 MiniMax \xB7 Proxy (non-Claude lane)"
520253
+ },
520254
+ { type: "section", label: "Shared effort" },
520255
+ {
520256
+ key: "compatReasoningEffort",
520257
+ label: "Effort",
520258
+ desc: "Single knob \u2014 propagates as reasoning_effort in the request body for every provider listed above.",
520259
+ type: "cycle",
520260
+ options: ["off", "low", "medium", "high", "xhigh"]
520261
+ },
520262
+ { type: "section", label: "Groq" },
520263
+ {
520264
+ type: "info",
520265
+ text: "Groq-specific overrides. qwen3 / gpt-oss / deepseek-r1 reasoning SKUs."
520266
+ },
520267
+ {
520268
+ key: "groqReasoningEffort",
520269
+ label: "Groq override",
520270
+ desc: "Takes priority over shared effort when set. qwen3 auto-maps to default.",
520271
+ type: "cycle",
520272
+ options: ["off", "low", "medium", "high"]
520273
+ },
520274
+ {
520275
+ key: "groqReasoningFormat",
520276
+ label: "Groq format",
520277
+ desc: "How reasoning appears in the Groq response payload",
520278
+ type: "cycle",
520279
+ options: ["off", "parsed", "raw", "hidden"]
520280
+ }
520281
+ ];
519287
520282
  TAB_ITEMS = {
519288
520283
  claude: CLAUDE_ITEMS,
519289
520284
  openai: OPENAI_ITEMS,
520285
+ google: GOOGLE_ITEMS,
520286
+ xai: XAI_ITEMS,
520287
+ deepseek: DEEPSEEK_ITEMS,
520288
+ openrouter: OPENROUTER_ITEMS,
520289
+ compat: COMPAT_ITEMS,
519290
520290
  general: GENERAL_ITEMS
519291
520291
  };
519292
520292
  DEFAULTS = {
@@ -519306,7 +520306,20 @@ var init_ProviderSettings = __esm(async () => {
519306
520306
  compact: false,
519307
520307
  clearToolUses: false,
519308
520308
  clearThinking: true,
519309
- pruning: "none"
520309
+ pruning: "none",
520310
+ googleThinkingLevel: "off",
520311
+ googleThinkingBudget: "off",
520312
+ googleIncludeThoughts: false,
520313
+ xaiReasoningEffort: "off",
520314
+ deepseekThinking: "off",
520315
+ openrouterReasoningEffort: "off",
520316
+ openrouterReasoningMaxTokens: "off",
520317
+ openrouterExcludeReasoning: false,
520318
+ compatReasoningEffort: "off",
520319
+ groqReasoningEffort: "off",
520320
+ openaiReasoningSummary: "off",
520321
+ openaiVerbosity: "off",
520322
+ groqReasoningFormat: "off"
519310
520323
  };
519311
520324
  });
519312
520325
 
@@ -519809,27 +520822,29 @@ function RouterSettings({
519809
520822
  for (const d3 of s2.defs) {
519810
520823
  if (d3.kind === "slot")
519811
520824
  out2.push({ kind: "slot", section: s2, def: d3 });
520825
+ else
520826
+ out2.push({ kind: "picker", section: s2, def: d3 });
519812
520827
  }
519813
520828
  }
519814
520829
  return out2;
519815
520830
  }, []);
519816
- const slotIndices = import_react140.useMemo(() => rows.map((r4, i4) => r4.kind === "slot" ? i4 : -1).filter((i4) => i4 >= 0), [rows]);
520831
+ const selectableIndices = import_react140.useMemo(() => rows.map((r4, i4) => r4.kind === "slot" || r4.kind === "picker" ? i4 : -1).filter((i4) => i4 >= 0), [rows]);
519817
520832
  const moveItem = (dir) => {
519818
- if (slotIndices.length === 0)
520833
+ if (selectableIndices.length === 0)
519819
520834
  return;
519820
- const cur = slotIndices.indexOf(cursor);
520835
+ const cur = selectableIndices.indexOf(cursor);
519821
520836
  const base = cur < 0 ? 0 : cur;
519822
- const nextPos = (base + dir + slotIndices.length) % slotIndices.length;
519823
- setCursor(slotIndices[nextPos] ?? slotIndices[0] ?? 0);
520837
+ const nextPos = (base + dir + selectableIndices.length) % selectableIndices.length;
520838
+ setCursor(selectableIndices[nextPos] ?? selectableIndices[0] ?? 0);
519824
520839
  };
519825
520840
  import_react140.useMemo(() => {
519826
- if (cursor === 0 && slotIndices.length > 0 && slotIndices[0] !== 0) {
519827
- setCursor(slotIndices[0] ?? 0);
520841
+ if (cursor === 0 && selectableIndices.length > 0 && selectableIndices[0] !== 0) {
520842
+ setCursor(selectableIndices[0] ?? 0);
519828
520843
  }
519829
- }, [cursor, slotIndices]);
520844
+ }, [cursor, selectableIndices]);
519830
520845
  const selectedRow = rows[cursor];
519831
- const selectedDef = selectedRow?.kind === "slot" ? selectedRow.def : null;
519832
- const pickerDefs = import_react140.useMemo(() => ALL_DEFS.filter((d3) => d3.kind === "picker"), []);
520846
+ const selectedSlot = selectedRow?.kind === "slot" ? selectedRow.def : null;
520847
+ const selectedPicker = selectedRow?.kind === "picker" ? selectedRow.def : null;
519833
520848
  useKeyboard((evt) => {
519834
520849
  if (!visible)
519835
520850
  return;
@@ -519846,16 +520861,28 @@ function RouterSettings({
519846
520861
  return;
519847
520862
  }
519848
520863
  if (evt.name === "return") {
519849
- if (selectedDef)
519850
- onPickSlot(selectedDef.key);
520864
+ if (selectedSlot)
520865
+ onPickSlot(selectedSlot.key);
519851
520866
  return;
519852
520867
  }
519853
520868
  if (evt.name === "d" || evt.name === "delete" || evt.name === "backspace") {
519854
- if (selectedDef)
519855
- onClearSlot(selectedDef.key);
520869
+ if (selectedSlot)
520870
+ onClearSlot(selectedSlot.key);
519856
520871
  return;
519857
520872
  }
519858
520873
  if (evt.name === "left" || evt.name === "right") {
520874
+ if (selectedPicker) {
520875
+ const cur = router2?.[selectedPicker.key];
520876
+ const curVal = typeof cur === "number" ? cur : selectedPicker.defaultValue;
520877
+ const opts = selectedPicker.options;
520878
+ const i4 = opts.indexOf(curVal);
520879
+ const base = i4 < 0 ? 0 : i4;
520880
+ const nextIdx = evt.name === "left" ? (base - 1 + opts.length) % opts.length : (base + 1) % opts.length;
520881
+ const next2 = opts[nextIdx];
520882
+ if (typeof next2 === "number" && next2 !== curVal)
520883
+ onPickerChange(selectedPicker.key, next2);
520884
+ return;
520885
+ }
519859
520886
  const sIdx = CONFIG_SCOPES.indexOf(scope);
519860
520887
  const next = evt.name === "left" ? CONFIG_SCOPES[(sIdx - 1 + CONFIG_SCOPES.length) % CONFIG_SCOPES.length] : CONFIG_SCOPES[(sIdx + 1) % CONFIG_SCOPES.length];
519861
520888
  if (next && next !== scope)
@@ -519886,7 +520913,7 @@ function RouterSettings({
519886
520913
  { key: "\u2191\u2193", label: "nav" },
519887
520914
  { key: "Enter", label: "set" },
519888
520915
  { key: "d", label: "reset" },
519889
- { key: "\u2190\u2192", label: "scope" },
520916
+ { key: "\u2190\u2192", label: selectedPicker ? "adjust" : "scope" },
519890
520917
  { key: "Esc", label: "close" }
519891
520918
  ],
519892
520919
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Section, {
@@ -519914,6 +520941,17 @@ function RouterSettings({
519914
520941
  }, `h-${idx}`, true, undefined, this);
519915
520942
  }
519916
520943
  const isSelected = idx === cursor;
520944
+ if (row.kind === "picker") {
520945
+ const cur = router2?.[row.def.key];
520946
+ const num = typeof cur === "number" ? cur : row.def.defaultValue;
520947
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SegmentedControl, {
520948
+ label: row.def.label,
520949
+ labelWidth: labelCol,
520950
+ options: row.def.options.map((o3) => ({ value: o3, label: String(o3) })),
520951
+ value: num,
520952
+ focused: isSelected
520953
+ }, `p-${idx}`, false, undefined, this);
520954
+ }
519917
520955
  const rowBg = isSelected ? t2.bgPopupHighlight : t2.bgPopup;
519918
520956
  const raw2 = router2?.[row.def.key] ?? null;
519919
520957
  const modelId = typeof raw2 === "string" ? raw2 : null;
@@ -519965,17 +521003,6 @@ function RouterSettings({
519965
521003
  })
519966
521004
  }, undefined, false, undefined, this),
519967
521005
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(VSpacer, {}, undefined, false, undefined, this),
519968
- pickerDefs.map((def) => {
519969
- const cur = router2?.[def.key];
519970
- const num = typeof cur === "number" ? cur : def.defaultValue;
519971
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SegmentedControl, {
519972
- label: def.label,
519973
- labelWidth: 14,
519974
- options: def.options.map((o3) => ({ value: o3, label: String(o3) })),
519975
- value: num
519976
- }, def.key, false, undefined, this);
519977
- }),
519978
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(VSpacer, {}, undefined, false, undefined, this),
519979
521006
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SegmentedControl, {
519980
521007
  label: "Scope",
519981
521008
  labelWidth: 14,