openfox 2.0.0-beta.7 → 2.0.0-beta.9

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.
@@ -11,7 +11,7 @@ allowedTools:
11
11
  - session_metadata:get,add,update,remove
12
12
  ---
13
13
 
14
- You are a code reviewer. Review all current changes.
14
+ You are a code reviewer. Review the **git diff** of the modified files rather than reading the full files.
15
15
  You're mostly interested in:
16
16
 
17
17
  1. **For the user (UX interaction)** — does this feel good to use? Any rough edges, confusing behavior, or unnecessary friction?
@@ -8,8 +8,8 @@ import {
8
8
  } from "./chunk-CDDMHSZF.js";
9
9
  import {
10
10
  runChatTurn
11
- } from "./chunk-DFITQ75T.js";
12
- import "./chunk-QN5ST54E.js";
11
+ } from "./chunk-C75I2KZM.js";
12
+ import "./chunk-LR5R7EEE.js";
13
13
  import "./chunk-DL6ZILAF.js";
14
14
  import "./chunk-PBGOZMVY.js";
15
15
  import "./chunk-VRGRAQDG.js";
@@ -27,7 +27,7 @@ import "./chunk-RFNEDBVO.js";
27
27
  import "./chunk-XAMAYRDA.js";
28
28
  import "./chunk-FBGWG4N6.js";
29
29
  import "./chunk-BVHFMAVN.js";
30
- import "./chunk-7FDY3EOH.js";
30
+ import "./chunk-VIIRNJDT.js";
31
31
  import {
32
32
  logger
33
33
  } from "./chunk-K44MW7JJ.js";
@@ -161,4 +161,4 @@ export {
161
161
  startChatSession,
162
162
  stopSessionExecution
163
163
  };
164
- //# sourceMappingURL=chat-handler-XIAY7O5X.js.map
164
+ //# sourceMappingURL=chat-handler-6COBLIDR.js.map
@@ -16,7 +16,7 @@ import {
16
16
  loadAllAgentsDefault,
17
17
  processEventsForConversation,
18
18
  runTopLevelAgentLoop
19
- } from "./chunk-QN5ST54E.js";
19
+ } from "./chunk-LR5R7EEE.js";
20
20
  import {
21
21
  getCurrentContextWindowId,
22
22
  getCurrentWindowMessageOptions,
@@ -317,4 +317,4 @@ export {
317
317
  runAgentTurn,
318
318
  injectWorkflowKickoffIfNeeded
319
319
  };
320
- //# sourceMappingURL=chunk-DFITQ75T.js.map
320
+ //# sourceMappingURL=chunk-C75I2KZM.js.map
@@ -2,11 +2,14 @@ import {
2
2
  clearModelCache,
3
3
  createLLMClient,
4
4
  detectModel
5
- } from "./chunk-EMJGF3A7.js";
5
+ } from "./chunk-UKTPL5ZG.js";
6
6
  import {
7
+ buildModelsUrl,
7
8
  detectBackend,
8
- getModelProfile
9
- } from "./chunk-7FDY3EOH.js";
9
+ ensureVersionPrefix,
10
+ getModelProfile,
11
+ stripVersionPrefix
12
+ } from "./chunk-VIIRNJDT.js";
10
13
  import {
11
14
  logger
12
15
  } from "./chunk-K44MW7JJ.js";
@@ -67,7 +70,7 @@ function mergeModelsWithUserOverrides(backendModels, userModels) {
67
70
  return updatedModels;
68
71
  }
69
72
  async function fetchAvailableModelsFromBackend(baseUrl, apiKey) {
70
- const url = baseUrl.includes("/v1") ? `${baseUrl}/models` : `${baseUrl}/v1/models`;
73
+ const url = buildModelsUrl(baseUrl);
71
74
  const models = await fetchModelsFromBackend(url, apiKey);
72
75
  return models.map((m) => m.id);
73
76
  }
@@ -78,7 +81,7 @@ async function fetchModelsWithContext(baseUrl, apiKey, backend) {
78
81
  return fetchOllamaModelsWithContext(baseUrl, apiKey);
79
82
  }
80
83
  const isOpenCodeGo = baseUrl.includes("opencode.ai/zen/go");
