openfox 2.0.0-beta.8 → 2.0.0

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 +11 -0
  2. package/dist/{chat-handler-XIAY7O5X.js → chat-handler-LJMW4OK3.js} +9 -9
  3. package/dist/{chunk-QN5ST54E.js → chunk-32GQUDLN.js} +118 -97
  4. package/dist/{chunk-IGSZUXQP.js → chunk-7ZMMDZU7.js} +435 -33
  5. package/dist/{chunk-CDDMHSZF.js → chunk-CK6LGE7G.js} +10 -6
  6. package/dist/{chunk-7FDY3EOH.js → chunk-FFEAEPJB.js} +80 -226
  7. package/dist/{chunk-2ZS2B5HW.js → chunk-HPCGVAS4.js} +21 -45
  8. package/dist/{chunk-XJEOP6XU.js → chunk-ITWVFGFV.js} +1 -30
  9. package/dist/{chunk-DFITQ75T.js → chunk-LEDG5WAN.js} +29 -35
  10. package/dist/{chunk-GJ47CMZM.js → chunk-MFUPS6UE.js} +6 -6
  11. package/dist/{chunk-NPHYEUYE.js → chunk-XEK3KII6.js} +55 -4
  12. package/dist/{chunk-GJ34YIOL.js → chunk-ZDY4WMZJ.js} +185 -71
  13. package/dist/cli/dev.js +1 -1
  14. package/dist/cli/index.js +1 -1
  15. package/dist/{config-QUT7YZQ7.js → config-BU66P4KX.js} +2 -7
  16. package/dist/{events-PQ3KTI5H.js → events-ZKWAKWI7.js} +3 -3
  17. package/dist/{folding-CXORTBAU.js → folding-YOCGTZYH.js} +2 -2
  18. package/dist/{orchestrator-GAOENX5Q.js → orchestrator-LX6FKB6L.js} +8 -8
  19. package/dist/package.json +2 -1
  20. package/dist/{processor-6VIYGURD.js → processor-NMYSEBC7.js} +11 -6
  21. package/dist/{protocol-CDOV1pyc.d.ts → protocol-D59sCy9L.d.ts} +15 -6
  22. package/dist/{provider-4T6BVPMD.js → provider-DTNQYCMV.js} +9 -20
  23. package/dist/provider-manager-LMHAHLIF.js +15 -0
  24. package/dist/{serve-2V7T6GDG.js → serve-SGNL43UL.js} +14 -15
  25. package/dist/server/index.d.ts +22 -16
  26. package/dist/server/index.js +9 -10
  27. package/dist/shared/index.d.ts +2 -2
  28. package/dist/{tools-SDXWIYSA.js → tools-BOE5T3KC.js} +7 -7
  29. package/dist/web/assets/index-Bego8SwT.js +299 -0
  30. package/dist/web/assets/{index-CSOB8dwI.css → index-Sdax8ayU.css} +1 -1
  31. package/dist/web/index.html +2 -2
  32. package/dist/web/sw.js +1 -1
  33. package/package.json +2 -1
  34. package/dist/chunk-EMJGF3A7.js +0 -466
  35. package/dist/web/assets/index-BJuF4wi7.js +0 -299
@@ -1,16 +1,389 @@
1
1
  import {
2
- clearModelCache,
3
- createLLMClient,
4
- detectModel
5
- } from "./chunk-EMJGF3A7.js";
6
- import {
7
- detectBackend,
8
- getModelProfile
9
- } from "./chunk-7FDY3EOH.js";
2
+ buildNonStreamingCreateParams,
3
+ buildStreamingCreateParams,
4
+ getBackendCapabilities,
5
+ getModelProfile,
6
+ getThinking,
7
+ mapFinishReason
8
+ } from "./chunk-FFEAEPJB.js";
10
9
  import {
11
10
  logger
12
11
  } from "./chunk-K44MW7JJ.js";
13
12
 
