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.
- package/README.md +11 -0
- package/dist/{chat-handler-XIAY7O5X.js → chat-handler-LJMW4OK3.js} +9 -9
- package/dist/{chunk-QN5ST54E.js → chunk-32GQUDLN.js} +118 -97
- package/dist/{chunk-IGSZUXQP.js → chunk-7ZMMDZU7.js} +435 -33
- package/dist/{chunk-CDDMHSZF.js → chunk-CK6LGE7G.js} +10 -6
- package/dist/{chunk-7FDY3EOH.js → chunk-FFEAEPJB.js} +80 -226
- package/dist/{chunk-2ZS2B5HW.js → chunk-HPCGVAS4.js} +21 -45
- package/dist/{chunk-XJEOP6XU.js → chunk-ITWVFGFV.js} +1 -30
- package/dist/{chunk-DFITQ75T.js → chunk-LEDG5WAN.js} +29 -35
- package/dist/{chunk-GJ47CMZM.js → chunk-MFUPS6UE.js} +6 -6
- package/dist/{chunk-NPHYEUYE.js → chunk-XEK3KII6.js} +55 -4
- package/dist/{chunk-GJ34YIOL.js → chunk-ZDY4WMZJ.js} +185 -71
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{config-QUT7YZQ7.js → config-BU66P4KX.js} +2 -7
- package/dist/{events-PQ3KTI5H.js → events-ZKWAKWI7.js} +3 -3
- package/dist/{folding-CXORTBAU.js → folding-YOCGTZYH.js} +2 -2
- package/dist/{orchestrator-GAOENX5Q.js → orchestrator-LX6FKB6L.js} +8 -8
- package/dist/package.json +2 -1
- package/dist/{processor-6VIYGURD.js → processor-NMYSEBC7.js} +11 -6
- package/dist/{protocol-CDOV1pyc.d.ts → protocol-D59sCy9L.d.ts} +15 -6
- package/dist/{provider-4T6BVPMD.js → provider-DTNQYCMV.js} +9 -20
- package/dist/provider-manager-LMHAHLIF.js +15 -0
- package/dist/{serve-2V7T6GDG.js → serve-SGNL43UL.js} +14 -15
- package/dist/server/index.d.ts +22 -16
- package/dist/server/index.js +9 -10
- package/dist/shared/index.d.ts +2 -2
- package/dist/{tools-SDXWIYSA.js → tools-BOE5T3KC.js} +7 -7
- package/dist/web/assets/index-Bego8SwT.js +299 -0
- package/dist/web/assets/{index-CSOB8dwI.css → index-Sdax8ayU.css} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/package.json +2 -1
- package/dist/chunk-EMJGF3A7.js +0 -466
- package/dist/web/assets/index-BJuF4wi7.js +0 -299
|
@@ -1,16 +1,389 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
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")
|
|
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
|
|
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
|
|
239
|
-
clearModelCache(
|
|
623
|
+
const cacheUrl = stripVersionPrefix(provider.url);
|
|
624
|
+
clearModelCache(cacheUrl);
|
|
240
625
|
const backend = provider.backend;
|
|
241
|
-
logger.info("activateProvider fetching models", {
|
|
242
|
-
|
|
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
|
-
|
|
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", {
|
|
472
|
-
|
|
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-
|
|
916
|
+
//# sourceMappingURL=chunk-7ZMMDZU7.js.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getEventStore,
|
|
3
3
|
updateSessionMetadata
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XEK3KII6.js";
|
|
5
5
|
import {
|
|
6
6
|
buildMessagesFromStoredEvents,
|
|
7
7
|
foldPendingConfirmations
|
|
8
|
-
} from "./chunk-
|
|
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
|
-
|
|
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-
|
|
150
|
+
//# sourceMappingURL=chunk-CK6LGE7G.js.map
|