81
- const url = isOpenCodeGo ? baseUrl.replace("/zen/go", "/zen").replace(/\/v1$/, "") + "/v1/models" : baseUrl.includes("/v1") ? `${baseUrl}/models` : `${baseUrl}/v1/models`;
84
+ const url = isOpenCodeGo ? buildModelsUrl(baseUrl.replace("/zen/go", "/zen")) : buildModelsUrl(baseUrl);
82
85
  logger.info("Fetching models via /v1/models", { url });
83
86
  const models = await fetchModelsFromBackend(url, apiKey);
84
87
  if (models.length === 0) return [];
@@ -177,7 +180,7 @@ function createProviderManager(config) {
177
180
  ...config,
178
181
  llm: {
179
182
  ...config.llm,
180
- baseUrl: provider.url.includes("/v1") ? provider.url : `${provider.url}/v1`,
183
+ baseUrl: ensureVersionPrefix(provider.url),
181
184
  model,
182
185
  backend: provider.backend,
183
186
  ...provider.apiKey && { apiKey: provider.apiKey }
@@ -235,7 +238,7 @@ function createProviderManager(config) {
235
238
  const providerConfig = createConfigForProvider(provider, targetModel);
236
239
  const newClient = createLLMClient(providerConfig);
237
240
  try {
238
- const url = provider.url.includes("/v1") ? provider.url.replace("/v1", "") : provider.url;
241
+ const url = stripVersionPrefix(provider.url);
239
242
  clearModelCache(url);
240
243
  const backend = provider.backend;
241
244
  logger.info("activateProvider fetching models", { providerId, providerName: provider.name, url, backend });
@@ -355,7 +358,7 @@ function createProviderManager(config) {
355
358
  if (provider.models && provider.models.length > 0) {
356
359
  return provider.models;
357
360
  }
358
- const url = provider.url.includes("/v1") ? provider.url.replace("/v1", "") : provider.url;
361
+ const url = stripVersionPrefix(provider.url);
359
362
  const backend = provider.backend;
360
363
  return fetchModelsWithContext(url, provider.apiKey, backend);
361
364
  },
@@ -466,7 +469,7 @@ function createProviderManager(config) {
466
469
  if (!provider) {
467
470
  return { success: false, error: "Provider not found" };
468
471
  }
469
- const url = provider.url.includes("/v1") ? provider.url.replace("/v1", "") : provider.url;
472
+ const url = stripVersionPrefix(provider.url);
470
473
  const backend = provider.backend;
471
474
  logger.info("refreshProviderModels fetching models", { providerId, providerName: provider.name, url, backend });
472
475
  const modelsWithContext = await fetchModelsWithContext(url, provider.apiKey, backend);
@@ -511,4 +514,4 @@ export {
511
514
  parseDefaultModelSelection,
512
515
  createProviderManager
513
516
  };
514
- //# sourceMappingURL=chunk-IGSZUXQP.js.map
517
+ //# sourceMappingURL=chunk-DMH6JVPF.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  detectModel
3
- } from "./chunk-EMJGF3A7.js";
3
+ } from "./chunk-UKTPL5ZG.js";
4
4
  import {
5
5
  detectBackend
6
- } from "./chunk-7FDY3EOH.js";
6
+ } from "./chunk-VIIRNJDT.js";
7
7
  import {
8
8
  getGlobalConfigPath
9
9
  } from "./chunk-CQGTEGKL.js";
@@ -443,4 +443,4 @@ export {
443
443
  activateProvider,
444
444
  mergeConfigs
445
445
  };
446
- //# sourceMappingURL=chunk-2ZS2B5HW.js.map
446
+ //# sourceMappingURL=chunk-EZUR7OEP.js.map
@@ -3,7 +3,7 @@ import {
3
3
  injectWorkflowKickoffIfNeeded,
4
4
  runAgentTurn,
5
5
  runChatTurn
6
- } from "./chunk-DFITQ75T.js";
6
+ } from "./chunk-C75I2KZM.js";
7
7
  import {
8
8
  COMPACTION_PROMPT,
9
9
  TurnMetrics,
@@ -59,7 +59,7 @@ import {
59
59
  skillExists,
60
60
  spawnShellProcess,
61
61
  streamLLMPure
62
- } from "./chunk-QN5ST54E.js";
62
+ } from "./chunk-LR5R7EEE.js";
63
63
  import {
64
64
  getPathSeparator,
65
65
  getPlatformShell,
@@ -133,19 +133,20 @@ import {
133
133
  import {
134
134
  createProviderManager,
135
135
  parseDefaultModelSelection
136
- } from "./chunk-IGSZUXQP.js";
136
+ } from "./chunk-DMH6JVPF.js";
137
137
  import {
138
138
  SessionNotFoundError,
139
139
  createLLMClient,
140
140
  detectModel,
141
141
  getLlmStatus
142
- } from "./chunk-EMJGF3A7.js";
142
+ } from "./chunk-UKTPL5ZG.js";
143
143
  import {
144
144
  detectBackend,
145
+ ensureVersionPrefix,
145
146
  getBackendDisplayName,
146
147
  getModelProfile,
147
148
  modelSupportsVision
148
- } from "./chunk-7FDY3EOH.js";
149
+ } from "./chunk-VIIRNJDT.js";
149
150
  import {
150
151
  logger,
151
152
  setLogLevel
@@ -2843,7 +2844,7 @@ function createWebSocketServer(httpServer, config4, getLLMClient, getActiveProvi
2843
2844
  sessionLLMClients.delete(sessionId);
2844
2845
  return getLLMClient();
2845
2846
  }
2846
- const baseUrl = provider.url.includes("/v1") ? provider.url : `${provider.url}/v1`;
2847
+ const baseUrl = ensureVersionPrefix(provider.url);
2847
2848
  const sessionConfig = {
2848
2849
  ...config4,
2849
2850
  llm: {
@@ -5830,7 +5831,7 @@ import { Router as Router6 } from "express";
5830
5831
  import { spawn as spawn5 } from "child_process";
5831
5832
 
5832
5833
  // src/constants.ts
5833
- var VERSION = "2.0.0-beta.7";
5834
+ var VERSION = "2.0.0-beta.9";
5834
5835
 
5835
5836
  // src/server/routes/auto-update.ts
5836
5837
  var updateInProgress = false;
@@ -6209,7 +6210,7 @@ async function createServerHandle(config4) {
6209
6210
  return res.status(400).json({ error: "providerId is required" });
6210
6211
  }
6211
6212
  sessionManager.setSessionProvider(sessionId, providerId, model ?? "auto");
6212
- const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-QUT7YZQ7.js");
6213
+ const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-TDVA7MQN.js");
6213
6214
  const globalConfig = await loadGlobalConfig(config4.mode ?? "production");
6214
6215
  const updatedConfig = setDefaultModelSelection(globalConfig, providerId, model ?? "auto");
6215
6216
  await saveGlobalConfig(config4.mode ?? "production", updatedConfig);
@@ -6297,7 +6298,7 @@ async function createServerHandle(config4) {
6297
6298
  if (!callId || approved === void 0) {
6298
6299
  return res.status(400).json({ error: "callId and approved are required" });
6299
6300
  }
6300
- const { providePathConfirmation } = await import("./tools-SDXWIYSA.js");
6301
+ const { providePathConfirmation } = await import("./tools-CQGEU3JK.js");
6301
6302
  const result = providePathConfirmation(callId, approved, alwaysAllow);
6302
6303
  if (!result.found) {
6303
6304
  return res.status(404).json({ error: "No pending path confirmation with that ID" });
@@ -6321,7 +6322,7 @@ async function createServerHandle(config4) {
6321
6322
  if (!callId || !answer) {
6322
6323
  return res.status(400).json({ error: "callId and answer are required" });
6323
6324
  }
6324
- const { provideAnswer: provideAnswer2 } = await import("./tools-SDXWIYSA.js");
6325
+ const { provideAnswer: provideAnswer2 } = await import("./tools-CQGEU3JK.js");
6325
6326
  const found = provideAnswer2(callId, answer);
6326
6327
  if (!found) {
6327
6328
  return res.status(404).json({ error: "No pending question with that ID" });
@@ -6357,8 +6358,8 @@ async function createServerHandle(config4) {
6357
6358
  if (!session) {
6358
6359
  return res.status(404).json({ error: "Session not found" });
6359
6360
  }
6360
- const { stopSessionExecution } = await import("./chat-handler-XIAY7O5X.js");
6361
- const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-SDXWIYSA.js");
6361
+ const { stopSessionExecution } = await import("./chat-handler-6COBLIDR.js");
6362
+ const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-CQGEU3JK.js");
6362
6363
  stopSessionExecution(sessionId, sessionManager);
6363
6364
  abortSession(sessionId);
6364
6365
  cancelQuestionsForSession(sessionId, "Session stopped by user");
@@ -6468,7 +6469,7 @@ async function createServerHandle(config4) {
6468
6469
  let visionFallback;
6469
6470
  let globalWorkdir;
6470
6471
  try {
6471
- const { loadGlobalConfig, getVisionFallback } = await import("./config-QUT7YZQ7.js");
6472
+ const { loadGlobalConfig, getVisionFallback } = await import("./config-TDVA7MQN.js");
6472
6473
  const globalConfig = await loadGlobalConfig(config4.mode ?? "production");
6473
6474
  const fallback = getVisionFallback(globalConfig);
6474
6475
  if (fallback) {
@@ -6547,7 +6548,7 @@ async function createServerHandle(config4) {
6547
6548
  return res.status(400).json({ error: "name, url, and backend are required" });
6548
6549
  }
6549
6550
  try {
6550
- const { loadGlobalConfig, saveGlobalConfig, addProvider, setDefaultModelSelection } = await import("./config-QUT7YZQ7.js");
6551
+ const { loadGlobalConfig, saveGlobalConfig, addProvider, setDefaultModelSelection } = await import("./config-TDVA7MQN.js");
6551
6552
  const globalConfig = await loadGlobalConfig(config4.mode ?? "production");
6552
6553
  const providerBackend = backend;
6553
6554
  const configWithProvider = addProvider(globalConfig, {
@@ -6581,7 +6582,7 @@ async function createServerHandle(config4) {
6581
6582
  app.post("/api/init/config", async (req, res) => {
6582
6583
  const { workdir, visionFallback } = req.body;
6583
6584
  try {
6584
- const { loadGlobalConfig, saveGlobalConfig } = await import("./config-QUT7YZQ7.js");
6585
+ const { loadGlobalConfig, saveGlobalConfig } = await import("./config-TDVA7MQN.js");
6585
6586
  const globalConfig = await loadGlobalConfig(config4.mode ?? "production");
6586
6587
  const updatedConfig = {
6587
6588
  ...globalConfig,
@@ -6609,7 +6610,7 @@ async function createServerHandle(config4) {
6609
6610
  });
6610
6611
  app.delete("/api/providers/:id", async (req, res) => {
6611
6612
  const { id } = req.params;
6612
- const { loadGlobalConfig, saveGlobalConfig, removeProvider } = await import("./config-QUT7YZQ7.js");
6613
+ const { loadGlobalConfig, saveGlobalConfig, removeProvider } = await import("./config-TDVA7MQN.js");
6613
6614
  const globalConfig = await loadGlobalConfig(config4.mode ?? "production");
6614
6615
  const updatedConfig = removeProvider(globalConfig, id);
6615
6616
  await saveGlobalConfig(config4.mode ?? "production", updatedConfig);
@@ -6620,7 +6621,7 @@ async function createServerHandle(config4) {
6620
6621
  const { id } = req.params;
6621
6622
  const { isLocal } = req.body;
6622
6623
  try {
6623
- const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-QUT7YZQ7.js");
6624
+ const { loadGlobalConfig, saveGlobalConfig, updateProvider } = await import("./config-TDVA7MQN.js");
6624
6625
  const globalConfig = await loadGlobalConfig(config4.mode ?? "production");
6625
6626
  const provider = globalConfig.providers.find((p) => p.id === id);
6626
6627
  if (!provider) {
@@ -6649,7 +6650,7 @@ async function createServerHandle(config4) {
6649
6650
  return res.status(400).json({ error: result.error });
6650
6651
  }
6651
6652
  const llmClient = getLLMClient();
6652
- const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-QUT7YZQ7.js");
6653
+ const { loadGlobalConfig, saveGlobalConfig, setDefaultModelSelection } = await import("./config-TDVA7MQN.js");
6653
6654
  const globalConfig = await loadGlobalConfig(config4.mode ?? "production");
6654
6655
  const updatedConfig = setDefaultModelSelection(globalConfig, id, llmClient.getModel());
6655
6656
  await saveGlobalConfig(config4.mode ?? "production", updatedConfig);
@@ -6680,7 +6681,7 @@ async function createServerHandle(config4) {
6680
6681
  if (!result.success) {
6681
6682
  return res.status(400).json({ error: result.error });
6682
6683
  }
6683
- const { loadGlobalConfig, saveGlobalConfig } = await import("./config-QUT7YZQ7.js");
6684
+ const { loadGlobalConfig, saveGlobalConfig } = await import("./config-TDVA7MQN.js");
6684
6685
  const globalConfig = await loadGlobalConfig(config4.mode ?? "production");
6685
6686
  const updatedProviders = providerManager.getProviders();
6686
6687
  const updatedConfig = {
@@ -6894,7 +6895,7 @@ async function createServerHandle(config4) {
6894
6895
  providerManager
6895
6896
  );
6896
6897
  const wss = wssExports.wss;
6897
- const { QueueProcessor } = await import("./processor-6VIYGURD.js");
6898
+ const { QueueProcessor } = await import("./processor-WMAU4C2N.js");
6898
6899
  const queueProcessor = new QueueProcessor({
6899
6900
  sessionManager,
6900
6901
  providerManager,
@@ -6966,4 +6967,4 @@ export {
6966
6967
  createServerHandle,
6967
6968
  createServer
6968
6969
  };
6969
- //# sourceMappingURL=chunk-LN22TXNK.js.map
6970
+ //# sourceMappingURL=chunk-J2FFLZ5Z.js.map
@@ -33,7 +33,7 @@ Options:
33
33
  }
34
34
  async function runNetworkSetup(mode) {
35
35
  const { loadAuthConfig, saveAuthConfig, encryptPassword } = await import("./auth-56SIRACI.js");
36
- const { saveGlobalConfig } = await import("./config-QUT7YZQ7.js");
36
+ const { saveGlobalConfig } = await import("./config-TDVA7MQN.js");
37
37
  const { getAuthKeyPath } = await import("./paths-X46PPOI2.js");
38
38
  const existingAuth = await loadAuthConfig(mode);
39
39
  if (existingAuth) {
@@ -94,7 +94,7 @@ async function runNetworkSetup(mode) {
94
94
  console.log("\u2713 Configuration saved!\n");
95
95
  }
96
96
  async function runConfig(mode) {
97
- const { loadGlobalConfig, getActiveProvider, getDefaultModel } = await import("./config-QUT7YZQ7.js");
97
+ const { loadGlobalConfig, getActiveProvider, getDefaultModel } = await import("./config-TDVA7MQN.js");
98
98
  const { getGlobalConfigPath } = await import("./paths-X46PPOI2.js");
99
99
  const config = await loadGlobalConfig(mode);
100
100
  const configPath = getGlobalConfigPath(mode);
@@ -151,7 +151,7 @@ async function runCli(options) {
151
151
  break;
152
152
  }
153
153
  case "provider": {
154
- const { runProviderCommand } = await import("./provider-4T6BVPMD.js");
154
+ const { runProviderCommand } = await import("./provider-BGH4MBLH.js");
155
155
  const [, subcommand] = positionals;
156
156
  await runProviderCommand(mode, subcommand);
157
157
  break;
@@ -188,12 +188,12 @@ async function runCli(options) {
188
188
  break;
189
189
  }
190
190
  default: {
191
- const { configFileExists } = await import("./config-QUT7YZQ7.js");
191
+ const { configFileExists } = await import("./config-TDVA7MQN.js");
192
192
  const configExists = await configFileExists(mode);
193
193
  if (!configExists) {
194
194
  await runNetworkSetup(mode);
195
195
  }
196
- const { runServe } = await import("./serve-W3ETJJP3.js");
196
+ const { runServe } = await import("./serve-N3LBZUVN.js");
197
197
  const serveOptions = { mode };
198
198
  if (values.port) serveOptions.port = parseInt(values.port);
199
199
  if (values["no-browser"] === true) serveOptions.openBrowser = false;
@@ -205,4 +205,4 @@ async function runCli(options) {
205
205
  export {
206
206
  runCli
207
207
  };
208
- //# sourceMappingURL=chunk-KAYUPVHQ.js.map
208
+ //# sourceMappingURL=chunk-KUG27ZUR.js.map
@@ -54,7 +54,7 @@ import {
54
54
  getModelProfile,
55
55
  modelSupportsVision,
56
56
  streamWithSegments
57
- } from "./chunk-7FDY3EOH.js";
57
+ } from "./chunk-VIIRNJDT.js";
58
58
  import {
59
59
  logger
60
60
  } from "./chunk-K44MW7JJ.js";
@@ -954,6 +954,21 @@ function buildRegion(edits, contextStart, contextEnd, lines) {
954
954
  }
955
955
 
956
956
  // src/server/tools/edit.ts
957
+ var fileLocks = /* @__PURE__ */ new Map();
958
+ async function withFileLock(filePath, fn) {
959
+ const prev = fileLocks.get(filePath) ?? Promise.resolve();
960
+ const next = prev.then(fn, fn);
961
+ fileLocks.set(
962
+ filePath,
963
+ next.then(
964
+ () => {
965
+ },
966
+ () => {
967
+ }
968
+ )
969
+ );
970
+ return next;
971
+ }
957
972
  function detectLineEnding(content) {
958
973
  if (content.includes("\r\n")) return "crlf";
959
974
  if (content.includes("\n")) return "lf";
@@ -995,95 +1010,97 @@ var editFileTool = createTool(
995
1010
  }
996
1011
  },
997
1012
  async (args, context, helpers) => {
998
- const replaceAll = args.replace_all ?? false;
999
1013
  const fullPath = helpers.resolvePath(args.path);
1000
1014
  await helpers.checkPathAccess([fullPath]);
1001
- const readFiles = context.sessionManager.getReadFiles(context.sessionId);
1002
- const validation = await validateFileForWrite(fullPath, readFiles);
1003
- if (!validation.valid) {
1004
- return helpers.error(validation.error?.message ?? "File validation failed");
1005
- }
1006
- let content;
1007
- try {
1008
- content = await readFile3(fullPath, "utf-8");
1009
- } catch {
1010
- return helpers.error(`File not found: ${args.path}`);
1011
- }
1012
- const fileLineEnding = detectLineEnding(content);
1013
- const normalizedContent = normalizeToLF(content);
1014
- const normalizedOldString = normalizeToLF(args.old_string);
1015
- const occurrences = normalizedContent.split(normalizedOldString).length - 1;
1016
- if (occurrences === 0) {
1017
- const preview = args.old_string.length > 100 ? args.old_string.slice(0, 100) + "..." : args.old_string;
1018
- return helpers.error(
1019
- `old_string not found in file.
1015
+ return withFileLock(fullPath, async () => {
1016
+ const replaceAll = args.replace_all ?? false;
1017
+ const readFiles = context.sessionManager.getReadFiles(context.sessionId);
1018
+ const validation = await validateFileForWrite(fullPath, readFiles);
1019
+ if (!validation.valid) {
1020
+ return helpers.error(validation.error?.message ?? "File validation failed");
1021
+ }
1022
+ let content;
1023
+ try {
1024
+ content = await readFile3(fullPath, "utf-8");
1025
+ } catch {
1026
+ return helpers.error(`File not found: ${args.path}`);
1027
+ }
1028
+ const fileLineEnding = detectLineEnding(content);
1029
+ const normalizedContent = normalizeToLF(content);
1030
+ const normalizedOldString = normalizeToLF(args.old_string);
1031
+ const occurrences = normalizedContent.split(normalizedOldString).length - 1;
1032
+ if (occurrences === 0) {
1033
+ const preview = args.old_string.length > 100 ? args.old_string.slice(0, 100) + "..." : args.old_string;
1034
+ return helpers.error(
1035
+ `old_string not found in file.
1020
1036
 
1021
1037
  Searched for:
1022
1038
  ${preview}
1023
1039
 
1024
1040
  Make sure whitespace and indentation match exactly.`
1041
+ );
1042
+ }
1043
+ if (occurrences > 1 && !replaceAll) {
1044
+ return helpers.error(
1045
+ `Found ${occurrences} matches for old_string. Use replace_all: true to replace all, or provide more context to make the match unique.`
1046
+ );
1047
+ }
1048
+ const contextResult = extractEditContext(
1049
+ normalizedContent,
1050
+ normalizedOldString,
1051
+ normalizeToLF(args.new_string),
1052
+ replaceAll
1025
1053
  );
1026
- }
1027
- if (occurrences > 1 && !replaceAll) {
1028
- return helpers.error(
1029
- `Found ${occurrences} matches for old_string. Use replace_all: true to replace all, or provide more context to make the match unique.`
1054
+ const editContextRegions = contextResult.regions.map((region) => ({
1055
+ beforeContext: region.beforeContext.map((line) => ({
1056
+ lineNumber: line.lineNumber,
1057
+ content: line.content
1058
+ })),
1059
+ afterContext: region.afterContext.map((line) => ({
1060
+ lineNumber: line.lineNumber,
1061
+ content: line.content
1062
+ })),
1063
+ startLine: region.startLine,
1064
+ endLine: region.endLine,
1065
+ oldContent: region.oldContent,
1066
+ newContent: region.newContent,
1067
+ edits: region.edits.map((edit) => ({
1068
+ startLine: edit.startLine,
1069
+ endLine: edit.endLine,
1070
+ oldContent: edit.oldContent,
1071
+ newContent: edit.newContent
1072
+ }))
1073
+ }));
1074
+ const normalizedNewString = normalizeToLF(args.new_string);
1075
+ let replacedContent;
1076
+ if (replaceAll) {
1077
+ replacedContent = normalizedContent.replaceAll(normalizedOldString, normalizedNewString);
1078
+ } else {
1079
+ const index = normalizedContent.indexOf(normalizedOldString);
1080
+ if (index === -1) {
1081
+ return helpers.error("old_string not found in file (unexpected)");
1082
+ }
1083
+ replacedContent = normalizedContent.slice(0, index) + normalizedNewString + normalizedContent.slice(index + normalizedOldString.length);
1084
+ }
1085
+ const newContent = replacedContent.replace(
1086
+ /\n/g,
1087
+ fileLineEnding === "crlf" ? "\r\n" : fileLineEnding === "cr" ? "\r" : "\n"
1030
1088
  );
1031
- }
1032
- const contextResult = extractEditContext(
1033
- normalizedContent,
1034
- normalizedOldString,
1035
- normalizeToLF(args.new_string),
1036
- replaceAll
1037
- );
1038
- const editContextRegions = contextResult.regions.map((region) => ({
1039
- beforeContext: region.beforeContext.map((line) => ({
1040
- lineNumber: line.lineNumber,
1041
- content: line.content
1042
- })),
1043
- afterContext: region.afterContext.map((line) => ({
1044
- lineNumber: line.lineNumber,
1045
- content: line.content
1046
- })),
1047
- startLine: region.startLine,
1048
- endLine: region.endLine,
1049
- oldContent: region.oldContent,
1050
- newContent: region.newContent,
1051
- edits: region.edits.map((edit) => ({
1052
- startLine: edit.startLine,
1053
- endLine: edit.endLine,
1054
- oldContent: edit.oldContent,
1055
- newContent: edit.newContent
1056
- }))
1057
- }));
1058
- const normalizedNewString = normalizeToLF(args.new_string);
1059
- let replacedContent;
1060
- if (replaceAll) {
1061
- replacedContent = normalizedContent.replaceAll(normalizedOldString, normalizedNewString);
1062
- } else {
1063
- const index = normalizedContent.indexOf(normalizedOldString);
1064
- if (index === -1) {
1065
- return helpers.error("old_string not found in file (unexpected)");
1089
+ await writeFile2(fullPath, newContent, "utf-8");
1090
+ let output = `Successfully replaced ${replaceAll ? occurrences : 1} occurrence(s) in ${args.path}`;
1091
+ let diagnostics = [];
1092
+ if (context.lspManager) {
1093
+ diagnostics = await context.lspManager.notifyFileChange(fullPath, newContent);
1094
+ output += formatDiagnosticsForLLM(diagnostics);
1066
1095
  }
1067
- replacedContent = normalizedContent.slice(0, index) + normalizedNewString + normalizedContent.slice(index + normalizedOldString.length);
1068
- }
1069
- const newContent = replacedContent.replace(
1070
- /\n/g,
1071
- fileLineEnding === "crlf" ? "\r\n" : fileLineEnding === "cr" ? "\r" : "\n"
1072
- );
1073
- await writeFile2(fullPath, newContent, "utf-8");
1074
- let output = `Successfully replaced ${replaceAll ? occurrences : 1} occurrence(s) in ${args.path}`;
1075
- let diagnostics = [];
1076
- if (context.lspManager) {
1077
- diagnostics = await context.lspManager.notifyFileChange(fullPath, newContent);
1078
- output += formatDiagnosticsForLLM(diagnostics);
1079
- }
1080
- const newHash = await computeFileHash(fullPath);
1081
- if (newHash) {
1082
- context.sessionManager.updateFileHash(context.sessionId, fullPath, newHash);
1083
- }
1084
- return helpers.success(output, false, {
1085
- ...diagnostics.length > 0 && { diagnostics },
1086
- ...editContextRegions.length > 0 && { editContext: { regions: editContextRegions } }
1096
+ const newHash = await computeFileHash(fullPath);
1097
+ if (newHash) {
1098
+ context.sessionManager.updateFileHash(context.sessionId, fullPath, newHash);
1099
+ }
1100
+ return helpers.success(output, false, {
1101
+ ...diagnostics.length > 0 && { diagnostics },
1102
+ ...editContextRegions.length > 0 && { editContext: { regions: editContextRegions } }
1103
+ });
1087
1104
  });
1088
1105
  }
1089
1106
  );
@@ -3259,7 +3276,7 @@ async function describeImageFromDataUrl(dataUrl, visionModel, options) {
3259
3276
  import { createHash as createHash2 } from "crypto";
3260
3277
  async function loadVisionModelFromGlobalConfig() {
3261
3278
  try {
3262
- const { loadGlobalConfig, getVisionFallback } = await import("./config-QUT7YZQ7.js");
3279
+ const { loadGlobalConfig, getVisionFallback } = await import("./config-TDVA7MQN.js");
3263
3280
  const runtimeConfig = getRuntimeConfig();
3264
3281
  const mode = runtimeConfig.mode ?? "production";
3265
3282
  const globalConfig = await loadGlobalConfig(mode);
@@ -3713,7 +3730,7 @@ var callSubAgentTool = {
3713
3730
  };
3714
3731
  }
3715
3732
  try {
3716
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-SDXWIYSA.js");
3733
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-CQGEU3JK.js");
3717
3734
  const toolRegistry = getToolRegistryForAgent2(agentDef);
3718
3735
  const turnMetrics = new TurnMetrics();
3719
3736
  const result = await executeSubAgent({
@@ -4764,4 +4781,4 @@ export {
4764
4781
  getToolRegistryForAgent,
4765
4782
  createToolRegistry
4766
4783
  };
4767
- //# sourceMappingURL=chunk-QN5ST54E.js.map
4784
+ //# sourceMappingURL=chunk-LR5R7EEE.js.map
@@ -1,11 +1,14 @@
1
1
  import {
2
+ buildModelsUrl,
2
3
  buildNonStreamingCreateParams,
3
4
  buildStreamingCreateParams,
5
+ ensureVersionPrefix,
4
6
  extractThinking,
5
7
  getBackendCapabilities,
6
8
  getModelProfile,
7
- mapFinishReason
8
- } from "./chunk-7FDY3EOH.js";
9
+ mapFinishReason,
10
+ stripVersionPrefix
11
+ } from "./chunk-VIIRNJDT.js";
9
12
  import {
10
13
  logger
11
14
  } from "./chunk-K44MW7JJ.js";
@@ -16,7 +19,7 @@ var llmStatus = "unknown";
16
19
  var lastActiveUrl = null;
17
20
  var CACHE_TTL_MS = 3e4;
18
21
  function getCacheKey(url) {
19
- return url.replace(/\/v1\/?$/, "");
22
+ return stripVersionPrefix(url);
20
23
  }
21
24
  async function detectModel(llmBaseUrl, retries = 3, silent = false) {
22
25
  const cacheKey = getCacheKey(llmBaseUrl);
@@ -27,7 +30,7 @@ async function detectModel(llmBaseUrl, retries = 3, silent = false) {
27
30
  llmStatus = "connected";
28
31
  return cached.model;
29
32
  }
30
- const url = llmBaseUrl.includes("/v1") ? `${llmBaseUrl}/models` : `${llmBaseUrl}/v1/models`;
33
+ const url = buildModelsUrl(llmBaseUrl);
31
34
  for (let attempt = 1; attempt <= retries; attempt++) {
32
35
  try {
33
36
  if (silent) {
@@ -137,7 +140,7 @@ var LLMError = class extends OpenFoxError {
137
140
 
138
141
  // src/server/llm/client.ts
139
142
  function createLLMClient(config, initialBackend = "unknown") {
140
- const baseURL = config.llm.baseUrl.includes("/v1") ? config.llm.baseUrl : `${config.llm.baseUrl}/v1`;
143
+ const baseURL = ensureVersionPrefix(config.llm.baseUrl);
141
144
  const openai = new OpenAI({
142
145
  baseURL,
143
146
  apiKey: config.llm.apiKey ?? "not-needed"
@@ -463,4 +466,4 @@ export {
463
466
  getLlmStatus,
464
467
  clearModelCache
465
468
  };
466
- //# sourceMappingURL=chunk-EMJGF3A7.js.map
469
+ //# sourceMappingURL=chunk-UKTPL5ZG.js.map