openfox 2.0.0-beta.9 → 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-6COBLIDR.js → chat-handler-LJMW4OK3.js} +9 -9
- package/dist/{chunk-LR5R7EEE.js → chunk-32GQUDLN.js} +22 -18
- package/dist/{chunk-DMH6JVPF.js → chunk-7ZMMDZU7.js} +431 -32
- package/dist/{chunk-CDDMHSZF.js → chunk-CK6LGE7G.js} +10 -6
- package/dist/{chunk-VIIRNJDT.js → chunk-FFEAEPJB.js} +80 -245
- package/dist/{chunk-EZUR7OEP.js → chunk-HPCGVAS4.js} +21 -45
- package/dist/{chunk-XJEOP6XU.js → chunk-ITWVFGFV.js} +1 -30
- package/dist/{chunk-C75I2KZM.js → chunk-LEDG5WAN.js} +29 -35
- package/dist/{chunk-KUG27ZUR.js → chunk-MFUPS6UE.js} +6 -6
- package/dist/{chunk-NPHYEUYE.js → chunk-XEK3KII6.js} +55 -4
- package/dist/{chunk-J2FFLZ5Z.js → chunk-ZDY4WMZJ.js} +184 -71
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{config-TDVA7MQN.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-ZNGTMZ7W.js → orchestrator-LX6FKB6L.js} +8 -8
- package/dist/package.json +2 -1
- package/dist/{processor-WMAU4C2N.js → processor-NMYSEBC7.js} +11 -6
- package/dist/{protocol-CDOV1pyc.d.ts → protocol-D59sCy9L.d.ts} +15 -6
- package/dist/{provider-BGH4MBLH.js → provider-DTNQYCMV.js} +9 -20
- package/dist/provider-manager-LMHAHLIF.js +15 -0
- package/dist/{serve-N3LBZUVN.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-CQGEU3JK.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-UKTPL5ZG.js +0 -469
- package/dist/web/assets/index-BJuF4wi7.js +0 -299
|
@@ -1,19 +1,389 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from "./chunk-UKTPL5ZG.js";
|
|
6
|
-
import {
|
|
7
|
-
buildModelsUrl,
|
|
8
|
-
detectBackend,
|
|
9
|
-
ensureVersionPrefix,
|
|
2
|
+
buildNonStreamingCreateParams,
|
|
3
|
+
buildStreamingCreateParams,
|
|
4
|
+
getBackendCapabilities,
|
|
10
5
|
getModelProfile,
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
getThinking,
|
|
7
|
+
mapFinishReason
|
|
8
|
+
} from "./chunk-FFEAEPJB.js";
|
|
13
9
|
import {
|
|
14
10
|
logger
|
|
15
11
|
} from "./chunk-K44MW7JJ.js";
|
|
16
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
|
+
|
|
17
387
|
// src/server/provider-manager.ts
|
|
18
388
|
function normalizeModelId(s) {
|
|
19
389
|
return s.toLowerCase().replace(/[-_\s:.]+/g, "");
|
|
@@ -163,6 +533,7 @@ function parseDefaultModelSelection(selection) {
|
|
|
163
533
|
}
|
|
164
534
|
function createProviderManager(config) {
|
|
165
535
|
let providers = [...config.providers ?? []];
|
|
536
|
+
providers = providers.map((p) => ({ ...p, models: p.models.map((m) => enrichWithProfileDefaults(m)) }));
|
|
166
537
|
let defaultModelSelection = config.defaultModelSelection;
|
|
167
538
|
let llmClient = createLLMClient(config);
|
|
168
539
|
const providerStatus = /* @__PURE__ */ new Map();
|
|
@@ -175,7 +546,16 @@ function createProviderManager(config) {
|
|
|
175
546
|
for (const p of providers) {
|
|
176
547
|
providerStatus.set(p.id, "unknown");
|
|
177
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
|
+
}
|
|
178
557
|
function createConfigForProvider(provider, model) {
|
|
558
|
+
const modelThinking = resolveModelThinkingConfig(provider, model);
|
|
179
559
|
return {
|
|
180
560
|
...config,
|
|
181
561
|
llm: {
|
|
@@ -183,7 +563,9 @@ function createProviderManager(config) {
|
|
|
183
563
|
baseUrl: ensureVersionPrefix(provider.url),
|
|
184
564
|
model,
|
|
185
565
|
backend: provider.backend,
|
|
186
|
-
...provider.apiKey && { apiKey: provider.apiKey }
|
|
566
|
+
...provider.apiKey && { apiKey: provider.apiKey },
|
|
567
|
+
...provider.thinkingField && { thinkingField: provider.thinkingField },
|
|
568
|
+
...modelThinking.reasoningEffort && { reasoningEffort: modelThinking.reasoningEffort }
|
|
187
569
|
}
|
|
188
570
|
};
|
|
189
571
|
}
|
|
@@ -238,11 +620,16 @@ function createProviderManager(config) {
|
|
|
238
620
|
const providerConfig = createConfigForProvider(provider, targetModel);
|
|
239
621
|
const newClient = createLLMClient(providerConfig);
|
|
240
622
|
try {
|
|
241
|
-
const
|
|
242
|
-
clearModelCache(
|
|
623
|
+
const cacheUrl = stripVersionPrefix(provider.url);
|
|
624
|
+
clearModelCache(cacheUrl);
|
|
243
625
|
const backend = provider.backend;
|
|
244
|
-
logger.info("activateProvider fetching models", {
|
|
245
|
-
|
|
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);
|
|
246
633
|
const userModels = provider.models.filter((m) => m.source === "user");
|
|
247
634
|
logger.debug("activateProvider", {
|
|
248
635
|
providerId,
|
|
@@ -259,14 +646,9 @@ function createProviderManager(config) {
|
|
|
259
646
|
});
|
|
260
647
|
providers = providers.map((p) => p.id === providerId ? { ...p, models: userModels } : p);
|
|
261
648
|
}
|
|
262
|
-
|
|
263
|
-
const detected = await detectBackend(url);
|
|
264
|
-
newClient.setBackend(detected);
|
|
265
|
-
} else {
|
|
266
|
-
newClient.setBackend(provider.backend);
|
|
267
|
-
}
|
|
649
|
+
newClient.setBackend(provider.backend);
|
|
268
650
|
if (targetModel === "auto") {
|
|
269
|
-
const detected = await detectModel(url);
|
|
651
|
+
const detected = await detectModel(provider.url);
|
|
270
652
|
if (detected) {
|
|
271
653
|
newClient.setModel(detected);
|
|
272
654
|
}
|
|
@@ -336,7 +718,7 @@ function createProviderManager(config) {
|
|
|
336
718
|
const newActiveProviderId = this.getActiveProviderId();
|
|
337
719
|
if (newActiveProviderId && newActiveProviderId !== wasActiveProviderId) {
|
|
338
720
|
const activeProvider = providers.find((p) => p.id === newActiveProviderId);
|
|
339
|
-
if (activeProvider) {
|
|
721
|
+
if (activeProvider && activeProvider.apiKey) {
|
|
340
722
|
const providerConfig = createConfigForProvider(activeProvider, this.getCurrentModel() ?? "auto");
|
|
341
723
|
llmClient = createLLMClient(providerConfig);
|
|
342
724
|
logger.info("setProviders: recreated LLM client for new active provider", {
|
|
@@ -358,9 +740,8 @@ function createProviderManager(config) {
|
|
|
358
740
|
if (provider.models && provider.models.length > 0) {
|
|
359
741
|
return provider.models;
|
|
360
742
|
}
|
|
361
|
-
const url = stripVersionPrefix(provider.url);
|
|
362
743
|
const backend = provider.backend;
|
|
363
|
-
return fetchModelsWithContext(url, provider.apiKey, backend);
|
|
744
|
+
return fetchModelsWithContext(provider.url, provider.apiKey, backend);
|
|
364
745
|
},
|
|
365
746
|
async setDefaultModelSelection(providerId, model) {
|
|
366
747
|
const provider = providers.find((p) => p.id === providerId);
|
|
@@ -440,7 +821,12 @@ function createProviderManager(config) {
|
|
|
440
821
|
...finalTopP !== void 0 && { topP: finalTopP },
|
|
441
822
|
...finalTopK !== void 0 && { topK: finalTopK },
|
|
442
823
|
...finalMaxTokens !== void 0 && { maxTokens: finalMaxTokens },
|
|
443
|
-
...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 } : {}
|
|
444
830
|
});
|
|
445
831
|
if (existingModel) {
|
|
446
832
|
providers = providers.map(
|
|
@@ -452,16 +838,18 @@ function createProviderManager(config) {
|
|
|
452
838
|
logger.info("Model settings updated", { providerId, modelId, final: updatedModel });
|
|
453
839
|
return { success: true, model: updatedModel };
|
|
454
840
|
},
|
|
455
|
-
getModelSettings(modelId) {
|
|
841
|
+
getModelSettings(modelId, mode = "thinking") {
|
|
456
842
|
const provider = providers.find((p) => p.models.some((m) => m.id === modelId));
|
|
457
843
|
const model = provider?.models.find((m) => m.id === modelId);
|
|
458
844
|
if (!model) return void 0;
|
|
845
|
+
const kwargs = mode === "non-thinking" ? model.nonThinkingEnabled ? model.nonThinkingExtraKwargs : model.thinkingExtraKwargs : model.thinkingEnabled ? model.thinkingExtraKwargs : model.nonThinkingExtraKwargs;
|
|
459
846
|
return {
|
|
460
847
|
...model.temperature !== void 0 && { temperature: model.temperature },
|
|
461
848
|
...model.topP !== void 0 && { topP: model.topP },
|
|
462
849
|
...model.topK !== void 0 && { topK: model.topK },
|
|
463
850
|
...model.maxTokens !== void 0 && { maxTokens: model.maxTokens },
|
|
464
|
-
...model.supportsVision !== void 0 && { supportsVision: model.supportsVision }
|
|
851
|
+
...model.supportsVision !== void 0 && { supportsVision: model.supportsVision },
|
|
852
|
+
...kwargs ? { chatTemplateKwargs: JSON.parse(kwargs) } : {}
|
|
465
853
|
};
|
|
466
854
|
},
|
|
467
855
|
async refreshProviderModels(providerId) {
|
|
@@ -469,10 +857,14 @@ function createProviderManager(config) {
|
|
|
469
857
|
if (!provider) {
|
|
470
858
|
return { success: false, error: "Provider not found" };
|
|
471
859
|
}
|
|
472
|
-
const url = stripVersionPrefix(provider.url);
|
|
473
860
|
const backend = provider.backend;
|
|
474
|
-
logger.info("refreshProviderModels fetching models", {
|
|
475
|
-
|
|
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);
|
|
476
868
|
const userModels = provider.models.filter((m) => m.source === "user");
|
|
477
869
|
logger.info("refreshProviderModels", {
|
|
478
870
|
providerId,
|
|
@@ -510,8 +902,15 @@ function createProviderManager(config) {
|
|
|
510
902
|
}
|
|
511
903
|
|
|
512
904
|
export {
|
|
905
|
+
SessionNotFoundError,
|
|
906
|
+
ensureVersionPrefix,
|
|
907
|
+
buildModelsUrl,
|
|
908
|
+
createLLMClient,
|
|
909
|
+
detectModel,
|
|
910
|
+
getLlmStatus,
|
|
513
911
|
fetchAvailableModelsFromBackend,
|
|
912
|
+
fetchModelsWithContext,
|
|
514
913
|
parseDefaultModelSelection,
|
|
515
914
|
createProviderManager
|
|
516
915
|
};
|
|
517
|
-
//# 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
|