openfox 2.0.24 → 2.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/auto-config-FZFXOEEG.js +169 -0
  2. package/dist/backend-AGXWAU7A.js +9 -0
  3. package/dist/{chat-handler-4ATHDLH4.js → chat-handler-C4HZJNUN.js} +28 -47
  4. package/dist/{chunk-QK6TYNUN.js → chunk-7H4PYZMT.js} +6 -6
  5. package/dist/{chunk-RYHCYZQ7.js → chunk-DW55I7SI.js} +26 -24
  6. package/dist/{chunk-YVF3BLQS.js → chunk-GBUP7UDI.js} +36 -22
  7. package/dist/chunk-HNCM3D7Y.js +28 -0
  8. package/dist/chunk-IEDE6VK4.js +124 -0
  9. package/dist/chunk-J2GP3J3X.js +97 -0
  10. package/dist/{chunk-MDRNKI7D.js → chunk-K454WU7A.js} +62 -49
  11. package/dist/chunk-M3RB4IF6.js +114 -0
  12. package/dist/{chunk-XJ4SUDL7.js → chunk-QYP6MOB5.js} +33 -242
  13. package/dist/chunk-V4IE7HJY.js +175 -0
  14. package/dist/{chunk-GI24G4OW.js → chunk-VI236SOY.js} +79 -59
  15. package/dist/{chunk-CDIYCGCO.js → chunk-WEXW7ZXJ.js} +2 -2
  16. package/dist/{chunk-INRKWEOH.js → chunk-YBPRGUAE.js} +116 -65
  17. package/dist/{chunk-YUHODMKY.js → chunk-YGSBVKFU.js} +11 -5
  18. package/dist/{chunk-4EDH3ZXL.js → chunk-YRRUHP4T.js} +3 -3
  19. package/dist/chunk-Z4FMBCJO.js +52 -0
  20. package/dist/chunk-ZJ4FP6RS.js +200 -0
  21. package/dist/cli/dev.js +1 -1
  22. package/dist/cli/index.js +1 -1
  23. package/dist/client-X6BVH4Q4.js +13 -0
  24. package/dist/client-pure-5NOTSIRK.js +19 -0
  25. package/dist/{compactor-SEZEZSML.js → compactor-JMGSZ4DQ.js} +7 -4
  26. package/dist/http-client-SIPAW7IM.js +8 -0
  27. package/dist/{orchestrator-MFN7COWT.js → orchestrator-HZX3IETX.js} +16 -13
  28. package/dist/package.json +1 -1
  29. package/dist/{processor-W2ZSJVOJ.js → processor-AX2QQWUX.js} +30 -55
  30. package/dist/profiles-Q36ELWQF.js +9 -0
  31. package/dist/{provider-IMW3ITB7.js → provider-XRTIWMB6.js} +15 -9
  32. package/dist/provider-manager-4H4VGNYA.js +22 -0
  33. package/dist/{serve-ABSUHKT3.js → serve-NVFK3XHF.js} +23 -17
  34. package/dist/server/index.d.ts +9 -1
  35. package/dist/server/index.js +19 -13
  36. package/dist/{server-7EAYI7T4.js → server-7MFV467L.js} +18 -12
  37. package/dist/{tools-7CKTYL2G.js → tools-4KGLCQJL.js} +11 -8
  38. package/dist/url-utils-QWAHP54Q.js +15 -0
  39. package/dist/web/assets/{index-CkUCxzzC.css → index-BLOGpuPE.css} +1 -1
  40. package/dist/web/assets/{index-Bi5R_oF2.js → index-CtG8oo36.js} +66 -66
  41. package/dist/web/index.html +2 -2
  42. package/dist/web/sw.js +1 -1
  43. package/package.json +1 -1
  44. package/dist/chunk-UUFEE7VR.js +0 -505
  45. package/dist/provider-manager-DNBMBP4D.js +0 -16
