openfox 1.6.14 → 1.6.16
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/{auto-compaction-C4PMBB24.js → auto-compaction-2RKC6DC2.js} +5 -5
- package/dist/{chat-handler-US3QOOE4.js → chat-handler-IY2XVOO6.js} +26 -56
- package/dist/{chunk-7HLRI6JM.js → chunk-2KP34IDL.js} +161 -204
- package/dist/{chunk-N25QUEPO.js → chunk-4OI4VPZ6.js} +434 -812
- package/dist/{chunk-XFXOSPYH.js → chunk-55N6FAAZ.js} +1 -1
- package/dist/{chunk-5GE3QJSZ.js → chunk-6L3X7T4K.js} +82 -160
- package/dist/{chunk-QDEKU5RL.js → chunk-F54ZJN4X.js} +38 -2
- package/dist/{chunk-UL4JYQKK.js → chunk-IN5EP4ZB.js} +2 -2
- package/dist/{chunk-OOIRCXAY.js → chunk-KOUMYBYM.js} +53 -112
- package/dist/{chunk-3JU6H6A4.js → chunk-NN65D5SI.js} +426 -448
- package/dist/{chunk-3XZ23PXM.js → chunk-OVLFEBRR.js} +76 -92
- package/dist/chunk-SN7OBEVL.js +44 -0
- package/dist/{chunk-PCOG5FQD.js → chunk-T5PBG2PE.js} +6 -6
- package/dist/{chunk-H22VHHQ4.js → chunk-U54QVKL2.js} +4 -4
- package/dist/{chunk-J2DHVXRX.js → chunk-ZDNXCVW4.js} +2 -2
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{config-DEM6ASQM.js → config-67AX6CNS.js} +5 -5
- package/dist/{events-VDAC7E7K.js → events-2ETDOE5B.js} +3 -3
- package/dist/{folding-NDFQCISZ.js → folding-M7FMUBOL.js} +6 -4
- package/dist/{orchestrator-KZI7B5IS.js → orchestrator-U5VCLBYQ.js} +6 -6
- package/dist/package.json +13 -3
- package/dist/{processor-KBSF2HFD.js → processor-VUEJM73B.js} +24 -49
- package/dist/{provider-K3PHZO27.js → provider-DKGBQHUS.js} +7 -7
- package/dist/{serve-DERN4AB6.js → serve-GOLQMQFA.js} +12 -12
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +10 -10
- package/dist/{tools-PLVK22CF.js → tools-55YICCVH.js} +5 -5
- package/dist/{vision-fallback-NOC3YYIB.js → vision-fallback-ADYRFFD4.js} +2 -2
- package/dist/web/assets/index-CZBXRYpK.js +150 -0
- package/dist/web/assets/{index-MCWDS5UQ.css → index-D4V7Gtvt.css} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/package.json +13 -3
- package/dist/web/assets/index-Ccy2Csbl.js +0 -150
- /package/dist/{command-defaults → server/commands/defaults}/commit-push.command.md +0 -0
- /package/dist/{command-defaults → server/commands/defaults}/init.command.md +0 -0
- /package/dist/{command-defaults → server/commands/defaults}/test-ui.command.md +0 -0
- /package/dist/{skill-defaults → server/skills/defaults}/browser.skill.md +0 -0
|
@@ -2,8 +2,10 @@ import {
|
|
|
2
2
|
buildContextMessagesFromEventHistory,
|
|
3
3
|
buildMessagesFromStoredEvents,
|
|
4
4
|
foldContextState,
|
|
5
|
-
foldSessionState
|
|
6
|
-
|
|
5
|
+
foldSessionState,
|
|
6
|
+
spreadOptionalMessageFields,
|
|
7
|
+
stripPromptContextMessages
|
|
8
|
+
} from "./chunk-2KP34IDL.js";
|
|
7
9
|
import {
|
|
8
10
|
getDatabase
|
|
9
11
|
} from "./chunk-3EHGGBWE.js";
|
|
@@ -15,6 +17,61 @@ import {
|
|
|
15
17
|
} from "./chunk-PNBH3RAX.js";
|
|
16
18
|
|
|
17
19
|
// src/server/events/store.ts
|
|
20
|
+
function createEventIterator(state, subscriber) {
|
|
21
|
+
return {
|
|
22
|
+
[Symbol.asyncIterator]() {
|
|
23
|
+
return this;
|
|
24
|
+
},
|
|
25
|
+
async next() {
|
|
26
|
+
if (state.closed) {
|
|
27
|
+
return { value: void 0, done: true };
|
|
28
|
+
}
|
|
29
|
+
const queued = state.queue.shift();
|
|
30
|
+
if (queued) {
|
|
31
|
+
return { value: queued, done: false };
|
|
32
|
+
}
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
state.resolveNext = resolve;
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
async return() {
|
|
38
|
+
state.closed = true;
|
|
39
|
+
subscriber.closed = true;
|
|
40
|
+
return { value: void 0, done: true };
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function createIteratorState() {
|
|
45
|
+
const state = {
|
|
46
|
+
closed: false,
|
|
47
|
+
queue: [],
|
|
48
|
+
resolveNext: null,
|
|
49
|
+
closeIterator: () => {
|
|
50
|
+
state.closed = true;
|
|
51
|
+
if (state.resolveNext) {
|
|
52
|
+
state.resolveNext({ value: void 0, done: true });
|
|
53
|
+
state.resolveNext = null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
return state;
|
|
58
|
+
}
|
|
59
|
+
function createSubscriber(state, id) {
|
|
60
|
+
return {
|
|
61
|
+
...id,
|
|
62
|
+
callback: (event) => {
|
|
63
|
+
if (state.closed) return;
|
|
64
|
+
if (state.resolveNext) {
|
|
65
|
+
state.resolveNext({ value: event, done: false });
|
|
66
|
+
state.resolveNext = null;
|
|
67
|
+
} else {
|
|
68
|
+
state.queue.push(event);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
close: state.closeIterator,
|
|
72
|
+
closed: false
|
|
73
|
+
};
|
|
74
|
+
}
|
|
18
75
|
var EventStore = class {
|
|
19
76
|
db;
|
|
20
77
|
subscribers = /* @__PURE__ */ new Map();
|
|
@@ -176,30 +233,8 @@ var EventStore = class {
|
|
|
176
233
|
* Returns an async iterator that yields events and an unsubscribe function
|
|
177
234
|
*/
|
|
178
235
|
subscribe(sessionId, fromSeq) {
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
let closed = false;
|
|
182
|
-
const closeIterator = () => {
|
|
183
|
-
closed = true;
|
|
184
|
-
if (resolveNext) {
|
|
185
|
-
resolveNext({ value: void 0, done: true });
|
|
186
|
-
resolveNext = null;
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
const subscriber = {
|
|
190
|
-
sessionId,
|
|
191
|
-
callback: (event) => {
|
|
192
|
-
if (closed) return;
|
|
193
|
-
if (resolveNext) {
|
|
194
|
-
resolveNext({ value: event, done: false });
|
|
195
|
-
resolveNext = null;
|
|
196
|
-
} else {
|
|
197
|
-
queue.push(event);
|
|
198
|
-
}
|
|
199
|
-
},
|
|
200
|
-
close: closeIterator,
|
|
201
|
-
closed: false
|
|
202
|
-
};
|
|
236
|
+
const state = createIteratorState();
|
|
237
|
+
const subscriber = createSubscriber(state, { sessionId });
|
|
203
238
|
let sessionSubs = this.subscribers.get(sessionId);
|
|
204
239
|
if (!sessionSubs) {
|
|
205
240
|
sessionSubs = /* @__PURE__ */ new Set();
|
|
@@ -208,36 +243,14 @@ var EventStore = class {
|
|
|
208
243
|
sessionSubs.add(subscriber);
|
|
209
244
|
if (fromSeq !== void 0) {
|
|
210
245
|
const replayEvents = this.getEvents(sessionId, fromSeq);
|
|
211
|
-
queue.push(...replayEvents);
|
|
246
|
+
state.queue.push(...replayEvents);
|
|
212
247
|
}
|
|
213
|
-
const iterator = {
|
|
214
|
-
[Symbol.asyncIterator]() {
|
|
215
|
-
return this;
|
|
216
|
-
},
|
|
217
|
-
async next() {
|
|
218
|
-
if (closed) {
|
|
219
|
-
return { value: void 0, done: true };
|
|
220
|
-
}
|
|
221
|
-
const queued = queue.shift();
|
|
222
|
-
if (queued) {
|
|
223
|
-
return { value: queued, done: false };
|
|
224
|
-
}
|
|
225
|
-
return new Promise((resolve) => {
|
|
226
|
-
resolveNext = resolve;
|
|
227
|
-
});
|
|
228
|
-
},
|
|
229
|
-
async return() {
|
|
230
|
-
closed = true;
|
|
231
|
-
subscriber.closed = true;
|
|
232
|
-
return { value: void 0, done: true };
|
|
233
|
-
}
|
|
234
|
-
};
|
|
235
248
|
const unsubscribe = () => {
|
|
236
249
|
subscriber.closed = true;
|
|
237
|
-
closeIterator();
|
|
250
|
+
state.closeIterator();
|
|
238
251
|
sessionSubs?.delete(subscriber);
|
|
239
252
|
};
|
|
240
|
-
return { iterator, unsubscribe };
|
|
253
|
+
return { iterator: createEventIterator(state, subscriber), unsubscribe };
|
|
241
254
|
}
|
|
242
255
|
notifySubscribers(sessionId, event) {
|
|
243
256
|
const sessionSubs = this.subscribers.get(sessionId);
|
|
@@ -262,60 +275,16 @@ var EventStore = class {
|
|
|
262
275
|
* Returns an async iterator that yields events and an unsubscribe function
|
|
263
276
|
*/
|
|
264
277
|
subscribeAll() {
|
|
265
|
-
const
|
|
266
|
-
let resolveNext = null;
|
|
267
|
-
let closed = false;
|
|
268
|
-
const closeIterator = () => {
|
|
269
|
-
closed = true;
|
|
270
|
-
if (resolveNext) {
|
|
271
|
-
resolveNext({ value: void 0, done: true });
|
|
272
|
-
resolveNext = null;
|
|
273
|
-
}
|
|
274
|
-
};
|
|
278
|
+
const state = createIteratorState();
|
|
275
279
|
const wsId = ++this.globalSubscriberIdCounter;
|
|
276
|
-
const subscriber = {
|
|
277
|
-
wsId,
|
|
278
|
-
callback: (event) => {
|
|
279
|
-
if (closed) return;
|
|
280
|
-
if (resolveNext) {
|
|
281
|
-
resolveNext({ value: event, done: false });
|
|
282
|
-
resolveNext = null;
|
|
283
|
-
} else {
|
|
284
|
-
queue.push(event);
|
|
285
|
-
}
|
|
286
|
-
},
|
|
287
|
-
close: closeIterator,
|
|
288
|
-
closed: false
|
|
289
|
-
};
|
|
280
|
+
const subscriber = createSubscriber(state, { wsId });
|
|
290
281
|
this.globalSubscribers.set(wsId, subscriber);
|
|
291
|
-
const iterator = {
|
|
292
|
-
[Symbol.asyncIterator]() {
|
|
293
|
-
return this;
|
|
294
|
-
},
|
|
295
|
-
async next() {
|
|
296
|
-
if (closed) {
|
|
297
|
-
return { value: void 0, done: true };
|
|
298
|
-
}
|
|
299
|
-
const queued = queue.shift();
|
|
300
|
-
if (queued) {
|
|
301
|
-
return { value: queued, done: false };
|
|
302
|
-
}
|
|
303
|
-
return new Promise((resolve) => {
|
|
304
|
-
resolveNext = resolve;
|
|
305
|
-
});
|
|
306
|
-
},
|
|
307
|
-
async return() {
|
|
308
|
-
closed = true;
|
|
309
|
-
subscriber.closed = true;
|
|
310
|
-
return { value: void 0, done: true };
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
282
|
const unsubscribe = () => {
|
|
314
283
|
subscriber.closed = true;
|
|
315
|
-
closeIterator();
|
|
284
|
+
state.closeIterator();
|
|
316
285
|
this.globalSubscribers.delete(wsId);
|
|
317
286
|
};
|
|
318
|
-
return { iterator, unsubscribe };
|
|
287
|
+
return { iterator: createEventIterator(state, subscriber), unsubscribe };
|
|
319
288
|
}
|
|
320
289
|
// --------------------------------------------------------------------------
|
|
321
290
|
// Cleanup
|
|
@@ -417,25 +386,7 @@ var EventStore = class {
|
|
|
417
386
|
const data = JSON.parse(row.payload);
|
|
418
387
|
const messages = data.messages;
|
|
419
388
|
if (!messages) continue;
|
|
420
|
-
|
|
421
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
422
|
-
const msg = messages[i];
|
|
423
|
-
if (!msg) continue;
|
|
424
|
-
if (msg.role === "assistant" && msg.promptContext) {
|
|
425
|
-
lastAssistantIdx = i;
|
|
426
|
-
break;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
let changed = false;
|
|
430
|
-
for (let i = 0; i < messages.length; i++) {
|
|
431
|
-
const msg = messages[i];
|
|
432
|
-
if (!msg) continue;
|
|
433
|
-
const pc = msg.promptContext;
|
|
434
|
-
if (pc?.messages && pc.messages.length > 0 && i !== lastAssistantIdx) {
|
|
435
|
-
pc.messages = [];
|
|
436
|
-
changed = true;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
389
|
+
const changed = stripPromptContextMessages(messages);
|
|
439
390
|
if (changed) {
|
|
440
391
|
updateStmt.run(JSON.stringify(data), row.id);
|
|
441
392
|
strippedSnapshots++;
|
|
@@ -646,24 +597,7 @@ function listSessions() {
|
|
|
646
597
|
FROM sessions s
|
|
647
598
|
ORDER BY s.updated_at DESC
|
|
648
599
|
`).all();
|
|
649
|
-
return rows.map(
|
|
650
|
-
id: row.id,
|
|
651
|
-
projectId: row.project_id,
|
|
652
|
-
...row.title ? { title: row.title } : {},
|
|
653
|
-
workdir: row.workdir,
|
|
654
|
-
mode: row.mode ?? "planner",
|
|
655
|
-
phase: row.workflow_phase ?? "plan",
|
|
656
|
-
isRunning: Boolean(row.is_running),
|
|
657
|
-
providerId: row.provider_id ?? null,
|
|
658
|
-
providerModel: row.provider_model ?? null,
|
|
659
|
-
createdAt: row.created_at,
|
|
660
|
-
updatedAt: row.updated_at,
|
|
661
|
-
criteriaCount: 0,
|
|
662
|
-
// Derived from events
|
|
663
|
-
criteriaCompleted: 0,
|
|
664
|
-
// Derived from events
|
|
665
|
-
messageCount: row.message_count
|
|
666
|
-
}));
|
|
600
|
+
return rows.map(mapSessionSummaryRow);
|
|
667
601
|
}
|
|
668
602
|
function listSessionsByProject(projectId, limit = 20, offset = 0) {
|
|
669
603
|
const db = getDatabase();
|
|
@@ -687,7 +621,15 @@ function listSessionsByProject(projectId, limit = 20, offset = 0) {
|
|
|
687
621
|
LIMIT ? OFFSET ?
|
|
688
622
|
`).all(projectId, limit + 1, offset);
|
|
689
623
|
const hasMore = rows.length > limit;
|
|
690
|
-
const sessions = rows.slice(0, limit).map(
|
|
624
|
+
const sessions = rows.slice(0, limit).map(mapSessionSummaryRow);
|
|
625
|
+
return { sessions, hasMore };
|
|
626
|
+
}
|
|
627
|
+
function deleteSession(id) {
|
|
628
|
+
const db = getDatabase();
|
|
629
|
+
db.prepare("DELETE FROM sessions WHERE id = ?").run(id);
|
|
630
|
+
}
|
|
631
|
+
function mapSessionSummaryRow(row) {
|
|
632
|
+
return {
|
|
691
633
|
id: row.id,
|
|
692
634
|
projectId: row.project_id,
|
|
693
635
|
...row.title ? { title: row.title } : {},
|
|
@@ -702,12 +644,7 @@ function listSessionsByProject(projectId, limit = 20, offset = 0) {
|
|
|
702
644
|
criteriaCount: 0,
|
|
703
645
|
criteriaCompleted: 0,
|
|
704
646
|
messageCount: row.message_count
|
|
705
|
-
}
|
|
706
|
-
return { sessions, hasMore };
|
|
707
|
-
}
|
|
708
|
-
function deleteSession(id) {
|
|
709
|
-
const db = getDatabase();
|
|
710
|
-
db.prepare("DELETE FROM sessions WHERE id = ?").run(id);
|
|
647
|
+
};
|
|
711
648
|
}
|
|
712
649
|
|
|
713
650
|
// src/server/events/session.ts
|
|
@@ -717,22 +654,7 @@ function toSnapshotMessage(message) {
|
|
|
717
654
|
role: message.role,
|
|
718
655
|
content: message.content,
|
|
719
656
|
timestamp: new Date(message.timestamp).getTime(),
|
|
720
|
-
...message
|
|
721
|
-
...message.toolCalls !== void 0 && { toolCalls: message.toolCalls },
|
|
722
|
-
...message.segments !== void 0 && { segments: message.segments },
|
|
723
|
-
...message.stats !== void 0 && { stats: message.stats },
|
|
724
|
-
...message.tokenCount !== void 0 && { tokenCount: message.tokenCount },
|
|
725
|
-
...message.isStreaming !== void 0 && { isStreaming: message.isStreaming },
|
|
726
|
-
...message.partial !== void 0 && { partial: message.partial },
|
|
727
|
-
...message.subAgentId !== void 0 && { subAgentId: message.subAgentId },
|
|
728
|
-
...message.subAgentType !== void 0 && { subAgentType: message.subAgentType },
|
|
729
|
-
...message.isSystemGenerated !== void 0 && { isSystemGenerated: message.isSystemGenerated },
|
|
730
|
-
...message.messageKind !== void 0 && { messageKind: message.messageKind },
|
|
731
|
-
...message.contextWindowId !== void 0 && { contextWindowId: message.contextWindowId },
|
|
732
|
-
...message.isCompactionSummary !== void 0 && { isCompactionSummary: message.isCompactionSummary },
|
|
733
|
-
...message.promptContext !== void 0 && { promptContext: message.promptContext },
|
|
734
|
-
...message.attachments !== void 0 && { attachments: message.attachments },
|
|
735
|
-
...message.metadata !== void 0 && { metadata: message.metadata }
|
|
657
|
+
...spreadOptionalMessageFields(message)
|
|
736
658
|
};
|
|
737
659
|
}
|
|
738
660
|
function getSessionState(sessionId, maxTokens) {
|
|
@@ -1144,4 +1066,4 @@ export {
|
|
|
1144
1066
|
compactContext,
|
|
1145
1067
|
getRecentUserPromptsForSession
|
|
1146
1068
|
};
|
|
1147
|
-
//# sourceMappingURL=chunk-
|
|
1069
|
+
//# sourceMappingURL=chunk-6L3X7T4K.js.map
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
updateSessionMetadata
|
|
3
|
+
} from "./chunk-6L3X7T4K.js";
|
|
4
|
+
import {
|
|
5
|
+
buildMessagesFromStoredEvents,
|
|
6
|
+
foldPendingConfirmations
|
|
7
|
+
} from "./chunk-2KP34IDL.js";
|
|
8
|
+
import {
|
|
9
|
+
createSessionStateMessage
|
|
10
|
+
} from "./chunk-NJWPSSRW.js";
|
|
1
11
|
import {
|
|
2
12
|
logger
|
|
3
13
|
} from "./chunk-PNBH3RAX.js";
|
|
@@ -67,9 +77,35 @@ function needsNameGeneration(sessionTitle, messageCount) {
|
|
|
67
77
|
}
|
|
68
78
|
return false;
|
|
69
79
|
}
|
|
80
|
+
function needsNameGenerationCheck(sessionId, sessionTitle, messageCount) {
|
|
81
|
+
const needsGeneration = needsNameGeneration(sessionTitle, messageCount);
|
|
82
|
+
logger.debug("Session name generation check", {
|
|
83
|
+
sessionId,
|
|
84
|
+
title: sessionTitle,
|
|
85
|
+
messageCount,
|
|
86
|
+
needsGeneration
|
|
87
|
+
});
|
|
88
|
+
return needsGeneration;
|
|
89
|
+
}
|
|
90
|
+
function applyGeneratedSessionName(sessionId, name, deps) {
|
|
91
|
+
updateSessionMetadata(sessionId, { title: name });
|
|
92
|
+
deps.eventStore.append(sessionId, {
|
|
93
|
+
type: "session.name_generated",
|
|
94
|
+
data: { name }
|
|
95
|
+
});
|
|
96
|
+
const updatedSession = deps.sessionManager.getSession(sessionId);
|
|
97
|
+
if (updatedSession) {
|
|
98
|
+
const events = deps.eventStore.getEvents(sessionId);
|
|
99
|
+
const messages = buildMessagesFromStoredEvents(events);
|
|
100
|
+
const pendingConfirmations = foldPendingConfirmations(events);
|
|
101
|
+
deps.broadcastForSession(sessionId, createSessionStateMessage(updatedSession, messages, pendingConfirmations));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
70
104
|
|
|
71
105
|
export {
|
|
72
106
|
generateSessionName,
|
|
73
|
-
needsNameGeneration
|
|
107
|
+
needsNameGeneration,
|
|
108
|
+
needsNameGenerationCheck,
|
|
109
|
+
applyGeneratedSessionName
|
|
74
110
|
};
|
|
75
|
-
//# sourceMappingURL=chunk-
|
|
111
|
+
//# sourceMappingURL=chunk-F54ZJN4X.js.map
|
|
@@ -29,7 +29,7 @@ function isVisionFallbackEnabled() {
|
|
|
29
29
|
async function ensureVisionFallbackConfigLoaded() {
|
|
30
30
|
if (configLoaded) return;
|
|
31
31
|
try {
|
|
32
|
-
const { loadGlobalConfig, getVisionFallback } = await import("./config-
|
|
32
|
+
const { loadGlobalConfig, getVisionFallback } = await import("./config-67AX6CNS.js");
|
|
33
33
|
const { getRuntimeConfig } = await import("./runtime-config-2XJJIMSC.js");
|
|
34
34
|
const runtimeConfig = getRuntimeConfig();
|
|
35
35
|
const mode = runtimeConfig.mode ?? "production";
|
|
@@ -135,4 +135,4 @@ export {
|
|
|
135
135
|
describeImage,
|
|
136
136
|
describeImageFromDataUrl
|
|
137
137
|
};
|
|
138
|
-
//# sourceMappingURL=chunk-
|
|
138
|
+
//# sourceMappingURL=chunk-IN5EP4ZB.js.map
|
|
@@ -4,40 +4,61 @@ import {
|
|
|
4
4
|
detectBackend,
|
|
5
5
|
detectModel,
|
|
6
6
|
setLlmStatus
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OVLFEBRR.js";
|
|
8
8
|
import {
|
|
9
9
|
logger
|
|
10
10
|
} from "./chunk-PNBH3RAX.js";
|
|
11
11
|
|
|
12
12
|
// src/server/provider-manager.ts
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
function normalizeModelId(s) {
|
|
14
|
+
return s.toLowerCase().replace(/[-_\s:.]+/g, "");
|
|
15
|
+
}
|
|
16
|
+
async function fetchModelsFromBackend(url, apiKey) {
|
|
17
|
+
const headers = { "Content-Type": "application/json" };
|
|
18
|
+
if (apiKey) {
|
|
19
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
20
|
+
}
|
|
15
21
|
try {
|
|
16
|
-
const
|
|
17
|
-
"Content-Type": "application/json"
|
|
18
|
-
};
|
|
19
|
-
if (apiKey) {
|
|
20
|
-
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
21
|
-
}
|
|
22
|
-
const response = await fetch(url, {
|
|
23
|
-
method: "GET",
|
|
24
|
-
headers,
|
|
25
|
-
signal: AbortSignal.timeout(1e4)
|
|
26
|
-
});
|
|
22
|
+
const response = await fetch(url, { method: "GET", headers, signal: AbortSignal.timeout(1e4) });
|
|
27
23
|
if (!response.ok) {
|
|
28
24
|
logger.debug("Failed to fetch models", { url, status: response.status });
|
|
29
25
|
return [];
|
|
30
26
|
}
|
|
31
27
|
const data = await response.json();
|
|
32
28
|
if (data.data && Array.isArray(data.data)) {
|
|
33
|
-
return data.data.map((m) =>
|
|
29
|
+
return data.data.map((m) => ({
|
|
30
|
+
id: m.id,
|
|
31
|
+
contextWindow: m.max_model_len ?? void 0
|
|
32
|
+
}));
|
|
34
33
|
}
|
|
35
34
|
return [];
|
|
36
35
|
} catch (error) {
|
|
37
|
-
logger.debug("Error fetching models
|
|
36
|
+
logger.debug("Error fetching models", { url, error: error instanceof Error ? error.message : String(error) });
|
|
38
37
|
return [];
|
|
39
38
|
}
|
|
40
39
|
}
|
|
40
|
+
function mergeModelsWithUserOverrides(backendModels, userModels) {
|
|
41
|
+
const normalizedUserIdMap = new Map(userModels.map((m) => [normalizeModelId(m.id), m]));
|
|
42
|
+
const updatedModels = backendModels.map((backendModel) => {
|
|
43
|
+
const existingUserModel = normalizedUserIdMap.get(normalizeModelId(backendModel.id));
|
|
44
|
+
if (existingUserModel) {
|
|
45
|
+
return { ...existingUserModel, id: backendModel.id };
|
|
46
|
+
}
|
|
47
|
+
return backendModel;
|
|
48
|
+
});
|
|
49
|
+
const normalizedBackendIds = new Set(backendModels.map((m) => normalizeModelId(m.id)));
|
|
50
|
+
for (const userModel of userModels) {
|
|
51
|
+
if (!normalizedBackendIds.has(normalizeModelId(userModel.id))) {
|
|
52
|
+
updatedModels.push(userModel);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return updatedModels;
|
|
56
|
+
}
|
|
57
|
+
async function fetchAvailableModelsFromBackend(baseUrl, apiKey) {
|
|
58
|
+
const url = baseUrl.includes("/v1") ? `${baseUrl}/models` : `${baseUrl}/v1/models`;
|
|
59
|
+
const models = await fetchModelsFromBackend(url, apiKey);
|
|
60
|
+
return models.map((m) => m.id);
|
|
61
|
+
}
|
|
41
62
|
async function fetchModelsWithContext(baseUrl, apiKey, backend) {
|
|
42
63
|
logger.info("fetchModelsWithContext called", { baseUrl, apiKey: !!apiKey, backend });
|
|
43
64
|
if (backend === "ollama") {
|
|
@@ -45,44 +66,16 @@ async function fetchModelsWithContext(baseUrl, apiKey, backend) {
|
|
|
45
66
|
return fetchOllamaModelsWithContext(baseUrl, apiKey);
|
|
46
67
|
}
|
|
47
68
|
const isOpenCodeGo = baseUrl.includes("opencode.ai/zen/go");
|
|
48
|
-
|
|
49
|
-
if (isOpenCodeGo) {
|
|
50
|
-
url = baseUrl.replace("/zen/go", "/zen").replace(/\/v1$/, "") + "/v1/models";
|
|
51
|
-
logger.info("OpenCode Go detected, using alternate models endpoint", { original: baseUrl, modelsUrl: url });
|
|
52
|
-
} else {
|
|
53
|
-
url = baseUrl.includes("/v1") ? `${baseUrl}/models` : `${baseUrl}/v1/models`;
|
|
54
|
-
}
|
|
69
|
+
const url = isOpenCodeGo ? baseUrl.replace("/zen/go", "/zen").replace(/\/v1$/, "") + "/v1/models" : baseUrl.includes("/v1") ? `${baseUrl}/models` : `${baseUrl}/v1/models`;
|
|
55
70
|
logger.info("Fetching models via /v1/models", { url });
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
method: "GET",
|
|
65
|
-
headers,
|
|
66
|
-
signal: AbortSignal.timeout(1e4)
|
|
67
|
-
});
|
|
68
|
-
if (!response.ok) {
|
|
69
|
-
logger.debug("Failed to fetch models with context", { url, status: response.status });
|
|
70
|
-
return [];
|
|
71
|
-
}
|
|
72
|
-
const data = await response.json();
|
|
73
|
-
if (data.data && Array.isArray(data.data)) {
|
|
74
|
-
logger.info("Fetched models from /v1/models", { count: data.data.length, models: data.data.map((m) => m.id) });
|
|
75
|
-
return data.data.map((m) => ({
|
|
76
|
-
id: m.id,
|
|
77
|
-
contextWindow: m.max_model_len ?? 2e5,
|
|
78
|
-
source: m.max_model_len ? "backend" : "default"
|
|
79
|
-
}));
|
|
80
|
-
}
|
|
81
|
-
return [];
|
|
82
|
-
} catch (error) {
|
|
83
|
-
logger.debug("Error fetching models with context", { url, error: error instanceof Error ? error.message : String(error) });
|
|
84
|
-
return [];
|
|
85
|
-
}
|
|
71
|
+
const models = await fetchModelsFromBackend(url, apiKey);
|
|
72
|
+
if (models.length === 0) return [];
|
|
73
|
+
logger.info("Fetched models from /v1/models", { count: models.length });
|
|
74
|
+
return models.map((m) => ({
|
|
75
|
+
id: m.id,
|
|
76
|
+
contextWindow: m.contextWindow ?? 2e5,
|
|
77
|
+
source: m.contextWindow ? "backend" : "default"
|
|
78
|
+
}));
|
|
86
79
|
}
|
|
87
80
|
async function fetchOllamaModelsWithContext(baseUrl, apiKey) {
|
|
88
81
|
const tagsUrl = `${baseUrl}/api/tags`;
|
|
@@ -217,34 +210,10 @@ function createProviderManager(config) {
|
|
|
217
210
|
const backend = provider.backend;
|
|
218
211
|
logger.info("activateProvider fetching models", { providerId, providerName: provider.name, url, backend });
|
|
219
212
|
const modelsWithContext = await fetchModelsWithContext(url, provider.apiKey, backend);
|
|
220
|
-
const normalize = (s) => s.toLowerCase().replace(/[-_\s:.]+/g, "");
|
|
221
213
|
const userModels = provider.models.filter((m) => m.source === "user");
|
|
222
|
-
logger.debug("activateProvider", { providerId, backendModelsCount: modelsWithContext.length, userModelsCount: userModels.length
|
|
214
|
+
logger.debug("activateProvider", { providerId, backendModelsCount: modelsWithContext.length, userModelsCount: userModels.length });
|
|
223
215
|
if (modelsWithContext.length > 0) {
|
|
224
|
-
const updatedModels = modelsWithContext
|
|
225
|
-
let existingModel = provider.models.find((pm) => pm.id === m.id);
|
|
226
|
-
if (!existingModel) {
|
|
227
|
-
const normalizedId = normalize(m.id);
|
|
228
|
-
existingModel = provider.models.find((pm) => {
|
|
229
|
-
if (pm.source !== "user") return false;
|
|
230
|
-
return normalize(pm.id) === normalizedId;
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
if (existingModel && existingModel.source === "user") {
|
|
234
|
-
return { ...existingModel, id: m.id };
|
|
235
|
-
}
|
|
236
|
-
return m;
|
|
237
|
-
});
|
|
238
|
-
for (const userModel of userModels) {
|
|
239
|
-
const normalizedUserId = normalize(userModel.id);
|
|
240
|
-
const matchedInUpdated = updatedModels.some((m) => {
|
|
241
|
-
const normalizedBackendId = normalize(m.id);
|
|
242
|
-
return normalizedBackendId === normalizedUserId;
|
|
243
|
-
});
|
|
244
|
-
if (!matchedInUpdated) {
|
|
245
|
-
updatedModels.push(userModel);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
216
|
+
const updatedModels = mergeModelsWithUserOverrides(modelsWithContext, userModels);
|
|
248
217
|
providers = providers.map((p) => p.id === providerId ? { ...p, models: updatedModels } : p);
|
|
249
218
|
} else if (userModels.length > 0) {
|
|
250
219
|
logger.debug("Backend unavailable during provider switch, preserving user models", { providerId, userModelsCount: userModels.length });
|
|
@@ -403,52 +372,24 @@ function createProviderManager(config) {
|
|
|
403
372
|
const backend = provider.backend;
|
|
404
373
|
logger.info("refreshProviderModels fetching models", { providerId, providerName: provider.name, url, backend });
|
|
405
374
|
const modelsWithContext = await fetchModelsWithContext(url, provider.apiKey, backend);
|
|
406
|
-
const normalize = (s) => s.toLowerCase().replace(/[-_\s:.]+/g, "");
|
|
407
375
|
const userModels = provider.models.filter((m) => m.source === "user");
|
|
408
|
-
|
|
409
|
-
logger.info("refreshProviderModels", { providerId, userModelsCount: userModels.length, backendModelsCount: modelsWithContext.length, userModels: userModels.map((m) => ({ id: m.id, contextWindow: m.contextWindow, source: m.source })), allModelsBefore, backendModels: modelsWithContext });
|
|
376
|
+
logger.info("refreshProviderModels", { providerId, userModelsCount: userModels.length, backendModelsCount: modelsWithContext.length });
|
|
410
377
|
if (modelsWithContext.length === 0) {
|
|
411
378
|
setLlmStatus("disconnected");
|
|
412
379
|
if (userModels.length > 0) {
|
|
413
380
|
logger.debug("Backend unavailable, preserving user models", { providerId, userModels: userModels.map((m) => ({ id: m.id, contextWindow: m.contextWindow })) });
|
|
414
381
|
providers = providers.map((p) => p.id === providerId ? { ...p, models: userModels } : p);
|
|
415
|
-
const preservedProvider = providers.find((p) => p.id === providerId);
|
|
416
|
-
logger.debug("After preservation", { providerId, models: preservedProvider?.models.map((m) => ({ id: m.id, contextWindow: m.contextWindow, source: m.source })) });
|
|
417
382
|
return { success: true };
|
|
418
383
|
}
|
|
419
384
|
return { success: false, error: "No models returned from backend" };
|
|
420
385
|
}
|
|
421
386
|
setLlmStatus("connected");
|
|
422
|
-
const updatedModels = modelsWithContext
|
|
423
|
-
let existingModel = provider.models.find((pm) => pm.id === m.id);
|
|
424
|
-
if (!existingModel) {
|
|
425
|
-
const normalizedId = normalize(m.id);
|
|
426
|
-
existingModel = provider.models.find((pm) => {
|
|
427
|
-
if (pm.source !== "user") return false;
|
|
428
|
-
return normalize(pm.id) === normalizedId;
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
if (existingModel && existingModel.source === "user") {
|
|
432
|
-
return { ...existingModel, id: m.id };
|
|
433
|
-
}
|
|
434
|
-
return m;
|
|
435
|
-
});
|
|
436
|
-
for (const userModel of userModels) {
|
|
437
|
-
const normalizedUserId = normalize(userModel.id);
|
|
438
|
-
const matchedInUpdated = updatedModels.some((m) => {
|
|
439
|
-
const normalizedBackendId = normalize(m.id);
|
|
440
|
-
return normalizedBackendId === normalizedUserId;
|
|
441
|
-
});
|
|
442
|
-
logger.debug("User model match check", { userModelId: userModel.id, normalizedUserId, matchedInUpdated, updatedModelsIds: updatedModels.map((m) => m.id) });
|
|
443
|
-
if (!matchedInUpdated) {
|
|
444
|
-
updatedModels.push(userModel);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
387
|
+
const updatedModels = mergeModelsWithUserOverrides(modelsWithContext, userModels);
|
|
447
388
|
providers = providers.map((p) => p.id === providerId ? { ...p, models: updatedModels } : p);
|
|
448
389
|
const { providerId: currentProviderId, model: currentModel } = parseDefaultModelSelection(defaultModelSelection);
|
|
449
390
|
if (currentProviderId === providerId && currentModel) {
|
|
450
|
-
const normalizedCurrentModel =
|
|
451
|
-
const matchedModel = updatedModels.find((m) =>
|
|
391
|
+
const normalizedCurrentModel = normalizeModelId(currentModel);
|
|
392
|
+
const matchedModel = updatedModels.find((m) => normalizeModelId(m.id) === normalizedCurrentModel);
|
|
452
393
|
if (matchedModel && matchedModel.id !== currentModel) {
|
|
453
394
|
defaultModelSelection = `${providerId}/${matchedModel.id}`;
|
|
454
395
|
logger.debug("Updated defaultModelSelection after fuzzy match", { from: currentModel, to: matchedModel.id });
|
|
@@ -465,4 +406,4 @@ export {
|
|
|
465
406
|
parseDefaultModelSelection,
|
|
466
407
|
createProviderManager
|
|
467
408
|
};
|
|
468
|
-
//# sourceMappingURL=chunk-
|
|
409
|
+
//# sourceMappingURL=chunk-KOUMYBYM.js.map
|