openfox 1.6.20 → 1.6.23

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 (35) hide show
  1. package/README.md +46 -13
  2. package/dist/{auto-compaction-NFLWKJAO.js → auto-compaction-7LK3QGPI.js} +4 -3
  3. package/dist/{chat-handler-2RVTVNPF.js → chat-handler-ZU74RXED.js} +6 -5
  4. package/dist/{chunk-KOBGCNUE.js → chunk-4O3C2JMB.js} +58 -14
  5. package/dist/{chunk-QY7BMXWT.js → chunk-B7E3BICY.js} +6 -2
  6. package/dist/{chunk-U3KMU3UE.js → chunk-BOEXJCOD.js} +2 -2
  7. package/dist/{chunk-IN5EP4ZB.js → chunk-CJNQGEYG.js} +2 -2
  8. package/dist/{chunk-OVLFEBRR.js → chunk-D4ZLSV6P.js} +133 -468
  9. package/dist/{chunk-LTPZ4GTW.js → chunk-FTJPNCAV.js} +6 -6
  10. package/dist/chunk-KSASIV4B.js +486 -0
  11. package/dist/{chunk-ZDNXCVW4.js → chunk-P6GUT2QQ.js} +11 -5
  12. package/dist/{chunk-KOUMYBYM.js → chunk-PYBB34ZK.js} +54 -3
  13. package/dist/{chunk-R7UAGXQW.js → chunk-YCQSAFAQ.js} +42 -24
  14. package/dist/cli/dev.js +1 -1
  15. package/dist/cli/index.js +1 -1
  16. package/dist/{config-67AX6CNS.js → config-ACVEHBKG.js} +5 -5
  17. package/dist/{orchestrator-ZICQ5NIZ.js → orchestrator-OE7WFEW6.js} +5 -4
  18. package/dist/package.json +3 -3
  19. package/dist/{processor-MPSYT534.js → processor-GAOK7TPI.js} +2 -2
  20. package/dist/{protocol-I7rn7Msg.d.ts → protocol-BYM6rZvW.d.ts} +12 -0
  21. package/dist/{provider-DKGBQHUS.js → provider-RLQMVV2Z.js} +9 -8
  22. package/dist/{serve-B5A52252.js → serve-IBJ3SN3Q.js} +10 -10
  23. package/dist/server/index.d.ts +24 -1
  24. package/dist/server/index.js +8 -8
  25. package/dist/shared/index.d.ts +2 -2
  26. package/dist/shared/index.js +1 -1
  27. package/dist/{tools-ERJ3QRQU.js → tools-CSV7G554.js} +4 -3
  28. package/dist/{vision-fallback-ADYRFFD4.js → vision-fallback-QJ26DCEF.js} +2 -2
  29. package/dist/web/assets/index-BrZqZwpA.js +153 -0
  30. package/dist/web/assets/{index-vBklayFL.css → index-DF26vcqg.css} +1 -1
  31. package/dist/web/index.html +2 -2
  32. package/dist/web/sw.js +1 -1
  33. package/package.json +3 -3
  34. package/dist/chunk-55N6FAAZ.js +0 -117
  35. package/dist/web/assets/index-vOba1XKB.js +0 -151
@@ -27,7 +27,7 @@ Options:
27
27
  }