@@ -0,0 +1,169 @@
1
+ import {
2
+ ensureVersionPrefix
3
+ } from "./chunk-HNCM3D7Y.js";
4
+ import {
5
+ logger
6
+ } from "./chunk-K44MW7JJ.js";
7
+
8
+ // src/server/providers/auto-config.ts
9
+ var NON_THINKING_COMBOS = [
10
+ {},
11
+ { reasoning_effort: "none" },
12
+ { chat_template_kwargs: { enable_thinking: false } },
13
+ { thinking: { type: "disabled" } },
14
+ { reasoning_effort: "none", chat_template_kwargs: { enable_thinking: false } }
15
+ ];
16
+ var THINKING_COMBOS = [
17
+ { reasoning_effort: "high" },
18
+ { chat_template_kwargs: { enable_thinking: true } },
19
+ { thinking: { type: "enabled" } },
20
+ { reasoning_effort: "high", thinking: { type: "enabled" } }
21
+ ];
22
+ async function detectModelInfo(baseUrl, apiKey, backend, modelId) {
23
+ if (backend === "unknown") {
24
+ const known = {
25
+ "deepseek-v4-flash": { ctx: 1e6, vision: false },
26
+ "deepseek-v4-pro": { ctx: 1e6, vision: false },
27
+ "glm-5.2": { ctx: 1e6, vision: false },
28
+ "glm-5.1": { ctx: 1e6, vision: false },
29
+ "glm-5": { ctx: 1e6, vision: false },
30
+ "glm-5-turbo": { ctx: 1e6, vision: false },
31
+ "glm-4.7": { ctx: 128e3, vision: false },
32
+ "glm-4.6": { ctx: 128e3, vision: false },
33
+ "glm-4.5": { ctx: 128e3, vision: false },
34
+ "glm-4-32b-0414-128k": { ctx: 128e3, vision: false }
35
+ };
36
+ const knownVal = known[modelId];
37
+ if (knownVal) return { contextWindow: knownVal.ctx, source: "hardcoded", supportsVision: knownVal.vision };
38
+ }
39
+ try {
40
+ if (backend === "ollama") {
41
+ return await detectOllamaInfo(baseUrl, modelId);
42
+ }
43
+ if (backend === "llamacpp") {
44
+ return await detectLlamacppInfo(baseUrl);
45
+ }
46
+ return await detectVllmInfo(baseUrl, apiKey, modelId);
47
+ } catch {
48
+ return { contextWindow: 2e5, source: "default", supportsVision: false };
49
+ }
50
+ }
51
+ async function detectVllmInfo(baseUrl, apiKey, modelId) {
52
+ const headers = { "Content-Type": "application/json" };
53
+ if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
54
+ const response = await fetch(`${ensureVersionPrefix(baseUrl)}/models`, { headers, signal: AbortSignal.timeout(5e3) });
55
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
56
+ const data = await response.json();
57
+ const model = data.data?.find((m) => m.id === modelId);
58
+ if (model?.max_model_len) {
59
+ return { contextWindow: model.max_model_len, source: "backend", supportsVision: false };
60
+ }
61
+ throw new Error("No context window in response");
62
+ }
63
+ async function detectLlamacppInfo(baseUrl) {
64
+ const response = await fetch(`${baseUrl}/props`, { signal: AbortSignal.timeout(5e3) });
65
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
66
+ const data = await response.json();
67
+ const nCtx = data.default_generation_settings?.n_ctx;
68
+ const supportsVision = data.modalities?.vision ?? false;
69
+ if (nCtx) {
70
+ return { contextWindow: nCtx, source: "backend", supportsVision };
71
+ }
72
+ throw new Error("No n_ctx in props");
73
+ }
74
+ async function detectOllamaInfo(baseUrl, modelId) {
75
+ const response = await fetch(`${baseUrl}/api/show`, {
76
+ method: "POST",
77
+ headers: { "Content-Type": "application/json" },
78
+ body: JSON.stringify({ name: modelId }),
79
+ signal: AbortSignal.timeout(5e3)
80
+ });
81
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
82
+ const data = await response.json();
83
+ const mi = data.model_info ?? {};
84
+ const ctxKey = Object.keys(mi).find((k) => k.endsWith(".context_length") || k === "context_length");
85
+ const ctxLen = ctxKey ? Number(mi[ctxKey]) : void 0;
86
+ const supportsVision = !!mi["vision_start_token_id"] || Object.keys(mi).some((k) => k.includes(".vision."));
87
+ if (ctxLen && !isNaN(ctxLen)) {
88
+ return { contextWindow: ctxLen, source: "backend", supportsVision };
89
+ }
90
+ throw new Error("No context_length in model_info");
91
+ }
92
+ async function probeCombo(baseUrl, apiKey, model, combo, signal) {
93
+ const headers = { "Content-Type": "application/json" };
94
+ if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
95
+ const body = {
96
+ model,
97
+ messages: [{ role: "user", content: "say hi in one word" }],
98
+ max_tokens: 50,
99
+ ...combo
100
+ };
101
+ const start = Date.now();
102
+ try {
103
+ const response = await fetch(`${ensureVersionPrefix(baseUrl)}/chat/completions`, {
104
+ method: "POST",
105
+ headers,
106
+ body: JSON.stringify(body),
107
+ signal
108
+ });
109
+ const durationMs = Date.now() - start;
110
+ if (!response.ok) {
111
+ return { combo, httpCode: response.status, hasContent: false, durationMs };
112
+ }
113
+ const data = await response.json();
114
+ const message = data.choices?.[0]?.message ?? {};
115
+ const hasContent = !!(message["content"] || message["reasoning"] || message["reasoning_content"] || message["thinking"]);
116
+ return { combo, httpCode: response.status, hasContent, durationMs };
117
+ } catch {
118
+ const durationMs = Date.now() - start;
119
+ return { combo, httpCode: 0, hasContent: false, durationMs };
120
+ }
121
+ }
122
+ async function probeCombos(baseUrl, apiKey, model, combos) {
123
+ const timeout = AbortSignal.timeout(15e3);
124
+ const results = await Promise.allSettled(combos.map((combo) => probeCombo(baseUrl, apiKey, model, combo, timeout)));
125
+ const successful = results.filter(
126
+ (r) => r.status === "fulfilled" && r.value.httpCode === 200 && r.value.hasContent
127
+ ).map((r) => r.value).sort((a, b) => a.durationMs - b.durationMs);
128
+ if (successful.length > 0) {
129
+ const winner = successful[0];
130
+ logger.debug("Auto-config: found working combo", {
131
+ model,
132
+ combo: winner.combo,
133
+ durationMs: winner.durationMs
134
+ });
135
+ return winner.combo;
136
+ }
137
+ logger.debug("Auto-config: no working combo found", { model });
138
+ return null;
139
+ }
140
+ async function autoConfig(input) {
141
+ const { url, apiKey, backend, models } = input;
142
+ const baseUrl = url.replace(/\/+$/, "");
143
+ const results = [];
144
+ for (const model of models) {
145
+ logger.info("Auto-config probing model", { model: model.id, backend });
146
+ const {
147
+ contextWindow,
148
+ source: contextSource,
149
+ supportsVision
150
+ } = await detectModelInfo(baseUrl, apiKey, backend, model.id);
151
+ const [thinkingConfig, nonThinkingConfig] = await Promise.all([
152
+ probeCombos(baseUrl, apiKey, model.id, THINKING_COMBOS),
153
+ probeCombos(baseUrl, apiKey, model.id, NON_THINKING_COMBOS)
154
+ ]);
155
+ results.push({
156
+ id: model.id,
157
+ contextWindow,
158
+ contextSource,
159
+ supportsVision,
160
+ thinkingConfig,
161
+ nonThinkingConfig
162
+ });
163
+ }
164
+ return { models: results };
165
+ }
166
+ export {
167
+ autoConfig
168
+ };
169
+ //# sourceMappingURL=auto-config-FZFXOEEG.js.map
@@ -0,0 +1,9 @@
1
+ import {
2
+ getBackendCapabilities,
3
+ getBackendDisplayName
4
+ } from "./chunk-Z4FMBCJO.js";
5
+ export {
6
+ getBackendCapabilities,
7
+ getBackendDisplayName
8
+ };
9
+ //# sourceMappingURL=backend-AGXWAU7A.js.map
@@ -1,25 +1,16 @@
1
1
  import {
2
- applyGeneratedSessionName,
3
2
  buildRunChatTurnParams,
4
3
  finalizeTurnCompletion,
5
- generateSessionName,
6
- getSessionMessageCount,
7
- needsNameGenerationCheck
8
- } from "./chunk-GI24G4OW.js";
4
+ generateSessionNameForSession
5
+ } from "./chunk-VI236SOY.js";
9
6
  import {
10
7
  runChatTurn
11
- } from "./chunk-QK6TYNUN.js";
12
- import "./chunk-MDRNKI7D.js";
13
- import "./chunk-O4TED6AJ.js";
14
- import "./chunk-YUHODMKY.js";
8
+ } from "./chunk-7H4PYZMT.js";
9
+ import "./chunk-K454WU7A.js";
15
10
  import "./chunk-DL6ZILAF.js";