13
+ // src/server/llm/client.ts
14
+ import OpenAI from "openai";
15
+
16
+ // src/server/utils/errors.ts
17
+ var OpenFoxError = class extends Error {
18
+ constructor(message, code, details) {
19
+ super(message);
20
+ this.code = code;
21
+ this.details = details;
22
+ this.name = "OpenFoxError";
23
+ }
24
+ };
25
+ var SessionNotFoundError = class extends OpenFoxError {
26
+ constructor(sessionId) {
27
+ super(`Session not found: ${sessionId}`, "SESSION_NOT_FOUND", { sessionId });
28
+ this.name = "SessionNotFoundError";
29
+ }
30
+ };
31
+ var LLMError = class extends OpenFoxError {
32
+ constructor(message, details) {
33
+ super(message, "LLM_ERROR", details);
34
+ this.name = "LLMError";
35
+ }
36
+ };
37
+
38
+ // src/server/llm/url-utils.ts
39
+ var VERSION_PREFIX_REGEX = /\/v\d+(\/|$)/;
40
+ function hasVersionPrefix(url) {
41
+ return VERSION_PREFIX_REGEX.test(url);
42
+ }
43
+ function ensureVersionPrefix(url, defaultVersion = "/v1") {
44
+ if (hasVersionPrefix(url)) return url;
45
+ return `${url.replace(/\/+$/, "")}${defaultVersion}`;
46
+ }
47
+ function stripVersionPrefix(url) {
48
+ return url.replace(/\/v\d+\/?$/, "");
49
+ }
50
+ function buildModelsUrl(baseUrl) {
51
+ return `${ensureVersionPrefix(baseUrl)}/models`;
52
+ }
53
+
54
+ // src/server/llm/client.ts
55
+ import { Agent, setGlobalDispatcher } from "undici";
56
+ var agent = new Agent({ allowH2: true });
57
+ setGlobalDispatcher(agent);
58
+ function createLLMClient(config, initialBackend = "unknown") {
59
+ const baseURL = ensureVersionPrefix(config.llm.baseUrl);
60
+ const openai = new OpenAI({
61
+ baseURL,
62
+ apiKey: config.llm.apiKey ?? "not-needed"
63
+ });
64
+ let model = config.llm.model;
65
+ let profile = getModelProfile(model);
66
+ let backend = initialBackend;
67
+ let capabilities = getBackendCapabilities(backend);
68
+ const reasoningEffort = config.llm.reasoningEffort;
69
+ const thinkingField = config.llm.thinkingField;
70
+ const idleTimeout = config.llm.idleTimeout ?? 3e4;
71
+ return {
72
+ getModel() {
73
+ return model;
74
+ },
75
+ getProfile() {
76
+ return profile;
77
+ },
78
+ getBackend() {
79
+ return backend;
80
+ },
81
+ setBackend(newBackend) {
82
+ logger.debug("Setting LLM backend", { from: backend, to: newBackend });
83
+ backend = newBackend;
84
+ capabilities = getBackendCapabilities(newBackend);
85
+ },
86
+ setModel(newModel) {
87
+ const newProfile = getModelProfile(newModel);
88
+ logger.debug("Switching model", {
89
+ from: model,
90
+ to: newModel,
91
+ profile: newProfile.name,
92
+ temperature: newProfile.temperature
93
+ });
94
+ model = newModel;
95
+ profile = newProfile;
96
+ },
97
+ async complete(request) {
98
+ logger.debug("LLM complete request", {
99
+ messageCount: request.messages.length,
100
+ hasTools: !!request.tools?.length,
101
+ profile: profile.name,
102
+ reasoningEffort: request.reasoningEffort ?? reasoningEffort
103
+ });
104
+ try {
105
+ const resolvedEffort = request.reasoningEffort ?? reasoningEffort;
106
+ const { params: createParams } = await buildNonStreamingCreateParams({
107
+ model,
108
+ request,
109
+ profile,
110
+ capabilities,
111
+ ...resolvedEffort ? { reasoningEffort: resolvedEffort } : {},
112
+ ...thinkingField ? { thinkingField } : {}
113
+ });
114
+ const response = await openai.chat.completions.create(createParams, {
115
+ signal: request.signal
116
+ });
117
+ const choice = response.choices[0];
118
+ if (!choice) {
119
+ throw new LLMError("No completion choice returned");
120
+ }
121
+ const message = choice.message;
122
+ const content = message.content ?? "";
123
+ const thinkingContent = getThinking(message, thinkingField) ?? "";
124
+ const toolCalls = message.tool_calls?.map((tc) => ({
125
+ id: tc.id,
126
+ name: tc.function.name,
127
+ arguments: JSON.parse(tc.function.arguments)
128
+ }));
129
+ return {
130
+ id: response.id,
131
+ content,
132
+ ...thinkingContent ? { thinkingContent } : {},
133
+ ...toolCalls && toolCalls.length > 0 ? { toolCalls } : {},
134
+ finishReason: mapFinishReason(choice.finish_reason),
135
+ usage: {
136
+ promptTokens: response.usage?.prompt_tokens ?? 0,
137
+ completionTokens: response.usage?.completion_tokens ?? 0,
138
+ totalTokens: response.usage?.total_tokens ?? 0
139
+ }
140
+ };
141
+ } catch (error) {
142
+ logger.error("LLM complete error", { error: String(error) });
143
+ throw new LLMError(error instanceof Error ? error.message : "Unknown LLM error", {
144
+ originalError: error instanceof Error ? error : void 0
145
+ });
146
+ }
147
+ },
148
+ async *stream(request) {
149
+ const resolvedEffort = request.reasoningEffort ?? reasoningEffort;
150
+ logger.debug("LLM stream request", {
151
+ messageCount: request.messages.length,
152
+ hasTools: !!request.tools?.length,
153
+ profile: profile.name,
154
+ reasoningEffort: resolvedEffort,
155
+ idleTimeout
156
+ });
157
+ try {
158
+ const createParams = await buildStreamingCreateParams({
159
+ model,
160
+ request,
161
+ profile,
162
+ capabilities,
163
+ ...resolvedEffort ? { reasoningEffort: resolvedEffort } : {},
164
+ ...thinkingField ? { thinkingField } : {}
165
+ });
166
+ const { params: streamingParams } = createParams;
167
+ const stream = await openai.chat.completions.create(streamingParams, {
168
+ signal: request.signal
169
+ });
170
+ let fullContent = "";
171
+ let fullThinking = "";
172
+ const toolCalls = /* @__PURE__ */ new Map();
173
+ let finishReason = "stop";
174
+ let usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
175
+ let responseId = "";
176
+ let lastChunkTime = Date.now();
177
+ const idleTimeoutController = new AbortController();
178
+ const idleTimer = setInterval(() => {
179
+ const idleDuration = Date.now() - lastChunkTime;
180
+ if (idleDuration > idleTimeout) {
181
+ logger.warn("LLM stream idle timeout triggered", { idleDuration, idleTimeout });
182
+ idleTimeoutController.abort();
183
+ }
184
+ }, 100);
185
+ const onAbort = () => clearInterval(idleTimer);
186
+ request.signal?.addEventListener("abort", onAbort, { once: true });
187
+ try {
188
+ for await (const chunk of stream) {
189
+ if (idleTimeoutController.signal.aborted) {
190
+ throw new Error(`LLM stream idle timeout: no chunks received for ${idleTimeout}ms`);
191
+ }
192
+ lastChunkTime = Date.now();
193
+ responseId = chunk.id;
194
+ if (chunk.usage) {
195
+ usage = {
196
+ promptTokens: chunk.usage.prompt_tokens,
197
+ completionTokens: chunk.usage.completion_tokens,
198
+ totalTokens: chunk.usage.total_tokens
199
+ };
200
+ }
201
+ const choice = chunk.choices[0];
202
+ if (!choice) continue;
203
+ if (choice.finish_reason) {
204
+ finishReason = mapFinishReason(choice.finish_reason);
205
+ }
206
+ const delta = choice.delta;
207
+ const reasoning = getThinking(delta, thinkingField);
208
+ if (reasoning) {
209
+ fullThinking += reasoning;
210
+ yield { type: "thinking_delta", content: reasoning };
211
+ }
212
+ if (delta.content) {
213
+ fullContent += delta.content;
214
+ yield { type: "text_delta", content: delta.content };
215
+ }
216
+ if (delta.tool_calls) {
217
+ for (const tc of delta.tool_calls) {
218
+ const existing = toolCalls.get(tc.index);
219
+ if (!existing) {
220
+ toolCalls.set(tc.index, {
221
+ id: tc.id ?? "",
222
+ name: tc.function?.name ?? "",
223
+ arguments: tc.function?.arguments ?? ""
224
+ });
225
+ } else {
226
+ if (tc.id) existing.id = tc.id;
227
+ if (tc.function?.name) existing.name += tc.function.name;
228
+ if (tc.function?.arguments) existing.arguments += tc.function.arguments;
229
+ }
230
+ yield {
231
+ type: "tool_call_delta",
232
+ index: tc.index,
233
+ ...tc.id ? { id: tc.id } : {},
234
+ ...tc.function?.name ? { name: tc.function.name } : {},
235
+ ...tc.function?.arguments ? { arguments: tc.function.arguments } : {}
236
+ };
237
+ }
238
+ }
239
+ }
240
+ } finally {
241
+ clearInterval(idleTimer);
242
+ request.signal?.removeEventListener("abort", onAbort);
243
+ }
244
+ const finalContent = fullContent.trim();
245
+ const finalThinking = fullThinking.trim();
246
+ const parsedToolCalls = [];
247
+ for (const [, tc] of toolCalls) {
248
+ try {
249
+ parsedToolCalls.push({
250
+ id: tc.id,
251
+ name: tc.name,
252
+ arguments: JSON.parse(tc.arguments)
253
+ });
254
+ } catch (error) {
255
+ logger.warn("Failed to parse tool call arguments", { name: tc.name, arguments: tc.arguments });
256
+ parsedToolCalls.push({
257
+ id: tc.id,
258
+ name: tc.name,
259
+ arguments: {},
260
+ parseError: error instanceof Error ? error.message : "Unknown JSON parse error",
261
+ rawArguments: tc.arguments
262
+ });
263
+ }
264
+ }
265
+ yield {
266
+ type: "done",
267
+ response: {
268
+ id: responseId,
269
+ content: finalContent,
270
+ ...finalThinking ? { thinkingContent: finalThinking } : {},
271
+ ...parsedToolCalls.length > 0 ? { toolCalls: parsedToolCalls } : {},
272
+ finishReason,
273
+ usage
274
+ }
275
+ };
276
+ } catch (error) {
277
+ logger.error("LLM stream error", { error });
278
+ yield {
279
+ type: "error",
280
+ error: error instanceof Error ? error.message : "Unknown LLM error"
281
+ };
282
+ }
283
+ }
284
+ };
285
+ }
286
+
287
+ // src/server/llm/models.ts
288
+ var modelCache = /* @__PURE__ */ new Map();
289
+ var llmStatus = "unknown";
290
+ var lastActiveUrl = null;
291
+ var CACHE_TTL_MS = 3e4;
292
+ function getCacheKey(url) {
293
+ return stripVersionPrefix(url);
294
+ }
295
+ async function detectModel(llmBaseUrl, retries = 3, silent = false) {
296
+ const cacheKey = getCacheKey(llmBaseUrl);
297
+ const now = Date.now();
298
+ const cached = modelCache.get(cacheKey);
299
+ if (cached && now - cached.timestamp < CACHE_TTL_MS) {
300
+ lastActiveUrl = cacheKey;
301
+ llmStatus = "connected";
302
+ return cached.model;
303
+ }
304
+ const url = buildModelsUrl(llmBaseUrl);
305
+ for (let attempt = 1; attempt <= retries; attempt++) {
306
+ try {
307
+ if (silent) {
308
+ logger.debug("Fetching models from LLM server", { url, attempt });
309
+ }
310
+ const response = await fetch(url, {
311
+ signal: AbortSignal.timeout(1e4)
312
+ });
313
+ if (!response.ok) {
314
+ if (silent) {
315
+ logger.debug("Failed to fetch models from LLM server", { status: response.status, attempt });
316
+ } else {
317
+ logger.warn("Failed to fetch models from LLM server", { status: response.status, attempt });
318
+ }
319
+ if (attempt < retries) {
320
+ await new Promise((r) => setTimeout(r, 1e3 * attempt));
321
+ continue;
322
+ }
323
+ llmStatus = "disconnected";
324
+ return cached?.model ?? null;
325
+ }
326
+ const data = await response.json();
327
+ if (data.data && data.data.length > 0) {
328
+ const modelData = data.data[0];
329
+ const modelId = modelData.id;
330
+ modelCache.set(cacheKey, {
331
+ model: modelId,
332
+ modelInfo: modelData,
333
+ timestamp: now
334
+ });
335
+ lastActiveUrl = cacheKey;
336
+ llmStatus = "connected";
337
+ if (silent) {
338
+ logger.debug("Detected LLM model", {
339
+ model: modelId,
340
+ maxLen: modelData.max_model_len,
341
+ root: modelData.root
342
+ });
343
+ } else {
344
+ logger.info("Detected LLM model", {
345
+ model: modelId,
346
+ maxLen: modelData.max_model_len,
347
+ root: modelData.root
348
+ });
349
+ }
350
+ return modelId;
351
+ }
352
+ if (silent) {
353
+ logger.debug("LLM server returned empty models list");
354
+ } else {
355
+ logger.warn("LLM server returned empty models list");
356
+ }
357
+ llmStatus = "disconnected";
358
+ return null;
359
+ } catch (error) {
360
+ const errMsg = error instanceof Error ? error.message : String(error);
361
+ if (silent) {
362
+ logger.debug("Could not detect model from LLM server", { error: errMsg, attempt });
363
+ } else {
364
+ logger.warn("Could not detect model from LLM server", { error: errMsg, attempt });
365
+ }
366
+ if (attempt < retries) {
367
+ await new Promise((r) => setTimeout(r, 1e3 * attempt));
368
+ continue;
369
+ }
370
+ }
371
+ }
372
+ llmStatus = "disconnected";
373
+ return cached?.model ?? null;
374
+ }
375
+ function getLlmStatus() {
376
+ return llmStatus;
377
+ }
378
+ function clearModelCache(url) {
379
+ if (url) {
380
+ modelCache.delete(getCacheKey(url));
381
+ } else {
382
+ modelCache.clear();
383
+ }
384
+ llmStatus = "unknown";
385
+ }
386
+
14
387
  // src/server/provider-manager.ts
