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.
- package/README.md +46 -13
- package/dist/{auto-compaction-NFLWKJAO.js → auto-compaction-7LK3QGPI.js} +4 -3
- package/dist/{chat-handler-2RVTVNPF.js → chat-handler-ZU74RXED.js} +6 -5
- package/dist/{chunk-KOBGCNUE.js → chunk-4O3C2JMB.js} +58 -14
- package/dist/{chunk-QY7BMXWT.js → chunk-B7E3BICY.js} +6 -2
- package/dist/{chunk-U3KMU3UE.js → chunk-BOEXJCOD.js} +2 -2
- package/dist/{chunk-IN5EP4ZB.js → chunk-CJNQGEYG.js} +2 -2
- package/dist/{chunk-OVLFEBRR.js → chunk-D4ZLSV6P.js} +133 -468
- package/dist/{chunk-LTPZ4GTW.js → chunk-FTJPNCAV.js} +6 -6
- package/dist/chunk-KSASIV4B.js +486 -0
- package/dist/{chunk-ZDNXCVW4.js → chunk-P6GUT2QQ.js} +11 -5
- package/dist/{chunk-KOUMYBYM.js → chunk-PYBB34ZK.js} +54 -3
- package/dist/{chunk-R7UAGXQW.js → chunk-YCQSAFAQ.js} +42 -24
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{config-67AX6CNS.js → config-ACVEHBKG.js} +5 -5
- package/dist/{orchestrator-ZICQ5NIZ.js → orchestrator-OE7WFEW6.js} +5 -4
- package/dist/package.json +3 -3
- package/dist/{processor-MPSYT534.js → processor-GAOK7TPI.js} +2 -2
- package/dist/{protocol-I7rn7Msg.d.ts → protocol-BYM6rZvW.d.ts} +12 -0
- package/dist/{provider-DKGBQHUS.js → provider-RLQMVV2Z.js} +9 -8
- package/dist/{serve-B5A52252.js → serve-IBJ3SN3Q.js} +10 -10
- package/dist/server/index.d.ts +24 -1
- package/dist/server/index.js +8 -8
- package/dist/shared/index.d.ts +2 -2
- package/dist/shared/index.js +1 -1
- package/dist/{tools-ERJ3QRQU.js → tools-CSV7G554.js} +4 -3
- package/dist/{vision-fallback-ADYRFFD4.js → vision-fallback-QJ26DCEF.js} +2 -2
- package/dist/web/assets/index-BrZqZwpA.js +153 -0
- package/dist/web/assets/{index-vBklayFL.css → index-DF26vcqg.css} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-55N6FAAZ.js +0 -117
- 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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
460
|
+
//# sourceMappingURL=chunk-PYBB34ZK.js.map
|