16
11
  import "./chunk-PBGOZMVY.js";
17
12
  import "./chunk-VRGRAQDG.js";
18
13
  import "./chunk-NWO6GRYE.js";
19
- import {
20
- getEventStore
21
- } from "./chunk-YBWY4DKY.js";
22
- import "./chunk-6PLAWCHQ.js";
23
14
  import {
24
15
  createChatMessageMessage,
25
16
  createPhaseChangedMessage,
@@ -27,19 +18,26 @@ import {
27
18
  } from "./chunk-F4PMNP7S.js";
28
19
  import "./chunk-EU3WWTFH.js";
29
20
  import "./chunk-RFNEDBVO.js";
21
+ import "./chunk-O4TED6AJ.js";
22
+ import "./chunk-YGSBVKFU.js";
23
+ import {
24
+ getEventStore
25
+ } from "./chunk-YBWY4DKY.js";
26
+ import "./chunk-6PLAWCHQ.js";
30
27
  import "./chunk-FBGWG4N6.js";
28
+ import "./chunk-J2GP3J3X.js";
29
+ import "./chunk-Z4FMBCJO.js";
30
+ import "./chunk-ZJ4FP6RS.js";
31
+ import "./chunk-K44MW7JJ.js";
31
32
  import "./chunk-YD6NDTKF.js";
32
33
  import "./chunk-SNQT7LNU.js";
33
34
  import "./chunk-CQGTEGKL.js";
34
- import "./chunk-UUFEE7VR.js";
35
- import {
36
- logger
37
- } from "./chunk-K44MW7JJ.js";
35
+ import "./chunk-V4IE7HJY.js";
38
36
 
39
37
  // src/server/session/chat-handler.ts
40
38
  var activeAgents = /* @__PURE__ */ new Map();
41
39
  async function startChatSession(sessionId, content, deps, options) {
42
- const { sessionManager, llmClient, broadcastForSession } = deps;
40
+ const { sessionManager, broadcastForSession } = deps;
43
41
  const session = sessionManager.getSession(sessionId);
44
42
  if (!session) {
45
43
  throw new Error("Session not found");
@@ -69,34 +67,17 @@ async function startChatSession(sessionId, content, deps, options) {
69
67
  ...options?.isSystemGenerated && { isSystemGenerated: options.isSystemGenerated }
70
68
  });
71
69
  broadcastForSession(sessionId, createChatMessageMessage(userMessage));
72
- const messageCount = getSessionMessageCount(sessionId);
73
- const currentSession = sessionManager.getSession(sessionId);
74
- if (currentSession && needsNameGenerationCheck(sessionId, currentSession.metadata.title, messageCount)) {
75
- generateSessionName({
76
- userMessage: content,
77
- llmClient,
78
- signal: controller.signal
79
- }).then((result) => {
80
- logger.debug("Session name generation result", {
81
- sessionId,
82
- success: result.success,
83
- name: result.name,
84
- error: result.error
85
- });
86
- if (result.success && result.name) {
87
- applyGeneratedSessionName(sessionId, result.name, {
88
- sessionManager,
89
- eventStore,
90
- broadcastForSession
91
- });
92
- }
93
- }).catch((error) => {
94
- logger.error("Session name generation failed", {
95
- sessionId,
96
- error: error instanceof Error ? error.message : String(error)
97
- });
98
- });
99
- }
70
+ generateSessionNameForSession(
71
+ sessionId,
72
+ content,
73
+ {
74
+ sessionManager,
75
+ providerManager: deps.providerManager,
76
+ broadcastForSession,
77
+ eventStore
78
+ },
79
+ controller.signal
80
+ );
100
81
  startTurnWithCompletionChain(sessionId, controller, deps);
101
82
  } catch (error) {
102
83
  if (activeAgents.get(sessionId) === controller) {
@@ -164,4 +145,4 @@ export {
164
145
  startChatSession,
165
146
  stopSessionExecution
166
147
  };
167
- //# sourceMappingURL=chat-handler-4ATHDLH4.js.map
148
+ //# sourceMappingURL=chat-handler-C4HZJNUN.js.map
@@ -14,7 +14,7 @@ import {
14
14
  loadAllAgentsDefault,
15
15
  processEventsForConversation,
16
16
  runTopLevelAgentLoop
17
- } from "./chunk-MDRNKI7D.js";
17
+ } from "./chunk-K454WU7A.js";
18
18
  import {
19
19
  TurnMetrics,
20
20
  WORKFLOW_KICKOFF_PROMPT,
@@ -22,7 +22,7 @@ import {
22
22
  buildAgentSmallReminder,
23
23
  createChatDoneEvent,
24
24
  createMessageStartEvent
25
- } from "./chunk-YUHODMKY.js";
25
+ } from "./chunk-YGSBVKFU.js";
26
26
  import {
27
27
  getCurrentContextWindowId,
28
28
  getCurrentWindowMessageOptions,
@@ -32,12 +32,12 @@ import {
32
32
  import {
33
33
  buildSnapshotFromSessionState
34
34
  } from "./chunk-6PLAWCHQ.js";
35
- import {
36
- getGlobalConfigDir
37
- } from "./chunk-CQGTEGKL.js";
38
35
  import {
39
36
  logger
40
37
  } from "./chunk-K44MW7JJ.js";
38
+ import {
39
+ getGlobalConfigDir
40
+ } from "./chunk-CQGTEGKL.js";
41
41
 
42
42
  // src/server/chat/orchestrator.ts
43
43
  async function buildRetryPatterns() {
@@ -320,4 +320,4 @@ export {
320
320
  runAgentTurn,
321
321
  injectWorkflowKickoffIfNeeded
322
322
  };
323
- //# sourceMappingURL=chunk-QK6TYNUN.js.map
323
+ //# sourceMappingURL=chunk-7H4PYZMT.js.map
@@ -1,11 +1,8 @@
1
- import {
2
- appendCompactionPrompt
3
- } from "./chunk-CDIYCGCO.js";
4
1
  import {
5
2
  injectWorkflowKickoffIfNeeded,
6
3
  runAgentTurn,
7
4
  runChatTurn
8
- } from "./chunk-QK6TYNUN.js";
5
+ } from "./chunk-7H4PYZMT.js";
9
6
  import {
10
7
  applyDynamicContext,
11
8
  checkAborted,
@@ -22,20 +19,11 @@ import {
22
19
  loadAllAgentsDefault,
23
20
  saveItemToDir,
24
21
  spawnShellProcess
25
- } from "./chunk-MDRNKI7D.js";
26
- import {
27
- TurnMetrics,
28
- createMessageStartEvent
29
- } from "./chunk-YUHODMKY.js";
22
+ } from "./chunk-K454WU7A.js";
30
23
  import {
31
24
  getPlatformShell,
32
25
  onProcessEvent
33
26
  } from "./chunk-PBGOZMVY.js";
34
- import {
35
- getCurrentContextWindowId,
36
- getEventStore,
37
- getRuntimeConfig
38
- } from "./chunk-YBWY4DKY.js";
39
27
  import {
40
28
  createChatErrorMessage,
41
29
  createChatMessageMessage,
@@ -53,6 +41,27 @@ import {
53
41
  import {
54
42
  provideAnswer
55
43
  } from "./chunk-EU3WWTFH.js";
44
+ import {
45
+ appendCompactionPrompt
46
+ } from "./chunk-WEXW7ZXJ.js";
47
+ import {
48
+ TurnMetrics,
49
+ createMessageStartEvent
50
+ } from "./chunk-YGSBVKFU.js";
51
+ import {
52
+ getCurrentContextWindowId,
53
+ getEventStore,
54
+ getRuntimeConfig
55
+ } from "./chunk-YBWY4DKY.js";
56
+ import {
57
+ createLLMClient
58
+ } from "./chunk-QYP6MOB5.js";
59
+ import {
60
+ ensureVersionPrefix
61
+ } from "./chunk-HNCM3D7Y.js";
62
+ import {
63
+ logger
64
+ } from "./chunk-K44MW7JJ.js";
56
65
  import {
57
66
  computeSessionStats
58
67
  } from "./chunk-VUQCQXXJ.js";
@@ -62,13 +71,6 @@ import {
62
71
  import {
63
72
  getGlobalConfigDir
64
73
  } from "./chunk-CQGTEGKL.js";
65
- import {
66
- createLLMClient,
67
- ensureVersionPrefix
68
- } from "./chunk-XJ4SUDL7.js";
69
- import {
70
- logger
71
- } from "./chunk-K44MW7JJ.js";
72
74
 
73
75
  // src/server/ws/server.ts
74
76
  import { WebSocketServer, WebSocket as WebSocket2 } from "ws";
@@ -1775,7 +1777,7 @@ async function handleClientMessage(ws, client, message, _getLLMClient, _getActiv
1775
1777
  const runtimeConfig = getRuntimeConfig();
1776
1778
  const configDir = getGlobalConfigDir(runtimeConfig.mode ?? "production");
1777
1779
  const skills = await getEnabledSkillMetadata(configDir, runtimeConfig.workdir);
1778
- const { createToolRegistry } = await import("./tools-7CKTYL2G.js");
1780
+ const { createToolRegistry } = await import("./tools-4KGLCQJL.js");
1779
1781
  const allTools = createToolRegistry().definitions;
1780
1782
  const toolFingerprint = getToolFingerprint(allTools);
1781
1783
  const currentHash = computeDynamicContextHash(instructionContent, skills, toolFingerprint);
@@ -1848,7 +1850,7 @@ async function handleClientMessage(ws, client, message, _getLLMClient, _getActiv
1848
1850
  const runtimeConfig = getRuntimeConfig();
1849
1851
  const configDir = getGlobalConfigDir(runtimeConfig.mode ?? "production");
1850
1852
  const skills = await getEnabledSkillMetadata(configDir, runtimeConfig.workdir);
1851
- const { createToolRegistry } = await import("./tools-7CKTYL2G.js");
1853
+ const { createToolRegistry } = await import("./tools-4KGLCQJL.js");
1852
1854
  const allTools = createToolRegistry().definitions;
1853
1855
  const toolFingerprint = getToolFingerprint(allTools);
1854
1856
  const currentHash = computeDynamicContextHash(instructionContent, skills, toolFingerprint);
@@ -2069,4 +2071,4 @@ export {
2069
2071
  signalMcpReady,
2070
2072
  createWebSocketServer
2071
2073
  };
2072
- //# sourceMappingURL=chunk-RYHCYZQ7.js.map
2074
+ //# sourceMappingURL=chunk-DW55I7SI.js.map
@@ -1,17 +1,21 @@
1
1
  import {
2
- buildModelsUrl,
3
2
  clearModelCache,
4
- createLLMClient,
5
- detectModel,
3
+ detectModel
4
+ } from "./chunk-M3RB4IF6.js";
5
+ import {
6
+ createLLMClient
7
+ } from "./chunk-QYP6MOB5.js";
8
+ import {
9
+ buildModelsUrl,
6
10
  ensureVersionPrefix,
7
11
  stripVersionPrefix
8
- } from "./chunk-XJ4SUDL7.js";
9
- import {
10
- getModelProfile
11
- } from "./chunk-UUFEE7VR.js";
12
+ } from "./chunk-HNCM3D7Y.js";
12
13
  import {
13
14
  logger
14
15
  } from "./chunk-K44MW7JJ.js";
16
+ import {
17
+ getModelProfile
18
+ } from "./chunk-V4IE7HJY.js";
15
19
 
16
20
  // src/server/provider-manager.ts
17
21
  function normalizeModelId(s) {
@@ -201,7 +205,7 @@ function createProviderManager(config) {
201
205
  const { providerId: activeProviderId, model: activeModel } = parseDefaultModelSelection(defaultModelSelection);
202
206
  if (activeProviderId && activeModel) {
203
207
  const activeProvider = providers.find((p) => p.id === activeProviderId);
204
- if (activeProvider && activeProvider.apiKey) {
208
+ if (activeProvider) {
205
209
  llmClient = createLLMClient(createConfigForProvider(activeProvider, activeModel));
206
210
  }
207
211
  }
@@ -352,8 +356,7 @@ function createProviderManager(config) {
352
356
  llmClient = createLLMClient(providerConfig);
353
357
  logger.info("setProviders: recreated LLM client for new active provider", {
354
358
  providerId: newActiveProviderId,
355
- url: activeProvider.url,
356
- hasApiKey: !!activeProvider.apiKey
359
+ url: activeProvider.url
357
360
  });
358
361
  }
359
362
  }
@@ -473,17 +476,28 @@ function createProviderManager(config) {
473
476
  const provider = providers.find((p) => p.models.some((m) => m.id === modelId));
474
477
  const model = provider?.models.find((m) => m.id === modelId);
475
478
  if (!model) return void 0;
476
- const kwargs = mode === "non-thinking" ? model.nonThinkingEnabled ? model.nonThinkingExtraKwargs : model.thinkingExtraKwargs : model.thinkingEnabled ? model.thinkingExtraKwargs : model.nonThinkingExtraKwargs;
477
- return {
478
- ...model.temperature !== void 0 && { temperature: model.temperature },
479
- ...model.topP !== void 0 && { topP: model.topP },
480
- ...model.topK !== void 0 && { topK: model.topK },
481
- ...model.maxTokens !== void 0 && { maxTokens: model.maxTokens },
482
- ...model.supportsVision !== void 0 && { supportsVision: model.supportsVision },
483
- ...kwargs ? { chatTemplateKwargs: JSON.parse(kwargs) } : {},
484
- ...mode === "thinking" && model.thinkingQueryParams ? { queryParams: JSON.parse(model.thinkingQueryParams) } : {},
485
- ...mode === "non-thinking" && model.nonThinkingQueryParams ? { queryParams: JSON.parse(model.nonThinkingQueryParams) } : {}
486
- };
479
+ const baseSettings = {};
480
+ if (model["temperature"] !== void 0) baseSettings["temperature"] = model["temperature"];
481
+ if (model["topP"] !== void 0) baseSettings["topP"] = model["topP"];
482
+ if (model["topK"] !== void 0) baseSettings["topK"] = model["topK"];
483
+ if (model["maxTokens"] !== void 0) baseSettings["maxTokens"] = model["maxTokens"];
484
+ if (model["supportsVision"] !== void 0) baseSettings["supportsVision"] = model["supportsVision"];
485
+ const rawQueryParams = mode === "thinking" ? model.thinkingQueryParams : model.nonThinkingQueryParams;
486
+ if (rawQueryParams) {
487
+ return { ...baseSettings, queryParams: JSON.parse(rawQueryParams) };
488
+ }
489
+ const modeEnabled = mode === "thinking" ? model.thinkingEnabled : model.nonThinkingEnabled;
490
+ if (modeEnabled) {
491
+ return {
492
+ ...baseSettings,
493
+ chatTemplateKwargs: mode === "thinking" ? { enable_thinking: true } : { enable_thinking: false }
494
+ };
495
+ }
496
+ const fallbackRawQP = mode === "thinking" ? model.nonThinkingQueryParams : model.thinkingQueryParams;
497
+ if (fallbackRawQP) {
498
+ return { ...baseSettings, queryParams: JSON.parse(fallbackRawQP) };
499
+ }
500
+ return void 0;
487
501
  },
488
502
  async refreshProviderModels(providerId) {
489
503
  const provider = providers.find((p) => p.id === providerId);
@@ -540,4 +554,4 @@ export {
540
554
  parseDefaultModelSelection,
541
555
  createProviderManager
542
556
  };
543
- //# sourceMappingURL=chunk-YVF3BLQS.js.map
557
+ //# sourceMappingURL=chunk-GBUP7UDI.js.map
@@ -0,0 +1,28 @@
1
+ // src/server/llm/url-utils.ts
2
+ var VERSION_PREFIX_REGEX = /\/v\d+(\/|$)/;
3
+ function hasVersionPrefix(url) {
4
+ return VERSION_PREFIX_REGEX.test(url);
5
+ }
6
+ function getVersionPrefix(url) {
7
+ const match = url.match(/\/v\d+/);
8
+ return match ? match[0] : null;
9
+ }
10
+ function ensureVersionPrefix(url, defaultVersion = "/v1") {
11
+ if (hasVersionPrefix(url)) return url;
12
+ return `${url.replace(/\/+$/, "")}${defaultVersion}`;
13
+ }
14
+ function stripVersionPrefix(url) {
15
+ return url.replace(/\/v\d+\/?$/, "");
16
+ }
17
+ function buildModelsUrl(baseUrl) {
18
+ return `${ensureVersionPrefix(baseUrl)}/models`;
19
+ }
20
+
21
+ export {
22
+ hasVersionPrefix,
23
+ getVersionPrefix,
24
+ ensureVersionPrefix,
25
+ stripVersionPrefix,
26
+ buildModelsUrl
27
+ };
28
+ //# sourceMappingURL=chunk-HNCM3D7Y.js.map
@@ -0,0 +1,124 @@
1
+ import {
2
+ logger
3
+ } from "./chunk-K44MW7JJ.js";
4
+
5
+ // src/server/llm/http-client.ts
6
+ import { Agent, setGlobalDispatcher } from "undici";
7
+
8
+ // src/server/utils/errors.ts
9
+ var OpenFoxError = class extends Error {
10
+ constructor(message, code, details) {
11
+ super(message);
12
+ this.code = code;
13
+ this.details = details;
14
+ this.name = "OpenFoxError";
15
+ }
16
+ };
17
+ var SessionNotFoundError = class extends OpenFoxError {
18
+ constructor(sessionId) {
19
+ super(`Session not found: ${sessionId}`, "SESSION_NOT_FOUND", { sessionId });
20
+ this.name = "SessionNotFoundError";
21
+ }
22
+ };
23
+ var LLMError = class extends OpenFoxError {
24
+ constructor(message, details) {
25
+ super(message, "LLM_ERROR", details);
26
+ this.name = "LLMError";
27
+ }
28
+ };
29
+
30
+ // src/server/llm/http-client.ts
31
+ var agent = new Agent({ allowH2: true });
32
+ setGlobalDispatcher(agent);
33
+ var OpenAIHttpClient = class {
34
+ baseURL;
35
+ apiKey;
36
+ constructor(options) {
37
+ this.baseURL = options.baseURL;
38
+ this.apiKey = options.apiKey;
39
+ }
40
+ async fetchChatCompletion(params, options) {
41
+ const url = `${this.baseURL}/chat/completions`;
42
+ const headers = {
43
+ "Content-Type": "application/json",
44
+ Authorization: `Bearer ${this.apiKey}`
45
+ };
46
+ const bodyStr = JSON.stringify(params);
47
+ logger.debug("HTTP request to LLM", {
48
+ url,
49
+ body: bodyStr.slice(0, 2e3),
50
+ bodyKeys: Object.keys(params)
51
+ });
52
+ const response = await fetch(url, {
53
+ method: "POST",
54
+ headers,
55
+ body: bodyStr,
56
+ signal: options?.signal ?? null
57
+ });
58
+ if (!response.ok) {
59
+ const errorText = await response.text();
60
+ throw new LLMError(`HTTP ${response.status}: ${errorText}`);
61
+ }
62
+ return response;
63
+ }
64
+ async createChatCompletion(params, options, returnRaw) {
65
+ const response = await this.fetchChatCompletion(params, options);
66
+ const rawText = await response.text();
67
+ try {
68
+ const data = JSON.parse(rawText);
69
+ if (returnRaw) {
70
+ return { ...data, raw: rawText };
71
+ }
72
+ return data;
73
+ } catch (error) {
74
+ throw new LLMError(`Failed to parse response: ${error instanceof Error ? error.message : "Unknown error"}`);
75
+ }
76
+ }
77
+ createChatCompletionStream(params, options) {
78
+ const responsePromise = this.fetchChatCompletion(params, options);
79
+ async function* generate() {
80
+ const response = await responsePromise;
81
+ if (!response.body) {
82
+ throw new LLMError("No response body for streaming");
83
+ }
84
+ const reader = response.body.getReader();
85
+ const decoder = new TextDecoder();
86
+ let buffer = "";
87
+ try {
88
+ while (true) {
89
+ const { done, value } = await reader.read();
90
+ if (done) break;
91
+ buffer += decoder.decode(value, { stream: true });
92
+ const lines = buffer.split("\n");
93
+ buffer = lines.pop() || "";
94
+ for (const line of lines) {
95
+ const trimmed = line.trim();
96
+ if (!trimmed) continue;
97
+ if (trimmed.startsWith("data: ")) {
98
+ const data = trimmed.slice(6);
99
+ if (data === "[DONE]") {
100
+ return;
101
+ }
102
+ try {
103
+ const chunk = JSON.parse(data);
104
+ yield chunk;
105
+ } catch (error) {
106
+ logger.warn("Failed to parse SSE chunk", { data, error });
107
+ }
108
+ }
109
+ }
110
+ }
111
+ } finally {
112
+ reader.releaseLock();
113
+ }
114
+ }
115
+ return generate();
116
+ }
117
+ };
118
+
119
+ export {
120
+ SessionNotFoundError,
121
+ LLMError,
122
+ OpenAIHttpClient
123
+ };
124
+ //# sourceMappingURL=chunk-IEDE6VK4.js.map