openfox 2.0.0-beta.16 → 2.0.0-beta.17
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/dist/{chat-handler-7QLHIQOM.js → chat-handler-LJMW4OK3.js} +6 -6
- package/dist/{chunk-W52UQCER.js → chunk-32GQUDLN.js} +5 -5
- package/dist/{chunk-6CVDQJDV.js → chunk-7ZMMDZU7.js} +388 -17
- package/dist/{chunk-OKLV3ZNN.js → chunk-CK6LGE7G.js} +2 -2
- package/dist/{chunk-LXX2CPM5.js → chunk-FFEAEPJB.js} +1 -133
- package/dist/{chunk-N53OLRIU.js → chunk-HPCGVAS4.js} +12 -42
- package/dist/{chunk-D2QILH47.js → chunk-LEDG5WAN.js} +3 -3
- package/dist/{chunk-BE7YHSTL.js → chunk-PRBZSBKW.js} +44 -58
- package/dist/{chunk-LQWVMRMW.js → chunk-SN7ZAMHV.js} +6 -6
- package/dist/{chunk-DHAKJSE7.js → chunk-XEK3KII6.js} +2 -2
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{config-B6HYTLT4.js → config-BU66P4KX.js} +2 -7
- package/dist/{events-R7FRQEBE.js → events-ZKWAKWI7.js} +2 -2
- package/dist/{orchestrator-2AK4AYUD.js → orchestrator-LX6FKB6L.js} +5 -5
- package/dist/package.json +1 -1
- package/dist/{processor-IU56GBIW.js → processor-NMYSEBC7.js} +4 -4
- package/dist/{protocol-zn90yuIr.d.ts → protocol-D59sCy9L.d.ts} +3 -3
- package/dist/{provider-2JAXE5EA.js → provider-DTNQYCMV.js} +7 -18
- package/dist/{provider-manager-JMLJSPNX.js → provider-manager-LMHAHLIF.js} +3 -4
- package/dist/{serve-TFOO6AZH.js → serve-KB7IVU5D.js} +9 -10
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +6 -7
- package/dist/shared/index.d.ts +2 -2
- package/dist/{tools-VJMWGBUO.js → tools-BOE5T3KC.js} +4 -4
- package/dist/web/assets/{index-DCu8wsRj.js → index-Bego8SwT.js} +2 -2
- package/dist/web/index.html +1 -1
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-4F3C6X4M.js +0 -381
|
@@ -5,18 +5,18 @@ import {
|
|
|
5
5
|
generateSessionName,
|
|
6
6
|
getSessionMessageCount,
|
|
7
7
|
needsNameGenerationCheck
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-CK6LGE7G.js";
|
|
9
9
|
import {
|
|
10
10
|
runChatTurn
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-LEDG5WAN.js";
|
|
12
|
+
import "./chunk-32GQUDLN.js";
|
|
13
13
|
import "./chunk-DL6ZILAF.js";
|
|
14
14
|
import "./chunk-PBGOZMVY.js";
|
|
15
15
|
import "./chunk-VRGRAQDG.js";
|
|
16
16
|
import "./chunk-XAMAYRDA.js";
|
|
17
17
|
import {
|
|
18
18
|
getEventStore
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-XEK3KII6.js";
|
|
20
20
|
import "./chunk-ITWVFGFV.js";
|
|
21
21
|
import {
|
|
22
22
|
createChatMessageMessage,
|
|
@@ -28,7 +28,7 @@ import "./chunk-RFNEDBVO.js";
|
|
|
28
28
|
import "./chunk-FBGWG4N6.js";
|
|
29
29
|
import "./chunk-BVHFMAVN.js";
|
|
30
30
|
import "./chunk-CQGTEGKL.js";
|
|
31
|
-
import "./chunk-
|
|
31
|
+
import "./chunk-FFEAEPJB.js";
|
|
32
32
|
import {
|
|
33
33
|
logger
|
|
34
34
|
} from "./chunk-K44MW7JJ.js";
|
|
@@ -161,4 +161,4 @@ export {
|
|
|
161
161
|
startChatSession,
|
|
162
162
|
stopSessionExecution
|
|
163
163
|
};
|
|
164
|
-
//# sourceMappingURL=chat-handler-
|
|
164
|
+
//# sourceMappingURL=chat-handler-LJMW4OK3.js.map
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
getCurrentWindowMessageOptions,
|
|
23
23
|
getEventStore,
|
|
24
24
|
getRuntimeConfig
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-XEK3KII6.js";
|
|
26
26
|
import {
|
|
27
27
|
buildContextMessagesFromEventHistory,
|
|
28
28
|
foldContextState,
|
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
getModelProfile,
|
|
58
58
|
modelSupportsVision,
|
|
59
59
|
streamWithSegments
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-FFEAEPJB.js";
|
|
61
61
|
import {
|
|
62
62
|
logger
|
|
63
63
|
} from "./chunk-K44MW7JJ.js";
|
|
@@ -3280,7 +3280,7 @@ async function describeImageFromDataUrl(dataUrl, visionModel, options) {
|
|
|
3280
3280
|
import { createHash as createHash2 } from "crypto";
|
|
3281
3281
|
async function loadVisionModelFromGlobalConfig() {
|
|
3282
3282
|
try {
|
|
3283
|
-
const { loadGlobalConfig, getVisionFallback } = await import("./config-
|
|
3283
|
+
const { loadGlobalConfig, getVisionFallback } = await import("./config-BU66P4KX.js");
|
|
3284
3284
|
const runtimeConfig = getRuntimeConfig();
|
|
3285
3285
|
const mode = runtimeConfig.mode ?? "production";
|
|
3286
3286
|
const globalConfig = await loadGlobalConfig(mode);
|
|
@@ -3733,7 +3733,7 @@ var callSubAgentTool = {
|
|
|
3733
3733
|
};
|
|
3734
3734
|
}
|
|
3735
3735
|
try {
|
|
3736
|
-
const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-
|
|
3736
|
+
const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-BOE5T3KC.js");
|
|
3737
3737
|
const toolRegistry = getToolRegistryForAgent2(agentDef);
|
|
3738
3738
|
const turnMetrics = new TurnMetrics();
|
|
3739
3739
|
const result = await executeSubAgent({
|
|
@@ -4785,4 +4785,4 @@ export {
|
|
|
4785
4785
|
getToolRegistryForAgent,
|
|
4786
4786
|
createToolRegistry
|
|
4787
4787
|
};
|
|
4788
|
-
//# sourceMappingURL=chunk-
|
|
4788
|
+
//# sourceMappingURL=chunk-32GQUDLN.js.map
|
|
@@ -1,19 +1,389 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from "./chunk-4F3C6X4M.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, "");
|
|
@@ -276,12 +646,7 @@ function createProviderManager(config) {
|
|
|
276
646
|
});
|
|
277
647
|
providers = providers.map((p) => p.id === providerId ? { ...p, models: userModels } : p);
|
|
278
648
|
}
|
|
279
|
-
|
|
280
|
-
const detected = await detectBackend(provider.url);
|
|
281
|
-
newClient.setBackend(detected);
|
|
282
|
-
} else {
|
|
283
|
-
newClient.setBackend(provider.backend);
|
|
284
|
-
}
|
|
649
|
+
newClient.setBackend(provider.backend);
|
|
285
650
|
if (targetModel === "auto") {
|
|
286
651
|
const detected = await detectModel(provider.url);
|
|
287
652
|
if (detected) {
|
|
@@ -537,9 +902,15 @@ function createProviderManager(config) {
|
|
|
537
902
|
}
|
|
538
903
|
|
|
539
904
|
export {
|
|
905
|
+
SessionNotFoundError,
|
|
906
|
+
ensureVersionPrefix,
|
|
907
|
+
buildModelsUrl,
|
|
908
|
+
createLLMClient,
|
|
909
|
+
detectModel,
|
|
910
|
+
getLlmStatus,
|
|
540
911
|
fetchAvailableModelsFromBackend,
|
|
541
912
|
fetchModelsWithContext,
|
|
542
913
|
parseDefaultModelSelection,
|
|
543
914
|
createProviderManager
|
|
544
915
|
};
|
|
545
|
-
//# sourceMappingURL=chunk-
|
|
916
|
+
//# sourceMappingURL=chunk-7ZMMDZU7.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
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
|
|
@@ -147,4 +147,4 @@ export {
|
|
|
147
147
|
needsNameGenerationCheck,
|
|
148
148
|
applyGeneratedSessionName
|
|
149
149
|
};
|
|
150
|
-
//# sourceMappingURL=chunk-
|
|
150
|
+
//# sourceMappingURL=chunk-CK6LGE7G.js.map
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
logger
|
|
3
|
-
} from "./chunk-K44MW7JJ.js";
|
|
4
|
-
|
|
5
1
|
// src/server/llm/profiles.ts
|
|
6
2
|
var DEFAULT_PROFILE = {
|
|
7
3
|
name: "default",
|
|
@@ -172,22 +168,6 @@ function modelSupportsVision(modelName) {
|
|
|
172
168
|
return getModelProfile(modelName).supportsVision;
|
|
173
169
|
}
|
|
174
170
|
|
|
175
|
-
// src/server/llm/url-utils.ts
|
|
176
|
-
var VERSION_PREFIX_REGEX = /\/v\d+(\/|$)/;
|
|
177
|
-
function hasVersionPrefix(url) {
|
|
178
|
-
return VERSION_PREFIX_REGEX.test(url);
|
|
179
|
-
}
|
|
180
|
-
function ensureVersionPrefix(url, defaultVersion = "/v1") {
|
|
181
|
-
if (hasVersionPrefix(url)) return url;
|
|
182
|
-
return `${url.replace(/\/+$/, "")}${defaultVersion}`;
|
|
183
|
-
}
|
|
184
|
-
function stripVersionPrefix(url) {
|
|
185
|
-
return url.replace(/\/v\d+\/?$/, "");
|
|
186
|
-
}
|
|
187
|
-
function buildModelsUrl(baseUrl) {
|
|
188
|
-
return `${ensureVersionPrefix(baseUrl)}/models`;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
171
|
// src/server/llm/backend.ts
|
|
192
172
|
var BACKEND_CAPABILITIES = {
|
|
193
173
|
vllm: {
|
|
@@ -211,7 +191,6 @@ var BACKEND_CAPABILITIES = {
|
|
|
211
191
|
supportsTopK: true
|
|
212
192
|
},
|
|
213
193
|
unknown: {
|
|
214
|
-
// Assume vLLM-like for unknown backends
|
|
215
194
|
supportsChatTemplateKwargs: true,
|
|
216
195
|
supportsTopK: true
|
|
217
196
|
}
|
|
@@ -219,113 +198,6 @@ var BACKEND_CAPABILITIES = {
|
|
|
219
198
|
function getBackendCapabilities(backend) {
|
|
220
199
|
return BACKEND_CAPABILITIES[backend];
|
|
221
200
|
}
|
|
222
|
-
async function detectBackend(baseUrl, explicitBackend, silent = false) {
|
|
223
|
-
if (explicitBackend && explicitBackend !== "unknown") {
|
|
224
|
-
if (silent) {
|
|
225
|
-
logger.debug("Using explicit backend", { backend: explicitBackend });
|
|
226
|
-
} else {
|
|
227
|
-
logger.info("Using explicit backend", { backend: explicitBackend });
|
|
228
|
-
}
|
|
229
|
-
return explicitBackend;
|
|
230
|
-
}
|
|
231
|
-
const probeUrl = stripVersionPrefix(baseUrl);
|
|
232
|
-
try {
|
|
233
|
-
if (await probeOllama(probeUrl)) {
|
|
234
|
-
if (silent) {
|
|
235
|
-
logger.debug("Detected Ollama backend", { url: probeUrl });
|
|
236
|
-
} else {
|
|
237
|
-
logger.info("Detected Ollama backend", { url: probeUrl });
|
|
238
|
-
}
|
|
239
|
-
return "ollama";
|
|
240
|
-
}
|
|
241
|
-
if (await probeLlamaCpp(probeUrl)) {
|
|
242
|
-
if (silent) {
|
|
243
|
-
logger.debug("Detected llama.cpp backend", { url: probeUrl });
|
|
244
|
-
} else {
|
|
245
|
-
logger.info("Detected llama.cpp backend", { url: probeUrl });
|
|
246
|
-
}
|
|
247
|
-
return "llamacpp";
|
|
248
|
-
}
|
|
249
|
-
if (await probeSGLang(probeUrl)) {
|
|
250
|
-
if (silent) {
|
|
251
|
-
logger.debug("Detected SGLang backend", { url: probeUrl });
|
|
252
|
-
} else {
|
|
253
|
-
logger.info("Detected SGLang backend", { url: probeUrl });
|
|
254
|
-
}
|
|
255
|
-
return "sglang";
|
|
256
|
-
}
|
|
257
|
-
if (await probeOpenAI(baseUrl)) {
|
|
258
|
-
if (silent) {
|
|
259
|
-
logger.debug("Detected vLLM backend (OpenAI-compatible)", { url: baseUrl });
|
|
260
|
-
} else {
|
|
261
|
-
logger.info("Detected vLLM backend (OpenAI-compatible)", { url: baseUrl });
|
|
262
|
-
}
|
|
263
|
-
return "vllm";
|
|
264
|
-
}
|
|
265
|
-
if (silent) {
|
|
266
|
-
logger.debug("Could not detect backend, using unknown", { url: baseUrl });
|
|
267
|
-
} else {
|
|
268
|
-
logger.warn("Could not detect backend, using unknown", { url: baseUrl });
|
|
269
|
-
}
|
|
270
|
-
return "unknown";
|
|
271
|
-
} catch (error) {
|
|
272
|
-
if (silent) {
|
|
273
|
-
logger.debug("Backend detection failed", {
|
|
274
|
-
url: baseUrl,
|
|
275
|
-
error: error instanceof Error ? error.message : String(error)
|
|
276
|
-
});
|
|
277
|
-
} else {
|
|
278
|
-
logger.warn("Backend detection failed", {
|
|
279
|
-
url: baseUrl,
|
|
280
|
-
error: error instanceof Error ? error.message : String(error)
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
return "unknown";
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
async function probeOllama(baseUrl) {
|
|
287
|
-
try {
|
|
288
|
-
const response = await fetch(`${baseUrl}/api/tags`, {
|
|
289
|
-
signal: AbortSignal.timeout(5e3)
|
|
290
|
-
});
|
|
291
|
-
return response.ok;
|
|
292
|
-
} catch {
|
|
293
|
-
return false;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
async function probeLlamaCpp(baseUrl) {
|
|
297
|
-
try {
|
|
298
|
-
const response = await fetch(`${baseUrl}/health`, {
|
|
299
|
-
signal: AbortSignal.timeout(5e3)
|
|
300
|
-
});
|
|
301
|
-
if (!response.ok) return false;
|
|
302
|
-
const data = await response.json();
|
|
303
|
-
return "slots_idle" in data || "slots_processing" in data;
|
|
304
|
-
} catch {
|
|
305
|
-
return false;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
async function probeSGLang(baseUrl) {
|
|
309
|
-
try {
|
|
310
|
-
const response = await fetch(`${baseUrl}/get_model_info`, {
|
|
311
|
-
signal: AbortSignal.timeout(5e3)
|
|
312
|
-
});
|
|
313
|
-
return response.ok;
|
|
314
|
-
} catch {
|
|
315
|
-
return false;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
async function probeOpenAI(baseUrl) {
|
|
319
|
-
try {
|
|
320
|
-
const url = ensureVersionPrefix(baseUrl);
|
|
321
|
-
const response = await fetch(`${url}/models`, {
|
|
322
|
-
signal: AbortSignal.timeout(5e3)
|
|
323
|
-
});
|
|
324
|
-
return response.ok;
|
|
325
|
-
} catch {
|
|
326
|
-
return false;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
201
|
function getBackendDisplayName(backend) {
|
|
330
202
|
switch (backend) {
|
|
331
203
|
case "vllm":
|
|
@@ -616,11 +488,7 @@ async function* streamWithSegments(client, request) {
|
|
|
616
488
|
export {
|
|
617
489
|
getModelProfile,
|
|
618
490
|
modelSupportsVision,
|
|
619
|
-
ensureVersionPrefix,
|
|
620
|
-
stripVersionPrefix,
|
|
621
|
-
buildModelsUrl,
|
|
622
491
|
getBackendCapabilities,
|
|
623
|
-
detectBackend,
|
|
624
492
|
getBackendDisplayName,
|
|
625
493
|
buildModelParams,
|
|
626
494
|
getThinking,
|
|
@@ -629,4 +497,4 @@ export {
|
|
|
629
497
|
mapFinishReason,
|
|
630
498
|
streamWithSegments
|
|
631
499
|
};
|
|
632
|
-
//# sourceMappingURL=chunk-
|
|
500
|
+
//# sourceMappingURL=chunk-FFEAEPJB.js.map
|