@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.
Files changed (87) hide show
  1. package/dist/memory/contracts.d.ts +1 -0
  2. package/dist/memory/contracts.d.ts.map +1 -1
  3. package/dist/memory/service.d.ts +1 -0
  4. package/dist/memory/service.d.ts.map +1 -1
  5. package/dist/memory/service.js +4 -0
  6. package/dist/memory/service.js.map +1 -1
  7. package/dist/providers/acp-provider.d.ts +8 -0
  8. package/dist/providers/acp-provider.d.ts.map +1 -1
  9. package/dist/providers/acp-provider.js +88 -17
  10. package/dist/providers/acp-provider.js.map +1 -1
  11. package/dist/providers/model-fetchers.d.ts +7 -1
  12. package/dist/providers/model-fetchers.d.ts.map +1 -1
  13. package/dist/providers/model-fetchers.js +66 -7
  14. package/dist/providers/model-fetchers.js.map +1 -1
  15. package/dist/providers/provider-snapshot.d.ts +41 -0
  16. package/dist/providers/provider-snapshot.d.ts.map +1 -0
  17. package/dist/providers/provider-snapshot.js +77 -0
  18. package/dist/providers/provider-snapshot.js.map +1 -0
  19. package/dist/routes/chat.d.ts.map +1 -1
  20. package/dist/routes/chat.js +32 -11
  21. package/dist/routes/chat.js.map +1 -1
  22. package/dist/routes/providers.d.ts.map +1 -1
  23. package/dist/routes/providers.js +43 -48
  24. package/dist/routes/providers.js.map +1 -1
  25. package/dist/routes/reminders.d.ts +2 -0
  26. package/dist/routes/reminders.d.ts.map +1 -1
  27. package/dist/routes/reminders.js +27 -3
  28. package/dist/routes/reminders.js.map +1 -1
  29. package/dist/server.d.ts.map +1 -1
  30. package/dist/server.js +1 -0
  31. package/dist/server.js.map +1 -1
  32. package/package.json +1 -1
  33. package/web-dist/assets/{_basePickBy-Bs2Q2Eng.js → _basePickBy-vgfYW5YM.js} +1 -1
  34. package/web-dist/assets/{_baseUniq-C1Vgvc6k.js → _baseUniq-BCyddlmv.js} +1 -1
  35. package/web-dist/assets/{arc-B45ZD8Nx.js → arc-CetE4hi3.js} +1 -1
  36. package/web-dist/assets/{architectureDiagram-2XIMDMQ5-Dgn58dd_.js → architectureDiagram-2XIMDMQ5-ySUJrv-h.js} +1 -1
  37. package/web-dist/assets/{blockDiagram-WCTKOSBZ-DVo2YOE_.js → blockDiagram-WCTKOSBZ-BSpA2Vi-.js} +1 -1
  38. package/web-dist/assets/{c4Diagram-IC4MRINW-DGFSFQ71.js → c4Diagram-IC4MRINW-DTIgQZNZ.js} +1 -1
  39. package/web-dist/assets/channel-B4LKl9yt.js +1 -0
  40. package/web-dist/assets/{chunk-4BX2VUAB-BH1NL3uc.js → chunk-4BX2VUAB-l5CswJhC.js} +1 -1
  41. package/web-dist/assets/{chunk-55IACEB6-DXuyCFwp.js → chunk-55IACEB6-BJDbbrXC.js} +1 -1
  42. package/web-dist/assets/{chunk-FMBD7UC4-krCQHjSO.js → chunk-FMBD7UC4-aAPpg8z7.js} +1 -1
  43. package/web-dist/assets/{chunk-JSJVCQXG-Db70Tfzs.js → chunk-JSJVCQXG-BVprtjfJ.js} +1 -1
  44. package/web-dist/assets/{chunk-KX2RTZJC-ClwrCaPu.js → chunk-KX2RTZJC-UovbUaCZ.js} +1 -1
  45. package/web-dist/assets/{chunk-NQ4KR5QH-BgYsa0ay.js → chunk-NQ4KR5QH-Crx9IS7x.js} +1 -1
  46. package/web-dist/assets/{chunk-QZHKN3VN-DcrIkFKB.js → chunk-QZHKN3VN-CP7-7ek1.js} +1 -1
  47. package/web-dist/assets/{chunk-WL4C6EOR-BTf7iLVE.js → chunk-WL4C6EOR-YXqhe30x.js} +1 -1
  48. package/web-dist/assets/classDiagram-VBA2DB6C-B5rNybiS.js +1 -0
  49. package/web-dist/assets/classDiagram-v2-RAHNMMFH-B5rNybiS.js +1 -0
  50. package/web-dist/assets/clone-D42O3IVz.js +1 -0
  51. package/web-dist/assets/{cose-bilkent-S5V4N54A-CTYlJ5P2.js → cose-bilkent-S5V4N54A-IjeOb81w.js} +1 -1
  52. package/web-dist/assets/{dagre-KLK3FWXG-DWI1FJLN.js → dagre-KLK3FWXG-D69PF_t6.js} +1 -1
  53. package/web-dist/assets/{diagram-E7M64L7V-BUK_Kgia.js → diagram-E7M64L7V-DZ_jCthR.js} +1 -1
  54. package/web-dist/assets/{diagram-IFDJBPK2-NqEaUmP3.js → diagram-IFDJBPK2-BAB6O5Dv.js} +1 -1
  55. package/web-dist/assets/{diagram-P4PSJMXO-5Ep5l2GM.js → diagram-P4PSJMXO-CCACsUXt.js} +1 -1
  56. package/web-dist/assets/{erDiagram-INFDFZHY-G_uvZUyt.js → erDiagram-INFDFZHY-B1SILDm-.js} +1 -1
  57. package/web-dist/assets/{flowDiagram-PKNHOUZH-Dpx9wgBT.js → flowDiagram-PKNHOUZH-CZu_oMfJ.js} +1 -1
  58. package/web-dist/assets/{ganttDiagram-A5KZAMGK-C1wksGup.js → ganttDiagram-A5KZAMGK-BCRi3L1T.js} +1 -1
  59. package/web-dist/assets/{gitGraphDiagram-K3NZZRJ6-BMRbny8s.js → gitGraphDiagram-K3NZZRJ6-VDYqRMZf.js} +1 -1
  60. package/web-dist/assets/{graph-D813FHN0.js → graph-CGFhPhx8.js} +1 -1
  61. package/web-dist/assets/{index-Dz5PpkSn.js → index-B0ThQUZY.js} +352 -352
  62. package/web-dist/assets/{index-BHV3c90o.js → index-CbgPCPKw.js} +1 -1
  63. package/web-dist/assets/{index-B0WXmsg6.js → index-Dk7L2F_Y.js} +1 -1
  64. package/web-dist/assets/{infoDiagram-LFFYTUFH-CRhMjd3m.js → infoDiagram-LFFYTUFH-DXP_GMzg.js} +1 -1
  65. package/web-dist/assets/{ishikawaDiagram-PHBUUO56-C0b-DmJz.js → ishikawaDiagram-PHBUUO56-CpbSLbJg.js} +1 -1
  66. package/web-dist/assets/{journeyDiagram-4ABVD52K-7GAYf7qC.js → journeyDiagram-4ABVD52K-Dt27VAaz.js} +1 -1
  67. package/web-dist/assets/{kanban-definition-K7BYSVSG-DYH6GLQ_.js → kanban-definition-K7BYSVSG-DG9J5Mjh.js} +1 -1
  68. package/web-dist/assets/{layout-DflnUaC-.js → layout-D_AF7RYk.js} +1 -1
  69. package/web-dist/assets/{linear-BKaIWChA.js → linear-t3MuHagv.js} +1 -1
  70. package/web-dist/assets/{mindmap-definition-YRQLILUH-DLKYT7in.js → mindmap-definition-YRQLILUH-BlniMcB4.js} +1 -1
  71. package/web-dist/assets/{pieDiagram-SKSYHLDU-1pCzkOws.js → pieDiagram-SKSYHLDU-cDcZejYu.js} +1 -1
  72. package/web-dist/assets/{quadrantDiagram-337W2JSQ-sQvtWhE5.js → quadrantDiagram-337W2JSQ-BO3oDOmW.js} +1 -1
  73. package/web-dist/assets/{requirementDiagram-Z7DCOOCP-DjjWn7oo.js → requirementDiagram-Z7DCOOCP-C0ffaLyW.js} +1 -1
  74. package/web-dist/assets/{sankeyDiagram-WA2Y5GQK-BmubwmS7.js → sankeyDiagram-WA2Y5GQK-C_3OPo5Z.js} +1 -1
  75. package/web-dist/assets/{sequenceDiagram-2WXFIKYE-827kzmaQ.js → sequenceDiagram-2WXFIKYE-CEKGZq0Q.js} +1 -1
  76. package/web-dist/assets/{stateDiagram-RAJIS63D-CVnU2rvz.js → stateDiagram-RAJIS63D-D9w7CWEi.js} +1 -1
  77. package/web-dist/assets/stateDiagram-v2-FVOUBMTO-CREpnVYX.js +1 -0
  78. package/web-dist/assets/{timeline-definition-YZTLITO2-8QfPnNpk.js → timeline-definition-YZTLITO2-CbIkQ8PT.js} +1 -1
  79. package/web-dist/assets/{treemap-KZPCXAKY-D6AwuGcm.js → treemap-KZPCXAKY-CQKrf1qk.js} +1 -1
  80. package/web-dist/assets/{vennDiagram-LZ73GAT5-Bjye7yJQ.js → vennDiagram-LZ73GAT5-BQsFrHpE.js} +1 -1
  81. package/web-dist/assets/{xychartDiagram-JWTSCODW-NBNTRnip.js → xychartDiagram-JWTSCODW-CVpjE7Xh.js} +1 -1
  82. package/web-dist/index.html +1 -1
  83. package/web-dist/assets/channel-Ct_ZzeFZ.js +0 -1
  84. package/web-dist/assets/classDiagram-VBA2DB6C-BA-sk9nf.js +0 -1
  85. package/web-dist/assets/classDiagram-v2-RAHNMMFH-BA-sk9nf.js +0 -1
  86. package/web-dist/assets/clone-SN4ZG9tU.js +0 -1
  87. 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
- /** Fetch the OpenRouter catalogue. Returns [] on any non-OK response. */
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 && Date.now() - openRouterCache.fetchedAt < REMOTE_CACHE_TTL) {
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 && Date.now() - openaiCache.fetchedAt < REMOTE_CACHE_TTL) {
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 && Date.now() - ollamaCache.fetchedAt < OLLAMA_CACHE_TTL) {
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":"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"}
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;AAiZD,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,QAq5DnC"}
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"}
@@ -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
- cliToolCalls.push({
1463
- callId,
1464
- parentCallId: event.parentCallId,
1465
- tool: event.tool,
1466
- args: event.args ?? {},
1467
- ok: true,
1468
- message: "",
1469
- startedAt: Date.now(),
1470
- });
1471
- pendingToolGroup.push(callId);
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) {