28
28
  async function runNetworkSetup(mode) {
29
29
  const { loadAuthConfig, saveAuthConfig, encryptPassword } = await import("./auth-JF2HDJ6P.js");
30
- const { saveGlobalConfig } = await import("./config-67AX6CNS.js");
30
+ const { saveGlobalConfig } = await import("./config-ACVEHBKG.js");
31
31
  const { getAuthKeyPath } = await import("./paths-ZRI56O63.js");
32
32
  const existingAuth = await loadAuthConfig(mode);
33
33
  if (existingAuth) {
@@ -88,7 +88,7 @@ async function runNetworkSetup(mode) {
88
88
  console.log("\u2713 Configuration saved!\n");
89
89
  }
90
90
  async function runConfig(mode) {
91
- const { loadGlobalConfig, getActiveProvider, getDefaultModel } = await import("./config-67AX6CNS.js");
91
+ const { loadGlobalConfig, getActiveProvider, getDefaultModel } = await import("./config-ACVEHBKG.js");
92
92
  const { getGlobalConfigPath } = await import("./paths-ZRI56O63.js");
93
93
  const config = await loadGlobalConfig(mode);
94
94
  const configPath = getGlobalConfigPath(mode);
@@ -143,18 +143,18 @@ async function runCli(options) {
143
143
  break;
144
144
  }
145
145
  case "provider": {
146
- const { runProviderCommand } = await import("./provider-DKGBQHUS.js");
146
+ const { runProviderCommand } = await import("./provider-RLQMVV2Z.js");
147
147
  const [, subcommand] = positionals;
148
148
  await runProviderCommand(mode, subcommand);
149
149
  break;
150
150
  }
151
151
  default: {
152
- const { configFileExists } = await import("./config-67AX6CNS.js");
152
+ const { configFileExists } = await import("./config-ACVEHBKG.js");
153
153
  const configExists = await configFileExists(mode);
154
154
  if (!configExists) {
155
155
  await runNetworkSetup(mode);
156
156
  }
157
- const { runServe } = await import("./serve-B5A52252.js");
157
+ const { runServe } = await import("./serve-IBJ3SN3Q.js");
158
158
  await runServe({
159
159
  mode,
160
160
  port: values.port ? parseInt(values.port) : void 0,
@@ -167,4 +167,4 @@ async function runCli(options) {
167
167
  export {
168
168
  runCli
169
169
  };
170
- //# sourceMappingURL=chunk-LTPZ4GTW.js.map
170
+ //# sourceMappingURL=chunk-FTJPNCAV.js.map
@@ -0,0 +1,486 @@
1
+ import {
2
+ buildNonStreamingCreateParams,
3
+ buildStreamingCreateParams,
4
+ extractThinking,
5
+ getBackendCapabilities,
6
+ getModelProfile,
7
+ mapFinishReason
8
+ } from "./chunk-D4ZLSV6P.js";
9
+ import {
10
+ ensureVisionFallbackConfigLoaded
11
+ } from "./chunk-CJNQGEYG.js";
12
+ import {
13
+ logger
14
+ } from "./chunk-PNBH3RAX.js";
15
+
16
+ // src/server/llm/models.ts
17
+ var modelCache = /* @__PURE__ */ new Map();
18
+ var llmStatus = "unknown";
19
+ var lastActiveUrl = null;
20
+ var CACHE_TTL_MS = 3e4;
21
+ function getCacheKey(url) {
22
+ return url.replace(/\/v1\/?$/, "");
23
+ }
24
+ async function detectModel(llmBaseUrl, retries = 3, silent = false) {
25
+ const cacheKey = getCacheKey(llmBaseUrl);
26
+ const now = Date.now();
27
+ const cached = modelCache.get(cacheKey);
28
+ if (cached && now - cached.timestamp < CACHE_TTL_MS) {
29
+ lastActiveUrl = cacheKey;
30
+ llmStatus = "connected";
31
+ return cached.model;
32
+ }
33
+ const url = llmBaseUrl.includes("/v1") ? `${llmBaseUrl}/models` : `${llmBaseUrl}/v1/models`;
34
+ for (let attempt = 1; attempt <= retries; attempt++) {
35
+ try {
36
+ if (silent) {
37
+ logger.debug("Fetching models from LLM server", { url, attempt });
38
+ }
39
+ const response = await fetch(url, {
40
+ signal: AbortSignal.timeout(1e4)
41
+ });
42
+ if (!response.ok) {
43
+ if (silent) {
44
+ logger.debug("Failed to fetch models from LLM server", { status: response.status, attempt });
45
+ } else {
46
+ logger.warn("Failed to fetch models from LLM server", { status: response.status, attempt });
47
+ }
48
+ if (attempt < retries) {
49
+ await new Promise((r) => setTimeout(r, 1e3 * attempt));
50
+ continue;
51
+ }
52
+ llmStatus = "disconnected";
53
+ return cached?.model ?? null;
54
+ }
55
+ const data = await response.json();
56
+ if (data.data && data.data.length > 0) {
57
+ const modelData = data.data[0];
58
+ const modelId = modelData.id;
59
+ modelCache.set(cacheKey, {
60
+ model: modelId,
61
+ modelInfo: modelData,
62
+ timestamp: now
63
+ });
64
+ lastActiveUrl = cacheKey;
65
+ llmStatus = "connected";
66
+ if (silent) {
67
+ logger.debug("Detected LLM model", {
68
+ model: modelId,
69
+ maxLen: modelData.max_model_len,
70
+ root: modelData.root
71
+ });
72
+ } else {
73
+ logger.info("Detected LLM model", {
74
+ model: modelId,
75
+ maxLen: modelData.max_model_len,
76
+ root: modelData.root
77
+ });
78
+ }
79
+ return modelId;
80
+ }
81
+ if (silent) {
82
+ logger.debug("LLM server returned empty models list");
83
+ } else {
84
+ logger.warn("LLM server returned empty models list");
85
+ }
86
+ llmStatus = "disconnected";
87
+ return null;
88
+ } catch (error) {
89
+ const errMsg = error instanceof Error ? error.message : String(error);
90
+ if (silent) {
91
+ logger.debug("Could not detect model from LLM server", { error: errMsg, attempt });
92
+ } else {
93
+ logger.warn("Could not detect model from LLM server", { error: errMsg, attempt });
94
+ }
95
+ if (attempt < retries) {
96
+ await new Promise((r) => setTimeout(r, 1e3 * attempt));
97
+ continue;
98
+ }
99
+ }
100
+ }
101
+ llmStatus = "disconnected";
102
+ return cached?.model ?? null;
103
+ }
104
+ function getLlmStatus() {
105
+ return llmStatus;
106
+ }
107
+ function setLlmStatus(status) {
108
+ llmStatus = status;
109
+ }
110
+ function clearModelCache(url) {
111
+ if (url) {
112
+ modelCache.delete(getCacheKey(url));
113
+ } else {
114
+ modelCache.clear();
115
+ }
116
+ llmStatus = "unknown";
117
+ }
118
+
119
+ // src/server/llm/client.ts
120
+ import OpenAI from "openai";
121
+
122
+ // src/server/utils/errors.ts
123
+ var OpenFoxError = class extends Error {
124
+ constructor(message, code, details) {
125
+ super(message);
126
+ this.code = code;
127
+ this.details = details;
128
+ this.name = "OpenFoxError";
129
+ }
130
+ };
131
+ var SessionNotFoundError = class extends OpenFoxError {
132
+ constructor(sessionId) {
133
+ super(`Session not found: ${sessionId}`, "SESSION_NOT_FOUND", { sessionId });
134
+ this.name = "SessionNotFoundError";
135
+ }
136
+ };
137
+ var LLMError = class extends OpenFoxError {
138
+ constructor(message, details) {
139
+ super(message, "LLM_ERROR", details);
140
+ this.name = "LLMError";
141
+ }
142
+ };
143
+
144
+ // src/server/llm/client.ts
145
+ function createLLMClient(config, initialBackend = "unknown") {
146
+ const baseURL = config.llm.baseUrl.includes("/v1") ? config.llm.baseUrl : `${config.llm.baseUrl}/v1`;
147
+ const openai = new OpenAI({
148
+ baseURL,
149
+ apiKey: config.llm.apiKey ?? "not-needed"
150
+ });
151
+ let model = config.llm.model;
152
+ let profile = getModelProfile(model);
153
+ let backend = initialBackend;
154
+ let capabilities = getBackendCapabilities(backend);
155
+ const disableThinking = config.llm.disableThinking ?? false;
156
+ const idleTimeout = config.llm.idleTimeout ?? 3e4;
157
+ return {
158
+ getModel() {
159
+ return model;
160
+ },
161
+ getProfile() {
162
+ return profile;
163
+ },
164
+ getBackend() {
165
+ return backend;
166
+ },
167
+ setBackend(newBackend) {
168
+ logger.debug("Setting LLM backend", { from: backend, to: newBackend });
169
+ backend = newBackend;
170
+ capabilities = getBackendCapabilities(newBackend);
171
+ },
172
+ setModel(newModel) {
173
+ const newProfile = getModelProfile(newModel);
174
+ logger.debug("Switching model", {
175
+ from: model,
176
+ to: newModel,
177
+ profile: newProfile.name,
178
+ temperature: newProfile.temperature,
179
+ supportsReasoning: newProfile.supportsReasoning
180
+ });
181
+ model = newModel;
182
+ profile = newProfile;
183
+ },
184
+ async complete(request) {
185
+ logger.debug("LLM complete request", {
186
+ messageCount: request.messages.length,
187
+ hasTools: !!request.tools?.length,
188
+ profile: profile.name,
189
+ disableThinking
190
+ });
191
+ try {
192
+ const shouldDisableThinking = disableThinking || request.disableThinking === true;
193
+ await ensureVisionFallbackConfigLoaded();
194
+ const { isVisionFallbackEnabled } = await import("./vision-fallback-QJ26DCEF.js");
195
+ const paramsOptions = {
196
+ model,
197
+ request,
198
+ profile,
199
+ capabilities,
200
+ disableThinking: shouldDisableThinking,
201
+ visionFallbackEnabled: isVisionFallbackEnabled()
202
+ };
203
+ if (request.onVisionFallbackStart) {
204
+ paramsOptions.onVisionFallbackStart = request.onVisionFallbackStart;
205
+ }
206
+ if (request.onVisionFallbackDone) {
207
+ paramsOptions.onVisionFallbackDone = request.onVisionFallbackDone;
208
+ }
209
+ const { params: createParams } = await buildNonStreamingCreateParams(paramsOptions);
210
+ const response = await openai.chat.completions.create(createParams, {
211
+ signal: request.signal
212
+ });
213
+ const choice = response.choices[0];
214
+ if (!choice) {
215
+ throw new LLMError("No completion choice returned");
216
+ }
217
+ const message = choice.message;
218
+ let content = message.content ?? "";
219
+ let thinkingContent = "";
220
+ if (profile.supportsReasoning) {
221
+ if (capabilities.supportsReasoningField) {
222
+ thinkingContent = message.reasoning_content ?? message.reasoning ?? "";
223
+ } else {
224
+ const extracted = extractThinking(content);
225
+ content = extracted.content;
226
+ thinkingContent = extracted.thinkingContent ?? "";
227
+ }
228
+ if (profile.reasoningAsContent && thinkingContent.trim()) {
229
+ content = thinkingContent;
230
+ thinkingContent = "";
231
+ }
232
+ }
233
+ if (!content.trim() && thinkingContent.trim()) {
234
+ content = thinkingContent;
235
+ thinkingContent = "";
236
+ }
237
+ const toolCalls = message.tool_calls?.map((tc) => ({
238
+ id: tc.id,
239
+ name: tc.function.name,
240
+ arguments: JSON.parse(tc.function.arguments)
241
+ }));
242
+ return {
243
+ id: response.id,
244
+ content,
245
+ ...thinkingContent ? { thinkingContent } : {},
246
+ ...toolCalls && toolCalls.length > 0 ? { toolCalls } : {},
247
+ finishReason: mapFinishReason(choice.finish_reason),
248
+ usage: {
249
+ promptTokens: response.usage?.prompt_tokens ?? 0,
250
+ completionTokens: response.usage?.completion_tokens ?? 0,
251
+ totalTokens: response.usage?.total_tokens ?? 0
252
+ }
253
+ };
254
+ } catch (error) {
255
+ logger.error("LLM complete error", { error: error.toString() });
256
+ throw new LLMError(
257
+ error instanceof Error ? error.message : "Unknown LLM error",
258
+ { originalError: error }
259
+ );
260
+ }
261
+ },
262
+ async *stream(request) {
263
+ logger.debug("LLM stream request", {
264
+ messageCount: request.messages.length,
265
+ hasTools: !!request.tools?.length,
266
+ profile: profile.name,
267
+ disableThinking,
268
+ idleTimeout
269
+ });
270
+ try {
271
+ await ensureVisionFallbackConfigLoaded();
272
+ const { isVisionFallbackEnabled } = await import("./vision-fallback-QJ26DCEF.js");
273
+ const shouldDisableThinking = disableThinking || request.disableThinking === true;
274
+ const createParams = await buildStreamingCreateParams({
275
+ model,
276
+ request,
277
+ profile,
278
+ capabilities,
279
+ disableThinking: shouldDisableThinking,
280
+ visionFallbackEnabled: isVisionFallbackEnabled(),
281
+ onVisionFallbackStart: request.onVisionFallbackStart,
282
+ onVisionFallbackDone: request.onVisionFallbackDone
283
+ });
284
+ const { params: streamingParams } = createParams;
285
+ const stream = await openai.chat.completions.create(streamingParams, {
286
+ signal: request.signal
287
+ });
288
+ let fullContent = "";
289
+ let fullThinking = "";
290
+ let inThinking = false;
291
+ let tagBuffer = "";
292
+ const toolCalls = /* @__PURE__ */ new Map();
293
+ let finishReason = "stop";
294
+ let usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
295
+ let responseId = "";
296
+ let lastChunkTime = Date.now();
297
+ const idleTimeoutController = new AbortController();
298
+ const idleTimer = setInterval(() => {
299
+ const idleDuration = Date.now() - lastChunkTime;
300
+ if (idleDuration > idleTimeout) {
301
+ logger.warn("LLM stream idle timeout triggered", { idleDuration, idleTimeout });
302
+ idleTimeoutController.abort();
303
+ }
304
+ }, 100);
305
+ try {
306
+ for await (const chunk of stream) {
307
+ if (idleTimeoutController.signal.aborted) {
308
+ throw new Error(`LLM stream idle timeout: no chunks received for ${idleTimeout}ms`);
309
+ }
310
+ lastChunkTime = Date.now();
311
+ responseId = chunk.id;
312
+ if (chunk.usage) {
313
+ usage = {
314
+ promptTokens: chunk.usage.prompt_tokens,
315
+ completionTokens: chunk.usage.completion_tokens,
316
+ totalTokens: chunk.usage.total_tokens
317
+ };
318
+ }
319
+ const choice = chunk.choices[0];
320
+ if (!choice) continue;
321
+ if (choice.finish_reason) {
322
+ finishReason = mapFinishReason(choice.finish_reason);
323
+ }
324
+ const delta = choice.delta;
325
+ if (capabilities.supportsReasoningField) {
326
+ const reasoning = delta.reasoning_content ?? delta.reasoning;
327
+ if (reasoning) {
328
+ if (profile.supportsReasoning && !profile.reasoningAsContent) {
329
+ fullThinking += reasoning;
330
+ yield { type: "thinking_delta", content: reasoning };
331
+ } else {
332
+ fullContent += reasoning;
333
+ yield { type: "text_delta", content: reasoning };
334
+ }
335
+ }
336
+ }
337
+ if (delta.content) {
338
+ fullContent += delta.content;
339
+ if (!capabilities.supportsReasoningField && profile.supportsReasoning && !profile.reasoningAsContent) {
340
+ tagBuffer += delta.content;
341
+ while (tagBuffer.length > 0) {
342
+ if (inThinking) {
343
+ const closeIdx = tagBuffer.indexOf("</think>");
344
+ if (closeIdx !== -1) {
345
+ const thinkText = tagBuffer.slice(0, closeIdx);
346
+ if (thinkText) {
347
+ fullThinking += thinkText;
348
+ yield { type: "thinking_delta", content: thinkText };
349
+ }
350
+ tagBuffer = tagBuffer.slice(closeIdx + "</think>".length);
351
+ inThinking = false;
352
+ } else if (tagBuffer.includes("</")) {
353
+ const partialIdx = tagBuffer.lastIndexOf("</");
354
+ const before = tagBuffer.slice(0, partialIdx);
355
+ if (before) {
356
+ fullThinking += before;
357
+ yield { type: "thinking_delta", content: before };
358
+ }
359
+ tagBuffer = tagBuffer.slice(partialIdx);
360
+ break;
361
+ } else {
362
+ fullThinking += tagBuffer;
363
+ yield { type: "thinking_delta", content: tagBuffer };
364
+ tagBuffer = "";
365
+ }
366
+ } else {
367
+ const openIdx = tagBuffer.indexOf("<think>");
368
+ if (openIdx !== -1) {
369
+ const textBefore = tagBuffer.slice(0, openIdx);
370
+ if (textBefore) {
371
+ yield { type: "text_delta", content: textBefore };
372
+ }
373
+ tagBuffer = tagBuffer.slice(openIdx + "<think>".length);
374
+ inThinking = true;
375
+ } else if (tagBuffer.includes("<")) {
376
+ const partialIdx = tagBuffer.lastIndexOf("<");
377
+ const before = tagBuffer.slice(0, partialIdx);
378
+ if (before) {
379
+ yield { type: "text_delta", content: before };
380
+ }
381
+ tagBuffer = tagBuffer.slice(partialIdx);
382
+ break;
383
+ } else {
384
+ yield { type: "text_delta", content: tagBuffer };
385
+ tagBuffer = "";
386
+ }
387
+ }
388
+ }
389
+ } else {
390
+ yield { type: "text_delta", content: delta.content };
391
+ }
392
+ }
393
+ if (delta.tool_calls) {
394
+ for (const tc of delta.tool_calls) {
395
+ const existing = toolCalls.get(tc.index);
396
+ if (!existing) {
397
+ toolCalls.set(tc.index, {
398
+ id: tc.id ?? "",
399
+ name: tc.function?.name ?? "",
400
+ arguments: tc.function?.arguments ?? ""
401
+ });
402
+ } else {
403
+ if (tc.id) existing.id = tc.id;
404
+ if (tc.function?.name) existing.name += tc.function.name;
405
+ if (tc.function?.arguments) existing.arguments += tc.function.arguments;
406
+ }
407
+ yield {
408
+ type: "tool_call_delta",
409
+ index: tc.index,
410
+ ...tc.id ? { id: tc.id } : {},
411
+ ...tc.function?.name ? { name: tc.function.name } : {},
412
+ ...tc.function?.arguments ? { arguments: tc.function.arguments } : {}
413
+ };
414
+ }
415
+ }
416
+ }
417
+ } finally {
418
+ clearInterval(idleTimer);
419
+ }
420
+ if (tagBuffer) {
421
+ if (inThinking) {
422
+ fullThinking += tagBuffer;
423
+ }
424
+ tagBuffer = "";
425
+ }
426
+ let finalContent = fullContent.trim();
427
+ let finalThinking = fullThinking.trim();
428
+ if (!capabilities.supportsReasoningField && profile.supportsReasoning) {
429
+ const extracted = extractThinking(finalContent);
430
+ finalContent = extracted.content;
431
+ finalThinking = extracted.thinkingContent ?? "";
432
+ }
433
+ if (!finalContent && finalThinking) {
434
+ finalContent = finalThinking;
435
+ finalThinking = "";
436
+ }
437
+ const parsedToolCalls = [];
438
+ for (const [, tc] of toolCalls) {
439
+ try {
440
+ parsedToolCalls.push({
441
+ id: tc.id,
442
+ name: tc.name,
443
+ arguments: JSON.parse(tc.arguments)
444
+ });
445
+ } catch (error) {
446
+ logger.warn("Failed to parse tool call arguments", { name: tc.name, arguments: tc.arguments });
447
+ parsedToolCalls.push({
448
+ id: tc.id,
449
+ name: tc.name,
450
+ arguments: {},
451
+ parseError: error instanceof Error ? error.message : "Unknown JSON parse error",
452
+ rawArguments: tc.arguments
453
+ });
454
+ }
455
+ }
456
+ yield {
457
+ type: "done",
458
+ response: {
459
+ id: responseId,
460
+ content: finalContent,
461
+ ...finalThinking ? { thinkingContent: finalThinking } : {},
462
+ ...parsedToolCalls.length > 0 ? { toolCalls: parsedToolCalls } : {},
463
+ finishReason,
464
+ usage
465
+ }
466
+ };
467
+ } catch (error) {
468
+ logger.error("LLM stream error", { error });
469
+ yield {
470
+ type: "error",
471
+ error: error instanceof Error ? error.message : "Unknown LLM error"
472
+ };
473
+ }
474
+ }
475
+ };
476
+ }
477
+
478
+ export {
479
+ SessionNotFoundError,
480
+ createLLMClient,
481
+ detectModel,
482
+ getLlmStatus,
483
+ setLlmStatus,
484
+ clearModelCache
485
+ };
486
+ //# sourceMappingURL=chunk-KSASIV4B.js.map
@@ -1,7 +1,9 @@
1
1
  import {
2
- detectBackend,
3
2
  detectModel
4
- } from "./chunk-OVLFEBRR.js";
3
+ } from "./chunk-KSASIV4B.js";
4
+ import {
5
+ detectBackend
6
+ } from "./chunk-D4ZLSV6P.js";
5
7
  import {
6
8
  getGlobalConfigPath
7
9
  } from "./chunk-R4HADRYO.js";
@@ -48,8 +50,12 @@ var backendSchema = z.enum(["auto", "vllm", "sglang", "ollama", "llamacpp", "ope
48
50
  var modelConfigSchema = z.object({
49
51
  id: z.string(),
50
52
  contextWindow: z.number(),
51
- source: z.enum(["backend", "user", "default"])
52
- });
53
+ source: z.enum(["backend", "user", "default"]),
54
+ temperature: z.number().optional(),
55
+ topP: z.number().optional(),
56
+ topK: z.number().optional(),
57
+ maxTokens: z.number().optional()
58
+ }).passthrough();
53
59
  var providerSchema = z.object({
54
60
  id: z.string(),
55
61
  name: z.string(),
@@ -380,4 +386,4 @@ export {
380
386
  activateProvider,
381
387
  mergeConfigs
382
388
  };
383
- //# sourceMappingURL=chunk-ZDNXCVW4.js.map
389
+ //# sourceMappingURL=chunk-P6GUT2QQ.js.map
@@ -1,10 +1,12 @@
1
1
  import {
2
2
  clearModelCache,
3
3
  createLLMClient,
4
- detectBackend,
5
4
  detectModel,
6
5
  setLlmStatus
7
- } from "./chunk-OVLFEBRR.js";
6
+ } from "./chunk-KSASIV4B.js";
7
+ import {
8
+ detectBackend
9
+ } from "./chunk-D4ZLSV6P.js";
8
10
  import {
9
11
  logger
10
12
  } from "./chunk-PNBH3RAX.js";
@@ -363,6 +365,55 @@ function createProviderManager(config) {
363
365
  logger.info("Model context updated", { providerId, modelId, contextWindow });
364
366
  return { success: true };
365
367
  },
368
+ async updateModelSettings(providerId, modelId, settings) {
369
+ const provider = providers.find((p) => p.id === providerId);
370
+ if (!provider) {
371
+ return { success: false, error: "Provider not found" };
372
+ }
373
+ const existingModel = provider.models.find((m) => m.id === modelId);
374
+ const finalTemp = settings.temperature !== void 0 && settings.temperature !== null ? settings.temperature : existingModel?.temperature;
375
+ const finalTopP = settings.topP !== void 0 && settings.topP !== null ? settings.topP : existingModel?.topP;
376
+ const finalTopK = settings.topK !== void 0 && settings.topK !== null ? settings.topK : existingModel?.topK;
377
+ const finalMaxTokens = settings.maxTokens !== void 0 && settings.maxTokens !== null ? settings.maxTokens : existingModel?.maxTokens;
378
+ logger.info("Updating model settings", {
379
+ providerId,
380
+ modelId,
381
+ existing: existingModel,
382
+ incoming: settings,
383
+ final: { temperature: finalTemp, topP: finalTopP, topK: finalTopK, maxTokens: finalMaxTokens }
384
+ });
385
+ const updatedModel = {
386
+ id: modelId,
387
+ contextWindow: settings.contextWindow ?? existingModel?.contextWindow ?? 2e5,
388
+ source: "user",
389
+ ...finalTemp !== void 0 && { temperature: finalTemp },
390
+ ...finalTopP !== void 0 && { topP: finalTopP },
391
+ ...finalTopK !== void 0 && { topK: finalTopK },
392
+ ...finalMaxTokens !== void 0 && { maxTokens: finalMaxTokens }
393
+ };
394
+ if (existingModel) {
395
+ providers = providers.map(
396
+ (p) => p.id === providerId ? { ...p, models: p.models.map((m) => m.id === modelId ? updatedModel : m) } : p
397
+ );
398
+ } else {
399
+ providers = providers.map(
400
+ (p) => p.id === providerId ? { ...p, models: [...p.models, updatedModel] } : p
401
+ );
402
+ }
403
+ logger.info("Model settings updated", { providerId, modelId, final: updatedModel });
404
+ return { success: true, model: updatedModel };
405
+ },
406
+ getModelSettings(modelId) {
407
+ const provider = providers.find((p) => p.models.some((m) => m.id === modelId));
408
+ const model = provider?.models.find((m) => m.id === modelId);
409
+ if (!model) return void 0;
410
+ return {
411
+ ...model.temperature !== void 0 && { temperature: model.temperature },
412
+ ...model.topP !== void 0 && { topP: model.topP },
413
+ ...model.topK !== void 0 && { topK: model.topK },
414
+ ...model.maxTokens !== void 0 && { maxTokens: model.maxTokens }
415
+ };
416
+ },
366
417
  async refreshProviderModels(providerId) {
367
418
  const provider = providers.find((p) => p.id === providerId);
368
419
  if (!provider) {
@@ -406,4 +457,4 @@ export {
406
457
  parseDefaultModelSelection,
407
458
  createProviderManager
408
459
  };
409
- //# sourceMappingURL=chunk-KOUMYBYM.js.map
460
+ //# sourceMappingURL=chunk-PYBB34ZK.js.map