@jait/gateway 0.1.488 → 0.1.490
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/memory/contracts.d.ts +1 -0
- package/dist/memory/contracts.d.ts.map +1 -1
- package/dist/memory/service.d.ts +1 -0
- package/dist/memory/service.d.ts.map +1 -1
- package/dist/memory/service.js +4 -0
- package/dist/memory/service.js.map +1 -1
- package/dist/providers/acp-provider.d.ts +8 -0
- package/dist/providers/acp-provider.d.ts.map +1 -1
- package/dist/providers/acp-provider.js +88 -17
- package/dist/providers/acp-provider.js.map +1 -1
- package/dist/providers/model-fetchers.d.ts +7 -1
- package/dist/providers/model-fetchers.d.ts.map +1 -1
- package/dist/providers/model-fetchers.js +66 -7
- package/dist/providers/model-fetchers.js.map +1 -1
- package/dist/providers/provider-snapshot.d.ts +41 -0
- package/dist/providers/provider-snapshot.d.ts.map +1 -0
- package/dist/providers/provider-snapshot.js +77 -0
- package/dist/providers/provider-snapshot.js.map +1 -0
- package/dist/routes/chat.d.ts.map +1 -1
- package/dist/routes/chat.js +32 -11
- package/dist/routes/chat.js.map +1 -1
- package/dist/routes/providers.d.ts.map +1 -1
- package/dist/routes/providers.js +43 -48
- package/dist/routes/providers.js.map +1 -1
- package/dist/routes/reminders.d.ts +2 -0
- package/dist/routes/reminders.d.ts.map +1 -1
- package/dist/routes/reminders.js +27 -3
- package/dist/routes/reminders.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -0
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/web-dist/assets/{_basePickBy-Bs2Q2Eng.js → _basePickBy-vgfYW5YM.js} +1 -1
- package/web-dist/assets/{_baseUniq-C1Vgvc6k.js → _baseUniq-BCyddlmv.js} +1 -1
- package/web-dist/assets/{arc-B45ZD8Nx.js → arc-CetE4hi3.js} +1 -1
- package/web-dist/assets/{architectureDiagram-2XIMDMQ5-Dgn58dd_.js → architectureDiagram-2XIMDMQ5-ySUJrv-h.js} +1 -1
- package/web-dist/assets/{blockDiagram-WCTKOSBZ-DVo2YOE_.js → blockDiagram-WCTKOSBZ-BSpA2Vi-.js} +1 -1
- package/web-dist/assets/{c4Diagram-IC4MRINW-DGFSFQ71.js → c4Diagram-IC4MRINW-DTIgQZNZ.js} +1 -1
- package/web-dist/assets/channel-B4LKl9yt.js +1 -0
- package/web-dist/assets/{chunk-4BX2VUAB-BH1NL3uc.js → chunk-4BX2VUAB-l5CswJhC.js} +1 -1
- package/web-dist/assets/{chunk-55IACEB6-DXuyCFwp.js → chunk-55IACEB6-BJDbbrXC.js} +1 -1
- package/web-dist/assets/{chunk-FMBD7UC4-krCQHjSO.js → chunk-FMBD7UC4-aAPpg8z7.js} +1 -1
- package/web-dist/assets/{chunk-JSJVCQXG-Db70Tfzs.js → chunk-JSJVCQXG-BVprtjfJ.js} +1 -1
- package/web-dist/assets/{chunk-KX2RTZJC-ClwrCaPu.js → chunk-KX2RTZJC-UovbUaCZ.js} +1 -1
- package/web-dist/assets/{chunk-NQ4KR5QH-BgYsa0ay.js → chunk-NQ4KR5QH-Crx9IS7x.js} +1 -1
- package/web-dist/assets/{chunk-QZHKN3VN-DcrIkFKB.js → chunk-QZHKN3VN-CP7-7ek1.js} +1 -1
- package/web-dist/assets/{chunk-WL4C6EOR-BTf7iLVE.js → chunk-WL4C6EOR-YXqhe30x.js} +1 -1
- package/web-dist/assets/classDiagram-VBA2DB6C-B5rNybiS.js +1 -0
- package/web-dist/assets/classDiagram-v2-RAHNMMFH-B5rNybiS.js +1 -0
- package/web-dist/assets/clone-D42O3IVz.js +1 -0
- package/web-dist/assets/{cose-bilkent-S5V4N54A-CTYlJ5P2.js → cose-bilkent-S5V4N54A-IjeOb81w.js} +1 -1
- package/web-dist/assets/{dagre-KLK3FWXG-DWI1FJLN.js → dagre-KLK3FWXG-D69PF_t6.js} +1 -1
- package/web-dist/assets/{diagram-E7M64L7V-BUK_Kgia.js → diagram-E7M64L7V-DZ_jCthR.js} +1 -1
- package/web-dist/assets/{diagram-IFDJBPK2-NqEaUmP3.js → diagram-IFDJBPK2-BAB6O5Dv.js} +1 -1
- package/web-dist/assets/{diagram-P4PSJMXO-5Ep5l2GM.js → diagram-P4PSJMXO-CCACsUXt.js} +1 -1
- package/web-dist/assets/{erDiagram-INFDFZHY-G_uvZUyt.js → erDiagram-INFDFZHY-B1SILDm-.js} +1 -1
- package/web-dist/assets/{flowDiagram-PKNHOUZH-Dpx9wgBT.js → flowDiagram-PKNHOUZH-CZu_oMfJ.js} +1 -1
- package/web-dist/assets/{ganttDiagram-A5KZAMGK-C1wksGup.js → ganttDiagram-A5KZAMGK-BCRi3L1T.js} +1 -1
- package/web-dist/assets/{gitGraphDiagram-K3NZZRJ6-BMRbny8s.js → gitGraphDiagram-K3NZZRJ6-VDYqRMZf.js} +1 -1
- package/web-dist/assets/{graph-D813FHN0.js → graph-CGFhPhx8.js} +1 -1
- package/web-dist/assets/{index-Dz5PpkSn.js → index-B0ThQUZY.js} +352 -352
- package/web-dist/assets/{index-BHV3c90o.js → index-CbgPCPKw.js} +1 -1
- package/web-dist/assets/{index-B0WXmsg6.js → index-Dk7L2F_Y.js} +1 -1
- package/web-dist/assets/{infoDiagram-LFFYTUFH-CRhMjd3m.js → infoDiagram-LFFYTUFH-DXP_GMzg.js} +1 -1
- package/web-dist/assets/{ishikawaDiagram-PHBUUO56-C0b-DmJz.js → ishikawaDiagram-PHBUUO56-CpbSLbJg.js} +1 -1
- package/web-dist/assets/{journeyDiagram-4ABVD52K-7GAYf7qC.js → journeyDiagram-4ABVD52K-Dt27VAaz.js} +1 -1
- package/web-dist/assets/{kanban-definition-K7BYSVSG-DYH6GLQ_.js → kanban-definition-K7BYSVSG-DG9J5Mjh.js} +1 -1
- package/web-dist/assets/{layout-DflnUaC-.js → layout-D_AF7RYk.js} +1 -1
- package/web-dist/assets/{linear-BKaIWChA.js → linear-t3MuHagv.js} +1 -1
- package/web-dist/assets/{mindmap-definition-YRQLILUH-DLKYT7in.js → mindmap-definition-YRQLILUH-BlniMcB4.js} +1 -1
- package/web-dist/assets/{pieDiagram-SKSYHLDU-1pCzkOws.js → pieDiagram-SKSYHLDU-cDcZejYu.js} +1 -1
- package/web-dist/assets/{quadrantDiagram-337W2JSQ-sQvtWhE5.js → quadrantDiagram-337W2JSQ-BO3oDOmW.js} +1 -1
- package/web-dist/assets/{requirementDiagram-Z7DCOOCP-DjjWn7oo.js → requirementDiagram-Z7DCOOCP-C0ffaLyW.js} +1 -1
- package/web-dist/assets/{sankeyDiagram-WA2Y5GQK-BmubwmS7.js → sankeyDiagram-WA2Y5GQK-C_3OPo5Z.js} +1 -1
- package/web-dist/assets/{sequenceDiagram-2WXFIKYE-827kzmaQ.js → sequenceDiagram-2WXFIKYE-CEKGZq0Q.js} +1 -1
- package/web-dist/assets/{stateDiagram-RAJIS63D-CVnU2rvz.js → stateDiagram-RAJIS63D-D9w7CWEi.js} +1 -1
- package/web-dist/assets/stateDiagram-v2-FVOUBMTO-CREpnVYX.js +1 -0
- package/web-dist/assets/{timeline-definition-YZTLITO2-8QfPnNpk.js → timeline-definition-YZTLITO2-CbIkQ8PT.js} +1 -1
- package/web-dist/assets/{treemap-KZPCXAKY-D6AwuGcm.js → treemap-KZPCXAKY-CQKrf1qk.js} +1 -1
- package/web-dist/assets/{vennDiagram-LZ73GAT5-Bjye7yJQ.js → vennDiagram-LZ73GAT5-BQsFrHpE.js} +1 -1
- package/web-dist/assets/{xychartDiagram-JWTSCODW-NBNTRnip.js → xychartDiagram-JWTSCODW-CVpjE7Xh.js} +1 -1
- package/web-dist/index.html +1 -1
- package/web-dist/assets/channel-Ct_ZzeFZ.js +0 -1
- package/web-dist/assets/classDiagram-VBA2DB6C-BA-sk9nf.js +0 -1
- package/web-dist/assets/classDiagram-v2-RAHNMMFH-BA-sk9nf.js +0 -1
- package/web-dist/assets/clone-SN4ZG9tU.js +0 -1
- package/web-dist/assets/stateDiagram-v2-FVOUBMTO-DhiBeXYZ.js +0 -1
|
@@ -32,11 +32,18 @@ const OPENAI_NON_CHAT_SUBSTRINGS = [
|
|
|
32
32
|
let openRouterCache = null;
|
|
33
33
|
let openaiCache = null;
|
|
34
34
|
let ollamaCache = null;
|
|
35
|
+
// In-flight guards so a stale-while-revalidate refresh never stampedes.
|
|
36
|
+
let openRouterInflight = null;
|
|
37
|
+
let openaiInflight = null;
|
|
38
|
+
let ollamaInflight = null;
|
|
35
39
|
/** Clear all cached model lists. Intended for tests. */
|
|
36
40
|
export function resetModelFetcherCaches() {
|
|
37
41
|
openRouterCache = null;
|
|
38
42
|
openaiCache = null;
|
|
39
43
|
ollamaCache = null;
|
|
44
|
+
openRouterInflight = null;
|
|
45
|
+
openaiInflight = null;
|
|
46
|
+
ollamaInflight = null;
|
|
40
47
|
}
|
|
41
48
|
// ── Filters (pure, exported for testing) ─────────────────────────
|
|
42
49
|
export function isChatCapableOpenAIModelId(id) {
|
|
@@ -47,11 +54,27 @@ export function isChatCapableOpenAIModelId(id) {
|
|
|
47
54
|
return !OPENAI_NON_CHAT_SUBSTRINGS.some((s) => id.includes(s));
|
|
48
55
|
}
|
|
49
56
|
// ── Fetchers ─────────────────────────────────────────────────────
|
|
50
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Fetch the OpenRouter catalogue. Returns [] on any non-OK response.
|
|
59
|
+
*
|
|
60
|
+
* Stale-while-revalidate: once a catalogue has been cached, callers get it
|
|
61
|
+
* instantly and a refresh runs in the background when the entry has expired, so
|
|
62
|
+
* the model list endpoint never blocks on the network after the first load.
|
|
63
|
+
*/
|
|
51
64
|
export async function fetchOpenRouterModels(apiKey) {
|
|
52
|
-
if (openRouterCache
|
|
65
|
+
if (openRouterCache) {
|
|
66
|
+
if (Date.now() - openRouterCache.fetchedAt >= REMOTE_CACHE_TTL && !openRouterInflight) {
|
|
67
|
+
openRouterInflight = doFetchOpenRouterModels(apiKey).finally(() => { openRouterInflight = null; });
|
|
68
|
+
openRouterInflight.catch(() => { });
|
|
69
|
+
}
|
|
53
70
|
return openRouterCache.models;
|
|
54
71
|
}
|
|
72
|
+
if (!openRouterInflight) {
|
|
73
|
+
openRouterInflight = doFetchOpenRouterModels(apiKey).finally(() => { openRouterInflight = null; });
|
|
74
|
+
}
|
|
75
|
+
return openRouterInflight;
|
|
76
|
+
}
|
|
77
|
+
async function doFetchOpenRouterModels(apiKey) {
|
|
55
78
|
const controller = new AbortController();
|
|
56
79
|
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
57
80
|
try {
|
|
@@ -60,7 +83,7 @@ export async function fetchOpenRouterModels(apiKey) {
|
|
|
60
83
|
signal: controller.signal,
|
|
61
84
|
});
|
|
62
85
|
if (!res.ok)
|
|
63
|
-
return [];
|
|
86
|
+
return openRouterCache?.models ?? [];
|
|
64
87
|
const data = (await res.json());
|
|
65
88
|
const models = (data.data ?? [])
|
|
66
89
|
.filter((m) => m.id && !m.id.includes(":free"))
|
|
@@ -73,6 +96,11 @@ export async function fetchOpenRouterModels(apiKey) {
|
|
|
73
96
|
openRouterCache = { models, fetchedAt: Date.now() };
|
|
74
97
|
return models;
|
|
75
98
|
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
if (openRouterCache)
|
|
101
|
+
return openRouterCache.models;
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
76
104
|
finally {
|
|
77
105
|
clearTimeout(timeout);
|
|
78
106
|
}
|
|
@@ -80,9 +108,20 @@ export async function fetchOpenRouterModels(apiKey) {
|
|
|
80
108
|
/** Fetch the OpenAI (or OpenAI-compatible) catalogue. Returns [] on any non-OK response. */
|
|
81
109
|
export async function fetchOpenAIModels(apiKey, baseUrl) {
|
|
82
110
|
const url = baseUrl.replace(/\/+$/, "");
|
|
83
|
-
if (openaiCache && openaiCache.baseUrl === url
|
|
111
|
+
if (openaiCache && openaiCache.baseUrl === url) {
|
|
112
|
+
if (Date.now() - openaiCache.fetchedAt >= REMOTE_CACHE_TTL && !openaiInflight) {
|
|
113
|
+
openaiInflight = doFetchOpenAIModels(apiKey, url).finally(() => { openaiInflight = null; });
|
|
114
|
+
openaiInflight.catch(() => { });
|
|
115
|
+
}
|
|
84
116
|
return openaiCache.models;
|
|
85
117
|
}
|
|
118
|
+
// Cold cache, or the base URL changed (different catalogue) — fetch fresh.
|
|
119
|
+
if (!openaiInflight) {
|
|
120
|
+
openaiInflight = doFetchOpenAIModels(apiKey, url).finally(() => { openaiInflight = null; });
|
|
121
|
+
}
|
|
122
|
+
return openaiInflight;
|
|
123
|
+
}
|
|
124
|
+
async function doFetchOpenAIModels(apiKey, url) {
|
|
86
125
|
const controller = new AbortController();
|
|
87
126
|
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
88
127
|
try {
|
|
@@ -91,7 +130,7 @@ export async function fetchOpenAIModels(apiKey, baseUrl) {
|
|
|
91
130
|
signal: controller.signal,
|
|
92
131
|
});
|
|
93
132
|
if (!res.ok)
|
|
94
|
-
return [];
|
|
133
|
+
return openaiCache?.baseUrl === url ? openaiCache.models : [];
|
|
95
134
|
const data = (await res.json());
|
|
96
135
|
const models = (data.data ?? [])
|
|
97
136
|
.filter((m) => isChatCapableOpenAIModelId(m.id))
|
|
@@ -104,6 +143,11 @@ export async function fetchOpenAIModels(apiKey, baseUrl) {
|
|
|
104
143
|
openaiCache = { models, fetchedAt: Date.now(), baseUrl: url };
|
|
105
144
|
return models;
|
|
106
145
|
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
if (openaiCache?.baseUrl === url)
|
|
148
|
+
return openaiCache.models;
|
|
149
|
+
throw err;
|
|
150
|
+
}
|
|
107
151
|
finally {
|
|
108
152
|
clearTimeout(timeout);
|
|
109
153
|
}
|
|
@@ -111,15 +155,25 @@ export async function fetchOpenAIModels(apiKey, baseUrl) {
|
|
|
111
155
|
/** Fetch the Ollama tags catalogue. Returns [] on any non-OK response. */
|
|
112
156
|
export async function fetchOllamaModels(baseUrl) {
|
|
113
157
|
const url = baseUrl.replace(/\/+$/, "");
|
|
114
|
-
if (ollamaCache && ollamaCache.url === url
|
|
158
|
+
if (ollamaCache && ollamaCache.url === url) {
|
|
159
|
+
if (Date.now() - ollamaCache.fetchedAt >= OLLAMA_CACHE_TTL && !ollamaInflight) {
|
|
160
|
+
ollamaInflight = doFetchOllamaModels(url).finally(() => { ollamaInflight = null; });
|
|
161
|
+
ollamaInflight.catch(() => { });
|
|
162
|
+
}
|
|
115
163
|
return ollamaCache.models;
|
|
116
164
|
}
|
|
165
|
+
if (!ollamaInflight) {
|
|
166
|
+
ollamaInflight = doFetchOllamaModels(url).finally(() => { ollamaInflight = null; });
|
|
167
|
+
}
|
|
168
|
+
return ollamaInflight;
|
|
169
|
+
}
|
|
170
|
+
async function doFetchOllamaModels(url) {
|
|
117
171
|
const controller = new AbortController();
|
|
118
172
|
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
119
173
|
try {
|
|
120
174
|
const res = await fetch(`${url}/api/tags`, { signal: controller.signal });
|
|
121
175
|
if (!res.ok)
|
|
122
|
-
return [];
|
|
176
|
+
return ollamaCache?.url === url ? ollamaCache.models : [];
|
|
123
177
|
const data = (await res.json());
|
|
124
178
|
const models = (data.models ?? []).map((m) => ({
|
|
125
179
|
id: m.name,
|
|
@@ -129,6 +183,11 @@ export async function fetchOllamaModels(baseUrl) {
|
|
|
129
183
|
ollamaCache = { models, fetchedAt: Date.now(), url };
|
|
130
184
|
return models;
|
|
131
185
|
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
if (ollamaCache?.url === url)
|
|
188
|
+
return ollamaCache.models;
|
|
189
|
+
throw err;
|
|
190
|
+
}
|
|
132
191
|
finally {
|
|
133
192
|
clearTimeout(timeout);
|
|
134
193
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-fetchers.js","sourceRoot":"","sources":["../../src/providers/model-fetchers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,oEAAoE;AAEpE,+DAA+D;AAC/D,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAEvC,6DAA6D;AAC7D,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,CAAC;AAEnC,4CAA4C;AAC5C,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAE/B,mEAAmE;AACnE,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAElC,8EAA8E;AAC9E,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;AAEpE,+EAA+E;AAC/E,MAAM,0BAA0B,GAAG;IACjC,MAAM;IACN,UAAU;IACV,YAAY;IACZ,KAAK;IACL,QAAQ;IACR,SAAS;IACT,OAAO;IACP,OAAO;IACP,WAAW;CACZ,CAAC;AAEF,oEAAoE;AAEpE,IAAI,eAAe,GAA8D,IAAI,CAAC;AACtF,IAAI,WAAW,GAA+E,IAAI,CAAC;AACnG,IAAI,WAAW,GAA2E,IAAI,CAAC;AAE/F,wDAAwD;AACxD,MAAM,UAAU,uBAAuB;IACrC,eAAe,GAAG,IAAI,CAAC;IACvB,WAAW,GAAG,IAAI,CAAC;IACnB,WAAW,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"model-fetchers.js","sourceRoot":"","sources":["../../src/providers/model-fetchers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider snapshot cache.
|
|
3
|
+
*
|
|
4
|
+
* Computing a provider's availability + auth status is expensive: it spawns the
|
|
5
|
+
* provider CLI (and, for ACP providers, runs a full agent handshake). Doing that
|
|
6
|
+
* inline on every `GET /api/providers` froze the initial page load while ~7
|
|
7
|
+
* providers were probed.
|
|
8
|
+
*
|
|
9
|
+
* This cache computes the snapshot once, serves it immediately, and refreshes in
|
|
10
|
+
* the background (stale-while-revalidate). Warm it at startup so the first page
|
|
11
|
+
* load never pays the probe cost.
|
|
12
|
+
*/
|
|
13
|
+
import type { ProviderRegistry } from "./registry.js";
|
|
14
|
+
import type { ProviderAuthInfo, RuntimeMode } from "./contracts.js";
|
|
15
|
+
export interface ProviderSnapshot {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
available: boolean;
|
|
20
|
+
unavailableReason?: string;
|
|
21
|
+
modes: RuntimeMode[];
|
|
22
|
+
auth?: ProviderAuthInfo;
|
|
23
|
+
}
|
|
24
|
+
export declare class ProviderSnapshotCache {
|
|
25
|
+
private readonly registry;
|
|
26
|
+
private snapshot;
|
|
27
|
+
private computedAt;
|
|
28
|
+
private inflight;
|
|
29
|
+
constructor(registry: ProviderRegistry);
|
|
30
|
+
/**
|
|
31
|
+
* Return the current snapshot. Serves cached data immediately when available;
|
|
32
|
+
* refreshes in the background when stale. Only blocks on a cold cache (or when
|
|
33
|
+
* `force` is set, e.g. an explicit user-triggered refresh).
|
|
34
|
+
*/
|
|
35
|
+
get(force?: boolean): Promise<ProviderSnapshot[]>;
|
|
36
|
+
/** Kick a background refresh without awaiting it (used to warm at startup). */
|
|
37
|
+
warm(): void;
|
|
38
|
+
private refresh;
|
|
39
|
+
private compute;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=provider-snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-snapshot.d.ts","sourceRoot":"","sources":["../../src/providers/provider-snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEpE,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAKD,qBAAa,qBAAqB;IAKpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAJrC,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,QAAQ,CAA4C;gBAE/B,QAAQ,EAAE,gBAAgB;IAEvD;;;;OAIG;IACG,GAAG,CAAC,KAAK,UAAQ,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAerD,+EAA+E;IAC/E,IAAI,IAAI,IAAI;IAIZ,OAAO,CAAC,OAAO;YAcD,OAAO;CAsBtB"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider snapshot cache.
|
|
3
|
+
*
|
|
4
|
+
* Computing a provider's availability + auth status is expensive: it spawns the
|
|
5
|
+
* provider CLI (and, for ACP providers, runs a full agent handshake). Doing that
|
|
6
|
+
* inline on every `GET /api/providers` froze the initial page load while ~7
|
|
7
|
+
* providers were probed.
|
|
8
|
+
*
|
|
9
|
+
* This cache computes the snapshot once, serves it immediately, and refreshes in
|
|
10
|
+
* the background (stale-while-revalidate). Warm it at startup so the first page
|
|
11
|
+
* load never pays the probe cost.
|
|
12
|
+
*/
|
|
13
|
+
/** How long a computed snapshot stays fresh before a background refresh. */
|
|
14
|
+
const SNAPSHOT_TTL_MS = 60_000;
|
|
15
|
+
export class ProviderSnapshotCache {
|
|
16
|
+
registry;
|
|
17
|
+
snapshot = null;
|
|
18
|
+
computedAt = 0;
|
|
19
|
+
inflight = null;
|
|
20
|
+
constructor(registry) {
|
|
21
|
+
this.registry = registry;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Return the current snapshot. Serves cached data immediately when available;
|
|
25
|
+
* refreshes in the background when stale. Only blocks on a cold cache (or when
|
|
26
|
+
* `force` is set, e.g. an explicit user-triggered refresh).
|
|
27
|
+
*/
|
|
28
|
+
async get(force = false) {
|
|
29
|
+
const fresh = this.snapshot && Date.now() - this.computedAt < SNAPSHOT_TTL_MS;
|
|
30
|
+
if (!force && fresh)
|
|
31
|
+
return this.snapshot;
|
|
32
|
+
// Stale but present: kick a background refresh, return what we have now.
|
|
33
|
+
if (!force && this.snapshot) {
|
|
34
|
+
void this.refresh().catch(() => { });
|
|
35
|
+
return this.snapshot;
|
|
36
|
+
}
|
|
37
|
+
// Cold cache or forced refresh: must wait for a computation.
|
|
38
|
+
return this.refresh();
|
|
39
|
+
}
|
|
40
|
+
/** Kick a background refresh without awaiting it (used to warm at startup). */
|
|
41
|
+
warm() {
|
|
42
|
+
void this.refresh().catch(() => { });
|
|
43
|
+
}
|
|
44
|
+
refresh() {
|
|
45
|
+
if (this.inflight)
|
|
46
|
+
return this.inflight;
|
|
47
|
+
this.inflight = this.compute()
|
|
48
|
+
.then((snap) => {
|
|
49
|
+
this.snapshot = snap;
|
|
50
|
+
this.computedAt = Date.now();
|
|
51
|
+
return snap;
|
|
52
|
+
})
|
|
53
|
+
.finally(() => {
|
|
54
|
+
this.inflight = null;
|
|
55
|
+
});
|
|
56
|
+
return this.inflight;
|
|
57
|
+
}
|
|
58
|
+
async compute() {
|
|
59
|
+
const providers = this.registry.list();
|
|
60
|
+
return Promise.all(providers.map(async (p) => {
|
|
61
|
+
await p.checkAvailability().catch(() => false);
|
|
62
|
+
const auth = await p.getAuthStatus?.().catch(() => p.info.auth
|
|
63
|
+
? { ...p.info.auth, authenticated: null, detail: "Failed to check provider auth status." }
|
|
64
|
+
: undefined);
|
|
65
|
+
return {
|
|
66
|
+
id: p.id,
|
|
67
|
+
name: p.info.name,
|
|
68
|
+
description: p.info.description,
|
|
69
|
+
available: p.info.available,
|
|
70
|
+
unavailableReason: p.info.unavailableReason,
|
|
71
|
+
modes: p.info.modes,
|
|
72
|
+
auth: auth ?? p.info.auth,
|
|
73
|
+
};
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=provider-snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-snapshot.js","sourceRoot":"","sources":["../../src/providers/provider-snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/routes/chat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAA4B,MAAM,uBAAuB,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAe,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAgCjE,OAAO,KAAK,EAAS,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAgGvF,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBrE;AAyED,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE3D;AAyUD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAyCtF;
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/routes/chat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAA4B,MAAM,uBAAuB,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAe,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAgCjE,OAAO,KAAK,EAAS,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAgGvF,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBrE;AAyED,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE3D;AAyUD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAyCtF;AA0ZD,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,oBAAoB,CAAC,EAAE,0BAA0B,CAAC;IAClD,YAAY,CAAC,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,KACtD,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,SAAS,EACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,aAAa,EACjC,iBAAiB,CAAC,EAAE,cAAc,QA85DnC"}
|
package/dist/routes/chat.js
CHANGED
|
@@ -439,6 +439,16 @@ function accumulateThinking(sessionId, content) {
|
|
|
439
439
|
/** Record a tool call start in the streaming accumulator */
|
|
440
440
|
function accumulateToolStart(sessionId, callId, tool, args, parentCallId) {
|
|
441
441
|
const acc = getOrCreateAccumulator(sessionId);
|
|
442
|
+
// ACP agents can re-emit an enriched tool.start for the same callId
|
|
443
|
+
// (progressive tool_call_update). Upgrade in place rather than duplicating.
|
|
444
|
+
const existing = acc.toolCalls.find(t => t.callId === callId);
|
|
445
|
+
if (existing) {
|
|
446
|
+
existing.tool = tool;
|
|
447
|
+
existing.args = args;
|
|
448
|
+
if (parentCallId !== undefined)
|
|
449
|
+
existing.parentCallId = parentCallId;
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
442
452
|
acc.toolCalls.push({ callId, parentCallId, tool, args, ok: true, message: "", startedAt: Date.now() });
|
|
443
453
|
const last = acc.segments[acc.segments.length - 1];
|
|
444
454
|
if (last?.type === "toolGroup") {
|
|
@@ -1458,17 +1468,28 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
|
|
|
1458
1468
|
// tokens were streamed for it.
|
|
1459
1469
|
tokenBytesThisBlock = 0;
|
|
1460
1470
|
const callId = event.callId ?? `cli-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1461
|
-
// Accumulate for persistence
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
}
|
|
1471
|
-
|
|
1471
|
+
// Accumulate for persistence. ACP agents may re-emit an enriched
|
|
1472
|
+
// tool.start for the same callId (progressive tool_call_update),
|
|
1473
|
+
// so upgrade the existing entry in place instead of duplicating.
|
|
1474
|
+
const existingCliCall = cliToolCalls.find(t => t.callId === callId);
|
|
1475
|
+
if (existingCliCall) {
|
|
1476
|
+
existingCliCall.tool = event.tool;
|
|
1477
|
+
existingCliCall.args = event.args ?? {};
|
|
1478
|
+
if (event.parentCallId !== undefined)
|
|
1479
|
+
existingCliCall.parentCallId = event.parentCallId;
|
|
1480
|
+
}
|
|
1481
|
+
else {
|
|
1482
|
+
cliToolCalls.push({
|
|
1483
|
+
callId,
|
|
1484
|
+
parentCallId: event.parentCallId,
|
|
1485
|
+
tool: event.tool,
|
|
1486
|
+
args: event.args ?? {},
|
|
1487
|
+
ok: true,
|
|
1488
|
+
message: "",
|
|
1489
|
+
startedAt: Date.now(),
|
|
1490
|
+
});
|
|
1491
|
+
pendingToolGroup.push(callId);
|
|
1492
|
+
}
|
|
1472
1493
|
// Save backup of the original file before external providers mutate it.
|
|
1473
1494
|
const mutationPath = getExternalFileMutationPath(event.tool, event.args);
|
|
1474
1495
|
if (mutationPath && cliFsSurface) {
|