15
388
  function normalizeModelId(s) {
16
389
  return s.toLowerCase().replace(/[-_\s:.]+/g, "");
@@ -67,7 +440,7 @@ function mergeModelsWithUserOverrides(backendModels, userModels) {
67
440
  return updatedModels;
68
441
  }
69
442
  async function fetchAvailableModelsFromBackend(baseUrl, apiKey) {
70
- const url = baseUrl.includes("/v1") ? `${baseUrl}/models` : `${baseUrl}/v1/models`;
443
+ const url = buildModelsUrl(baseUrl);
71
444
  const models = await fetchModelsFromBackend(url, apiKey);
72
445
  return models.map((m) => m.id);
73
446
  }
@@ -78,7 +451,7 @@ async function fetchModelsWithContext(baseUrl, apiKey, backend) {
78
451
  return fetchOllamaModelsWithContext(baseUrl, apiKey);
79
452
  }
80
453
  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`;
454
+ const url = isOpenCodeGo ? buildModelsUrl(baseUrl.replace("/zen/go", "/zen")) : buildModelsUrl(baseUrl);
82
455
  logger.info("Fetching models via /v1/models", { url });
83
456
  const models = await fetchModelsFromBackend(url, apiKey);
84
457
  if (models.length === 0) return [];
@@ -160,6 +533,7 @@ function parseDefaultModelSelection(selection) {
160
533
  }
161
534
  function createProviderManager(config) {
162
535
  let providers = [...config.providers ?? []];
536
+ providers = providers.map((p) => ({ ...p, models: p.models.map((m) => enrichWithProfileDefaults(m)) }));
163
537
  let defaultModelSelection = config.defaultModelSelection;
164
538
  let llmClient = createLLMClient(config);
165
539
  const providerStatus = /* @__PURE__ */ new Map();
@@ -172,15 +546,26 @@ function createProviderManager(config) {
172
546
  for (const p of providers) {
173
547
  providerStatus.set(p.id, "unknown");
174
548
  }
549
+ function resolveModelThinkingConfig(provider, modelId) {
550
+ const modelConfig = provider.models.find((m) => m.id === modelId);
551
+ if (!modelConfig) return {};
552
+ if (modelConfig.thinkingEnabled && modelConfig.thinkingLevel) {
553
+ return { reasoningEffort: modelConfig.thinkingLevel };
554
+ }
555
+ return {};
556
+ }
175
557
  function createConfigForProvider(provider, model) {
558
+ const modelThinking = resolveModelThinkingConfig(provider, model);
176
559
  return {
177
560
  ...config,
178
561
  llm: {
179
562
  ...config.llm,
180
- baseUrl: provider.url.includes("/v1") ? provider.url : `${provider.url}/v1`,
563
+ baseUrl: ensureVersionPrefix(provider.url),
181
564
  model,
182
565
  backend: provider.backend,
183
- ...provider.apiKey && { apiKey: provider.apiKey }
566
+ ...provider.apiKey && { apiKey: provider.apiKey },
567
+ ...provider.thinkingField && { thinkingField: provider.thinkingField },
568
+ ...modelThinking.reasoningEffort && { reasoningEffort: modelThinking.reasoningEffort }
184
569
  }
185
570
  };
186
571
  }
@@ -235,11 +620,16 @@ function createProviderManager(config) {
235
620
  const providerConfig = createConfigForProvider(provider, targetModel);
236
621
  const newClient = createLLMClient(providerConfig);
237
622
  try {
238
- const url = provider.url.includes("/v1") ? provider.url.replace("/v1", "") : provider.url;
239
- clearModelCache(url);
623
+ const cacheUrl = stripVersionPrefix(provider.url);
624
+ clearModelCache(cacheUrl);
240
625
  const backend = provider.backend;
241
- logger.info("activateProvider fetching models", { providerId, providerName: provider.name, url, backend });
242
- const modelsWithContext = await fetchModelsWithContext(url, provider.apiKey, backend);
626
+ logger.info("activateProvider fetching models", {
627
+ providerId,
628
+ providerName: provider.name,
629
+ url: provider.url,
630
+ backend
631
+ });
632
+ const modelsWithContext = await fetchModelsWithContext(provider.url, provider.apiKey, backend);
243
633
  const userModels = provider.models.filter((m) => m.source === "user");
244
634
  logger.debug("activateProvider", {
245
635
  providerId,
@@ -256,14 +646,9 @@ function createProviderManager(config) {
256
646
  });
257
647
  providers = providers.map((p) => p.id === providerId ? { ...p, models: userModels } : p);
258
648
  }
259
- if (provider.backend === "auto") {
260
- const detected = await detectBackend(url);
261
- newClient.setBackend(detected);
262
- } else {
263
- newClient.setBackend(provider.backend);
264
- }
649
+ newClient.setBackend(provider.backend);
265
650
  if (targetModel === "auto") {
266
- const detected = await detectModel(url);
651
+ const detected = await detectModel(provider.url);
267
652
  if (detected) {
268
653
  newClient.setModel(detected);
269
654
  }
@@ -333,7 +718,7 @@ function createProviderManager(config) {
333
718
  const newActiveProviderId = this.getActiveProviderId();
334
719
  if (newActiveProviderId && newActiveProviderId !== wasActiveProviderId) {
335
720
  const activeProvider = providers.find((p) => p.id === newActiveProviderId);
336
- if (activeProvider) {
721
+ if (activeProvider && activeProvider.apiKey) {
337
722
  const providerConfig = createConfigForProvider(activeProvider, this.getCurrentModel() ?? "auto");
338
723
  llmClient = createLLMClient(providerConfig);
339
724
  logger.info("setProviders: recreated LLM client for new active provider", {
@@ -355,9 +740,8 @@ function createProviderManager(config) {
355
740
  if (provider.models && provider.models.length > 0) {
356
741
  return provider.models;
357
742
  }
358
- const url = provider.url.includes("/v1") ? provider.url.replace("/v1", "") : provider.url;
359
743
  const backend = provider.backend;
360
- return fetchModelsWithContext(url, provider.apiKey, backend);
744
+ return fetchModelsWithContext(provider.url, provider.apiKey, backend);
361
745
  },
362
746
  async setDefaultModelSelection(providerId, model) {
363
747
  const provider = providers.find((p) => p.id === providerId);
@@ -437,7 +821,12 @@ function createProviderManager(config) {
437
821
  ...finalTopP !== void 0 && { topP: finalTopP },
438
822
  ...finalTopK !== void 0 && { topK: finalTopK },
439
823
  ...finalMaxTokens !== void 0 && { maxTokens: finalMaxTokens },
440
- ...finalSupportsVision !== void 0 && { supportsVision: finalSupportsVision }
824
+ ...finalSupportsVision !== void 0 && { supportsVision: finalSupportsVision },
825
+ ...settings.thinkingEnabled !== void 0 ? { thinkingEnabled: settings.thinkingEnabled } : existingModel?.thinkingEnabled !== void 0 ? { thinkingEnabled: existingModel.thinkingEnabled } : {},
826
+ ...settings.thinkingLevel !== void 0 ? { thinkingLevel: settings.thinkingLevel } : existingModel?.thinkingLevel !== void 0 ? { thinkingLevel: existingModel.thinkingLevel } : {},
827
+ ...settings.nonThinkingEnabled !== void 0 ? { nonThinkingEnabled: settings.nonThinkingEnabled } : existingModel?.nonThinkingEnabled !== void 0 ? { nonThinkingEnabled: existingModel.nonThinkingEnabled } : {},
828
+ ...settings.thinkingExtraKwargs !== void 0 ? { thinkingExtraKwargs: settings.thinkingExtraKwargs } : existingModel?.thinkingExtraKwargs !== void 0 ? { thinkingExtraKwargs: existingModel.thinkingExtraKwargs } : {},
829
+ ...settings.nonThinkingExtraKwargs !== void 0 ? { nonThinkingExtraKwargs: settings.nonThinkingExtraKwargs } : existingModel?.nonThinkingExtraKwargs !== void 0 ? { nonThinkingExtraKwargs: existingModel.nonThinkingExtraKwargs } : {}
441
830
  });
442
831
  if (existingModel) {
443
832
  providers = providers.map(
@@ -449,16 +838,18 @@ function createProviderManager(config) {
449
838
  logger.info("Model settings updated", { providerId, modelId, final: updatedModel });
450
839
  return { success: true, model: updatedModel };
451
840
  },
452
- getModelSettings(modelId) {
841
+ getModelSettings(modelId, mode = "thinking") {
453
842
  const provider = providers.find((p) => p.models.some((m) => m.id === modelId));
454
843
  const model = provider?.models.find((m) => m.id === modelId);
455
844
  if (!model) return void 0;
845
+ const kwargs = mode === "non-thinking" ? model.nonThinkingEnabled ? model.nonThinkingExtraKwargs : model.thinkingExtraKwargs : model.thinkingEnabled ? model.thinkingExtraKwargs : model.nonThinkingExtraKwargs;
456
846
  return {
457
847
  ...model.temperature !== void 0 && { temperature: model.temperature },
458
848
  ...model.topP !== void 0 && { topP: model.topP },
459
849
  ...model.topK !== void 0 && { topK: model.topK },
460
850
  ...model.maxTokens !== void 0 && { maxTokens: model.maxTokens },
461
- ...model.supportsVision !== void 0 && { supportsVision: model.supportsVision }
851
+ ...model.supportsVision !== void 0 && { supportsVision: model.supportsVision },
852
+ ...kwargs ? { chatTemplateKwargs: JSON.parse(kwargs) } : {}
462
853
  };
463
854
  },
464
855
  async refreshProviderModels(providerId) {
@@ -466,10 +857,14 @@ function createProviderManager(config) {
466
857
  if (!provider) {
467
858
  return { success: false, error: "Provider not found" };
468
859
  }
469
- const url = provider.url.includes("/v1") ? provider.url.replace("/v1", "") : provider.url;
470
860
  const backend = provider.backend;
471
- logger.info("refreshProviderModels fetching models", { providerId, providerName: provider.name, url, backend });
472
- const modelsWithContext = await fetchModelsWithContext(url, provider.apiKey, backend);
861
+ logger.info("refreshProviderModels fetching models", {
862
+ providerId,
863
+ providerName: provider.name,
864
+ url: provider.url,
865
+ backend
866
+ });
867
+ const modelsWithContext = await fetchModelsWithContext(provider.url, provider.apiKey, backend);
473
868
  const userModels = provider.models.filter((m) => m.source === "user");
474
869
  logger.info("refreshProviderModels", {
475
870
  providerId,
@@ -507,8 +902,15 @@ function createProviderManager(config) {
507
902
  }
508
903
 
509
904
  export {
905
+ SessionNotFoundError,
906
+ ensureVersionPrefix,
907
+ buildModelsUrl,
908
+ createLLMClient,
909
+ detectModel,
910
+ getLlmStatus,
510
911
  fetchAvailableModelsFromBackend,
912
+ fetchModelsWithContext,
511
913
  parseDefaultModelSelection,
512
914
  createProviderManager
513
915
  };
514
- //# sourceMappingURL=chunk-IGSZUXQP.js.map
916
+ //# sourceMappingURL=chunk-7ZMMDZU7.js.map
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  getEventStore,
3
3
  updateSessionMetadata
4
- } from "./chunk-NPHYEUYE.js";
4
+ } from "./chunk-XEK3KII6.js";
5
5
  import {
6
6
  buildMessagesFromStoredEvents,
7
7
  foldPendingConfirmations
8
- } from "./chunk-XJEOP6XU.js";
8
+ } from "./chunk-ITWVFGFV.js";
9
9
  import {
10
10
  createContextStateMessage,
11
11
  createSessionStateMessage
@@ -56,7 +56,7 @@ Example inputs and outputs:
56
56
 
57
57
  User message: {message}`;
58
58
  async function generateSessionName(options) {
59
- const { userMessage, llmClient, signal } = options;
59
+ const { userMessage, llmClient, signal, modelSettings, nonThinkingEnabled } = options;
60
60
  try {
61
61
  logger.debug("Generating session name", { messagePreview: userMessage.slice(0, 50) });
62
62
  const prompt = SESSION_NAME_PROMPT.replace("{message}", userMessage);
@@ -72,9 +72,13 @@ async function generateSessionName(options) {
72
72
  messages,
73
73
  tools: [],
74
74
  signal: composedSignal,
75
- disableThinking: true
75
+ // Default to non-thinking (reasoningEffort: 'none') when not explicitly configured
76
+ // to prevent thinking output in session names. Only skip when user explicitly
77
+ // set nonThinkingEnabled to false.
78
+ ...nonThinkingEnabled !== false ? { reasoningEffort: "none" } : {},
79
+ ...modelSettings ? { modelSettings } : {}
76
80
  });
77
- let name = response.content.trim();
81
+ let name = (response.content || response.thinkingContent || "").trim();
78
82
  if (name.length > 50) {
79
83
  name = name.substring(0, 47) + "...";
80
84
  }
@@ -143,4 +147,4 @@ export {
143
147
  needsNameGenerationCheck,
144
148
  applyGeneratedSessionName
145
149
  };
146
- //# sourceMappingURL=chunk-CDDMHSZF.js.map
150
+ //# sourceMappingURL=chunk-CK6LGE7G.js.map