@jait/gateway 0.1.435 → 0.1.436

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 (106) hide show
  1. package/dist/providers/acp-provider.d.ts +2 -0
  2. package/dist/providers/acp-provider.d.ts.map +1 -1
  3. package/dist/providers/acp-provider.js +53 -0
  4. package/dist/providers/acp-provider.js.map +1 -1
  5. package/dist/providers/jait-provider.d.ts.map +1 -1
  6. package/dist/providers/jait-provider.js +2 -0
  7. package/dist/providers/jait-provider.js.map +1 -1
  8. package/dist/routes/chat.d.ts.map +1 -1
  9. package/dist/routes/chat.js +19 -2
  10. package/dist/routes/chat.js.map +1 -1
  11. package/dist/routes/jobs.d.ts.map +1 -1
  12. package/dist/routes/jobs.js +17 -34
  13. package/dist/routes/jobs.js.map +1 -1
  14. package/dist/routes/providers.d.ts +24 -0
  15. package/dist/routes/providers.d.ts.map +1 -0
  16. package/dist/routes/providers.js +300 -0
  17. package/dist/routes/providers.js.map +1 -0
  18. package/dist/routes/threads.d.ts +0 -3
  19. package/dist/routes/threads.d.ts.map +1 -1
  20. package/dist/routes/threads.js +0 -230
  21. package/dist/routes/threads.js.map +1 -1
  22. package/dist/scheduler/service.d.ts +4 -1
  23. package/dist/scheduler/service.d.ts.map +1 -1
  24. package/dist/scheduler/service.js +63 -6
  25. package/dist/scheduler/service.js.map +1 -1
  26. package/dist/server.d.ts.map +1 -1
  27. package/dist/server.js +9 -0
  28. package/dist/server.js.map +1 -1
  29. package/dist/tools/agent-loop.d.ts +5 -1
  30. package/dist/tools/agent-loop.d.ts.map +1 -1
  31. package/dist/tools/agent-loop.js +4 -1
  32. package/dist/tools/agent-loop.js.map +1 -1
  33. package/dist/tools/agent-tools.d.ts.map +1 -1
  34. package/dist/tools/agent-tools.js +11 -1
  35. package/dist/tools/agent-tools.js.map +1 -1
  36. package/dist/tools/chat-modes.d.ts +5 -2
  37. package/dist/tools/chat-modes.d.ts.map +1 -1
  38. package/dist/tools/chat-modes.js +41 -1
  39. package/dist/tools/chat-modes.js.map +1 -1
  40. package/dist/tools/contracts.d.ts +1 -0
  41. package/dist/tools/contracts.d.ts.map +1 -1
  42. package/dist/tools/index.d.ts.map +1 -1
  43. package/dist/tools/index.js +12 -10
  44. package/dist/tools/index.js.map +1 -1
  45. package/dist/tools/prompts/shared-sections.d.ts +1 -0
  46. package/dist/tools/prompts/shared-sections.d.ts.map +1 -1
  47. package/dist/tools/prompts/shared-sections.js +5 -0
  48. package/dist/tools/prompts/shared-sections.js.map +1 -1
  49. package/package.json +1 -1
  50. package/web-dist/assets/{_basePickBy-5xpbol_n.js → _basePickBy-9TYNOM1l.js} +1 -1
  51. package/web-dist/assets/{_baseUniq-BfuJlen6.js → _baseUniq-CpWsYINF.js} +1 -1
  52. package/web-dist/assets/{arc-Kr1vkHgz.js → arc-DSvVuoRa.js} +1 -1
  53. package/web-dist/assets/{architectureDiagram-2XIMDMQ5-CGirVFae.js → architectureDiagram-2XIMDMQ5-tzgX3Vvn.js} +1 -1
  54. package/web-dist/assets/{blockDiagram-WCTKOSBZ-Cwk_62nk.js → blockDiagram-WCTKOSBZ-DjuKCu7h.js} +1 -1
  55. package/web-dist/assets/{c4Diagram-IC4MRINW-Can2WHA0.js → c4Diagram-IC4MRINW-zbpmigpb.js} +1 -1
  56. package/web-dist/assets/channel-D1ANp35Z.js +1 -0
  57. package/web-dist/assets/{chunk-4BX2VUAB-CtXXc-pV.js → chunk-4BX2VUAB-CVadPDBZ.js} +1 -1
  58. package/web-dist/assets/{chunk-55IACEB6-CvGTFy0d.js → chunk-55IACEB6-CNWQUwk_.js} +1 -1
  59. package/web-dist/assets/{chunk-FMBD7UC4-Cp3z8tqZ.js → chunk-FMBD7UC4-BH9THwsk.js} +1 -1
  60. package/web-dist/assets/{chunk-JSJVCQXG-I0qvdAUX.js → chunk-JSJVCQXG-BX3PRvkI.js} +1 -1
  61. package/web-dist/assets/{chunk-KX2RTZJC-B7qf1Dm7.js → chunk-KX2RTZJC-B7DF41n1.js} +1 -1
  62. package/web-dist/assets/{chunk-NQ4KR5QH-Bm555zTO.js → chunk-NQ4KR5QH-DhBLWNF5.js} +1 -1
  63. package/web-dist/assets/{chunk-QZHKN3VN-D3IZNq3Y.js → chunk-QZHKN3VN-DZTA9dqS.js} +1 -1
  64. package/web-dist/assets/{chunk-WL4C6EOR-C4zBW6VB.js → chunk-WL4C6EOR-DvFJqxTA.js} +1 -1
  65. package/web-dist/assets/classDiagram-VBA2DB6C-eekYA5Po.js +1 -0
  66. package/web-dist/assets/classDiagram-v2-RAHNMMFH-eekYA5Po.js +1 -0
  67. package/web-dist/assets/clone-CLQSY4Vh.js +1 -0
  68. package/web-dist/assets/{cose-bilkent-S5V4N54A-CyT_jRXW.js → cose-bilkent-S5V4N54A-jfwYRSvf.js} +1 -1
  69. package/web-dist/assets/{dagre-KLK3FWXG-BjG5Q2Px.js → dagre-KLK3FWXG-a-jKdMpQ.js} +1 -1
  70. package/web-dist/assets/{diagram-E7M64L7V-B9HCURNk.js → diagram-E7M64L7V-WdQ2vS_J.js} +1 -1
  71. package/web-dist/assets/{diagram-IFDJBPK2-BXXMPUfK.js → diagram-IFDJBPK2-CS1GA1Qv.js} +1 -1
  72. package/web-dist/assets/{diagram-P4PSJMXO-e_cE5oyu.js → diagram-P4PSJMXO-CZan0aG6.js} +1 -1
  73. package/web-dist/assets/{erDiagram-INFDFZHY-CFFuN3AV.js → erDiagram-INFDFZHY-io4hXPu2.js} +1 -1
  74. package/web-dist/assets/{flowDiagram-PKNHOUZH-D--bf6aJ.js → flowDiagram-PKNHOUZH-DB_tKlXg.js} +1 -1
  75. package/web-dist/assets/{ganttDiagram-A5KZAMGK-DrWPpShA.js → ganttDiagram-A5KZAMGK-DkU-deZW.js} +1 -1
  76. package/web-dist/assets/{gitGraphDiagram-K3NZZRJ6-DHs8i1pg.js → gitGraphDiagram-K3NZZRJ6-BlDmtRkv.js} +1 -1
  77. package/web-dist/assets/{graph-Bo38Z0Qh.js → graph-DfjSSucn.js} +1 -1
  78. package/web-dist/assets/{index-BvWV235X.js → index-BOZSANwJ.js} +1 -1
  79. package/web-dist/assets/{index-DK7yonuQ.js → index-Bi2-02kA.js} +1 -1
  80. package/web-dist/assets/{index-uKPv0tns.js → index-CM4cLE2g.js} +366 -366
  81. package/web-dist/assets/index-U0Q51fQQ.css +32 -0
  82. package/web-dist/assets/{infoDiagram-LFFYTUFH-BrvEJ5gz.js → infoDiagram-LFFYTUFH-Bvx2qhAd.js} +1 -1
  83. package/web-dist/assets/{ishikawaDiagram-PHBUUO56-WNxhUbLJ.js → ishikawaDiagram-PHBUUO56-DTEBYUHw.js} +1 -1
  84. package/web-dist/assets/{journeyDiagram-4ABVD52K-CvbGMp6G.js → journeyDiagram-4ABVD52K-BbnZ4sxn.js} +1 -1
  85. package/web-dist/assets/{kanban-definition-K7BYSVSG-_Yg3nqbC.js → kanban-definition-K7BYSVSG-xQlhwJm9.js} +1 -1
  86. package/web-dist/assets/{layout-DdC0_Lhx.js → layout-6T2sGeQu.js} +1 -1
  87. package/web-dist/assets/{linear-DGVBkAgf.js → linear-P0Etymzw.js} +1 -1
  88. package/web-dist/assets/{mindmap-definition-YRQLILUH-nM17s_Wy.js → mindmap-definition-YRQLILUH-CZIkrTzQ.js} +1 -1
  89. package/web-dist/assets/{pieDiagram-SKSYHLDU-CJcMLR_U.js → pieDiagram-SKSYHLDU-Bb9fLv4k.js} +1 -1
  90. package/web-dist/assets/{quadrantDiagram-337W2JSQ-BKiL4e_d.js → quadrantDiagram-337W2JSQ-BEIfa773.js} +1 -1
  91. package/web-dist/assets/{requirementDiagram-Z7DCOOCP-Dse5zp_O.js → requirementDiagram-Z7DCOOCP-Bk5gMigd.js} +1 -1
  92. package/web-dist/assets/{sankeyDiagram-WA2Y5GQK-BlcECWFS.js → sankeyDiagram-WA2Y5GQK-DhzVf2Lu.js} +1 -1
  93. package/web-dist/assets/{sequenceDiagram-2WXFIKYE-Cp7f5jmh.js → sequenceDiagram-2WXFIKYE-D2Pk_Gd4.js} +1 -1
  94. package/web-dist/assets/{stateDiagram-RAJIS63D-BkSKy7hg.js → stateDiagram-RAJIS63D-Dk8qXYTb.js} +1 -1
  95. package/web-dist/assets/stateDiagram-v2-FVOUBMTO-CBI7tCIp.js +1 -0
  96. package/web-dist/assets/{timeline-definition-YZTLITO2-CrnFcc8G.js → timeline-definition-YZTLITO2-Bc_OdSSU.js} +1 -1
  97. package/web-dist/assets/{treemap-KZPCXAKY-D_OSNTUe.js → treemap-KZPCXAKY-Db7Q_nBv.js} +1 -1
  98. package/web-dist/assets/{vennDiagram-LZ73GAT5-C3nfRcJP.js → vennDiagram-LZ73GAT5-BOO3XPKa.js} +1 -1
  99. package/web-dist/assets/{xychartDiagram-JWTSCODW-C3D6ydyc.js → xychartDiagram-JWTSCODW-Br5uXaC-.js} +1 -1
  100. package/web-dist/index.html +2 -2
  101. package/web-dist/assets/channel-B_G7ql8G.js +0 -1
  102. package/web-dist/assets/classDiagram-VBA2DB6C-BrzBiRoi.js +0 -1
  103. package/web-dist/assets/classDiagram-v2-RAHNMMFH-BrzBiRoi.js +0 -1
  104. package/web-dist/assets/clone-CTOuJIt4.js +0 -1
  105. package/web-dist/assets/index-CmmJPAgU.css +0 -32
  106. package/web-dist/assets/stateDiagram-v2-FVOUBMTO-DKZSTZUO.js +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/routes/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAuG/C,MAAM,WAAW,iBAAiB;IAChC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,EAAE,CAAC,EAAE,cAAc,CAAC;CACrB;AAED,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,iBAAiB,GACtB,IAAI,CAuMN"}
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Provider REST routes.
3
+ *
4
+ * Lists available providers, exposes auth flows, and returns
5
+ * dynamically-fetched model catalogues for each backend.
6
+ *
7
+ * GET /api/providers — list available providers
8
+ * GET /api/providers/:id/auth/status — get provider auth status
9
+ * POST /api/providers/:id/auth/login — start provider login
10
+ * POST /api/providers/:id/auth/logout — log out provider
11
+ * GET /api/providers/:id/models — list models for a provider
12
+ */
13
+ import { requireAuth } from "../security/http-auth.js";
14
+ // ── Model fetchers with in-memory caches ─────────────────────────
15
+ /** Fetch models from OpenRouter API with a 5-second timeout and in-memory cache. */
16
+ let orCache = null;
17
+ const OR_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
18
+ async function fetchOpenRouterModels(apiKey) {
19
+ if (orCache && Date.now() - orCache.fetchedAt < OR_CACHE_TTL) {
20
+ return orCache.models;
21
+ }
22
+ const controller = new AbortController();
23
+ const timeout = setTimeout(() => controller.abort(), 5000);
24
+ try {
25
+ const res = await fetch("https://openrouter.ai/api/v1/models", {
26
+ headers: { Authorization: `Bearer ${apiKey}` },
27
+ signal: controller.signal,
28
+ });
29
+ if (!res.ok)
30
+ return [];
31
+ const data = (await res.json());
32
+ const models = (data.data ?? [])
33
+ .filter((m) => m.id && !m.id.includes(":free"))
34
+ .slice(0, 100)
35
+ .map((m) => ({
36
+ id: m.id,
37
+ name: m.name || m.id.split("/").pop() || m.id,
38
+ description: m.description?.slice(0, 80),
39
+ }));
40
+ orCache = { models, fetchedAt: Date.now() };
41
+ return models;
42
+ }
43
+ finally {
44
+ clearTimeout(timeout);
45
+ }
46
+ }
47
+ /** Fetch models from OpenAI /v1/models with a 5-second timeout and in-memory cache. */
48
+ let openaiCache = null;
49
+ const OPENAI_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
50
+ /** Model ID prefixes that represent chat-completion-capable models. */
51
+ const OPENAI_CHAT_PREFIXES = ["gpt-", "o1", "o3", "o4", "chatgpt-"];
52
+ async function fetchOpenAIModels(apiKey, baseUrl) {
53
+ const url = baseUrl.replace(/\/+$/, "");
54
+ if (openaiCache && openaiCache.baseUrl === url && Date.now() - openaiCache.fetchedAt < OPENAI_CACHE_TTL) {
55
+ return openaiCache.models;
56
+ }
57
+ const controller = new AbortController();
58
+ const timeout = setTimeout(() => controller.abort(), 5000);
59
+ try {
60
+ const res = await fetch(`${url}/models`, {
61
+ headers: { Authorization: `Bearer ${apiKey}` },
62
+ signal: controller.signal,
63
+ });
64
+ if (!res.ok)
65
+ return [];
66
+ const data = (await res.json());
67
+ const models = (data.data ?? [])
68
+ .filter((m) => m.id && OPENAI_CHAT_PREFIXES.some((p) => m.id.startsWith(p)))
69
+ // Remove fine-tune snapshots, realtime, audio-only, transcription variants
70
+ .filter((m) => !m.id.includes(":ft-") && !m.id.includes("realtime") && !m.id.includes("transcribe") && !m.id.includes("tts") && !m.id.includes("dall-e") && !m.id.includes("whisper"))
71
+ .sort((a, b) => a.id.localeCompare(b.id))
72
+ .map((m) => ({
73
+ id: m.id,
74
+ name: m.id,
75
+ description: m.owned_by ? `by ${m.owned_by}` : undefined,
76
+ }));
77
+ openaiCache = { models, fetchedAt: Date.now(), baseUrl: url };
78
+ return models;
79
+ }
80
+ finally {
81
+ clearTimeout(timeout);
82
+ }
83
+ }
84
+ let ollamaCache = null;
85
+ const OLLAMA_CACHE_TTL = 30 * 1000; // 30 seconds (local, fast)
86
+ async function fetchOllamaModels(baseUrl) {
87
+ const url = baseUrl.replace(/\/+$/, "");
88
+ if (ollamaCache && ollamaCache.url === url && Date.now() - ollamaCache.fetchedAt < OLLAMA_CACHE_TTL) {
89
+ return ollamaCache.models;
90
+ }
91
+ const controller = new AbortController();
92
+ const timeout = setTimeout(() => controller.abort(), 5000);
93
+ try {
94
+ const res = await fetch(`${url}/api/tags`, { signal: controller.signal });
95
+ if (!res.ok)
96
+ return [];
97
+ const data = (await res.json());
98
+ const models = (data.models ?? []).map((m) => ({
99
+ id: m.name,
100
+ name: m.name,
101
+ description: [m.details?.family, m.details?.parameter_size].filter(Boolean).join(" · ") || undefined,
102
+ }));
103
+ ollamaCache = { models, fetchedAt: Date.now(), url };
104
+ return models;
105
+ }
106
+ finally {
107
+ clearTimeout(timeout);
108
+ }
109
+ }
110
+ export function registerProviderRoutes(app, config, deps) {
111
+ const { providerRegistry, ws } = deps;
112
+ /** List available providers (local + remote) */
113
+ app.get("/api/providers", async (request, reply) => {
114
+ const authUser = await requireAuth(request, reply, config.jwtSecret);
115
+ if (!authUser)
116
+ return;
117
+ const providers = providerRegistry.list();
118
+ const providerSnapshots = await Promise.all(providers.map(async (p) => {
119
+ await p.checkAvailability().catch(() => false);
120
+ const auth = await p.getAuthStatus?.().catch(() => p.info.auth
121
+ ? { ...p.info.auth, authenticated: null, detail: "Failed to check provider auth status." }
122
+ : undefined);
123
+ return { provider: p, auth };
124
+ }));
125
+ // Collect remote provider info from connected filesystem nodes
126
+ const remoteProviders = [];
127
+ if (ws) {
128
+ for (const node of ws.getFsNodes()) {
129
+ if (node.isGateway)
130
+ continue;
131
+ remoteProviders.push({
132
+ nodeId: node.id,
133
+ nodeName: node.name,
134
+ platform: node.platform,
135
+ providers: node.providers ?? [],
136
+ });
137
+ }
138
+ }
139
+ return {
140
+ providers: providerSnapshots.map(({ provider: p, auth }) => ({
141
+ id: p.id,
142
+ name: p.info.name,
143
+ description: p.info.description,
144
+ available: p.info.available,
145
+ unavailableReason: p.info.unavailableReason,
146
+ modes: p.info.modes,
147
+ auth: auth ?? p.info.auth,
148
+ })),
149
+ remoteProviders,
150
+ };
151
+ });
152
+ /** Get provider auth status */
153
+ app.get("/api/providers/:id/auth/status", async (request, reply) => {
154
+ const authUser = await requireAuth(request, reply, config.jwtSecret);
155
+ if (!authUser)
156
+ return;
157
+ const { id } = request.params;
158
+ const provider = providerRegistry.get(id);
159
+ if (!provider)
160
+ return reply.status(404).send({ error: `Unknown provider: ${id}` });
161
+ if (!provider.getAuthStatus) {
162
+ return reply.status(501).send({ error: `Provider ${id} does not support auth status` });
163
+ }
164
+ return provider.getAuthStatus();
165
+ });
166
+ /** Start provider login */
167
+ app.post("/api/providers/:id/auth/login", async (request, reply) => {
168
+ const authUser = await requireAuth(request, reply, config.jwtSecret);
169
+ if (!authUser)
170
+ return;
171
+ const { id } = request.params;
172
+ const provider = providerRegistry.get(id);
173
+ if (!provider)
174
+ return reply.status(404).send({ error: `Unknown provider: ${id}` });
175
+ if (!provider.startLogin) {
176
+ return reply.status(501).send({ error: `Provider ${id} does not support login` });
177
+ }
178
+ const result = await provider.startLogin();
179
+ if (!result.ok && result.status === "unsupported") {
180
+ return reply.status(501).send(result);
181
+ }
182
+ if (!result.ok) {
183
+ return reply.status(500).send(result);
184
+ }
185
+ return result;
186
+ });
187
+ /** Log out provider */
188
+ app.post("/api/providers/:id/auth/logout", async (request, reply) => {
189
+ const authUser = await requireAuth(request, reply, config.jwtSecret);
190
+ if (!authUser)
191
+ return;
192
+ const { id } = request.params;
193
+ const provider = providerRegistry.get(id);
194
+ if (!provider)
195
+ return reply.status(404).send({ error: `Unknown provider: ${id}` });
196
+ if (!provider.logout) {
197
+ return reply.status(501).send({ error: `Provider ${id} does not support logout` });
198
+ }
199
+ const result = await provider.logout();
200
+ if (!result.ok && result.status === "unsupported") {
201
+ return reply.status(501).send(result);
202
+ }
203
+ if (!result.ok) {
204
+ return reply.status(500).send(result);
205
+ }
206
+ return result;
207
+ });
208
+ /** List models for a specific provider */
209
+ app.get("/api/providers/:id/models", async (request, reply) => {
210
+ const authUser = await requireAuth(request, reply, config.jwtSecret);
211
+ if (!authUser)
212
+ return;
213
+ const { id } = request.params;
214
+ const provider = providerRegistry.get(id);
215
+ if (!provider) {
216
+ return reply.status(404).send({ error: `Unknown provider: ${id}` });
217
+ }
218
+ if (!provider.listModels) {
219
+ return { models: [] };
220
+ }
221
+ try {
222
+ let models = await provider.listModels();
223
+ // For jait provider, return models from ALL configured backends, grouped
224
+ if (id === "jait" && deps.userService) {
225
+ const settings = deps.userService.getSettings(authUser.id);
226
+ const userApiKeys = settings.apiKeys ?? {};
227
+ const jaitBackend = settings.jaitBackend || "openai";
228
+ const allModels = [];
229
+ // ── OpenAI models (dynamic when API key available) ────────
230
+ const openaiKey = userApiKeys["OPENAI_API_KEY"]?.trim() || config.openaiApiKey;
231
+ const openaiBaseUrl = userApiKeys["OPENAI_BASE_URL"]?.trim() || config.openaiBaseUrl || "https://api.openai.com/v1";
232
+ if (openaiKey && openaiBaseUrl.includes("openai.com")) {
233
+ try {
234
+ const apiModels = await fetchOpenAIModels(openaiKey, openaiBaseUrl);
235
+ if (apiModels.length > 0) {
236
+ allModels.push(...apiModels.map((m) => ({ ...m, group: "OpenAI" })));
237
+ }
238
+ else {
239
+ allModels.push(...models.map((m) => ({ ...m, group: "OpenAI" })));
240
+ }
241
+ }
242
+ catch {
243
+ allModels.push(...models.map((m) => ({ ...m, group: "OpenAI" })));
244
+ }
245
+ }
246
+ else {
247
+ allModels.push(...models.map((m) => ({ ...m, group: "OpenAI" })));
248
+ }
249
+ // ── OpenRouter models ─────────────────────────────────────
250
+ const openRouterKey = userApiKeys["OPENROUTER_API_KEY"]?.trim();
251
+ if (openRouterKey) {
252
+ try {
253
+ const orModels = await fetchOpenRouterModels(openRouterKey);
254
+ if (orModels.length > 0) {
255
+ allModels.push(...orModels.map((m) => ({ ...m, group: "OpenRouter" })));
256
+ }
257
+ else {
258
+ const { OPENROUTER_MODELS } = await import("../providers/jait-provider.js");
259
+ allModels.push(...OPENROUTER_MODELS.map((m) => ({ ...m, group: "OpenRouter" })));
260
+ }
261
+ }
262
+ catch {
263
+ const { OPENROUTER_MODELS } = await import("../providers/jait-provider.js");
264
+ allModels.push(...OPENROUTER_MODELS.map((m) => ({ ...m, group: "OpenRouter" })));
265
+ }
266
+ }
267
+ // ── Ollama models ─────────────────────────────────────────
268
+ const ollamaUrl = userApiKeys["OLLAMA_URL"]?.trim() || config.ollamaUrl;
269
+ if (ollamaUrl) {
270
+ try {
271
+ const ollamaModels = await fetchOllamaModels(ollamaUrl);
272
+ if (ollamaModels.length > 0) {
273
+ allModels.push(...ollamaModels.map((m) => ({ ...m, group: "Ollama" })));
274
+ }
275
+ }
276
+ catch {
277
+ // Ollama unreachable — skip
278
+ }
279
+ }
280
+ models = allModels;
281
+ // Prepend recent models (if they exist in the full list)
282
+ const recentIds = settings.recentModels ?? [];
283
+ if (recentIds.length > 0) {
284
+ const modelMap = new Map(models.map((m) => [m.id, m]));
285
+ const recents = recentIds
286
+ .filter((rid) => modelMap.has(rid))
287
+ .map((rid) => ({ ...modelMap.get(rid), isRecent: true }));
288
+ return { models, currentBackend: jaitBackend, recentModels: recents.slice(0, 5).map((r) => r.id) };
289
+ }
290
+ return { models, currentBackend: jaitBackend };
291
+ }
292
+ return { models };
293
+ }
294
+ catch (err) {
295
+ return reply.status(500).send({ error: err instanceof Error ? err.message : "Failed to list models" });
296
+ }
297
+ });
298
+ app.log.info("Provider routes registered at /api/providers");
299
+ }
300
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/routes/providers.ts"],"names":[],"mappings":"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"}
@@ -14,9 +14,6 @@
14
14
  * POST /api/threads/:id/stop — stop agent session
15
15
  * POST /api/threads/:id/interrupt — interrupt current turn
16
16
  * POST /api/threads/:id/approve — approve a tool call
17
- * POST /api/threads/:id/create-pr — create a PR for a completed thread
18
- * GET /api/threads/:id/activities — get activity log
19
- * GET /api/providers — list available providers
20
17
  */
21
18
  import type { FastifyInstance } from "fastify";
22
19
  import type { AppConfig } from "../config.js";
@@ -1 +1 @@
1
- {"version":3,"file":"threads.d.ts","sourceRoot":"","sources":["../../src/routes/threads.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAK/C,OAAO,EAA0C,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,OAAO,KAAK,EAAS,aAAa,EAAE,MAAM,oBAAoB,CAAC;AA8H/D,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,UAAU,CAAC,EAAE;QACX,gBAAgB,CACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,gBAAgB,EACxB,aAAa,CAAC,EAAE,MAAM,EACtB,aAAa,CAAC,EAAE,OAAO,EACvB,UAAU,CAAC,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,aAAa,CAAC,CAAC;QAC1B,SAAS,CACP,GAAG,EAAE,MAAM,EACX,UAAU,CAAC,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KAC3F,CAAC;CACH;AAuED,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,eAAe,GACpB,IAAI,CAguDN"}
1
+ {"version":3,"file":"threads.d.ts","sourceRoot":"","sources":["../../src/routes/threads.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAK/C,OAAO,EAA0C,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,OAAO,KAAK,EAAS,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAmE/D,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,UAAU,CAAC,EAAE;QACX,gBAAgB,CACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,gBAAgB,EACxB,aAAa,CAAC,EAAE,MAAM,EACtB,aAAa,CAAC,EAAE,OAAO,EACvB,UAAU,CAAC,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,aAAa,CAAC,CAAC;QAC1B,SAAS,CACP,GAAG,EAAE,MAAM,EACX,UAAU,CAAC,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KAC3F,CAAC;CACH;AAuED,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,eAAe,GACpB,IAAI,CA0iDN"}
@@ -14,9 +14,6 @@
14
14
  * POST /api/threads/:id/stop — stop agent session
15
15
  * POST /api/threads/:id/interrupt — interrupt current turn
16
16
  * POST /api/threads/:id/approve — approve a tool call
17
- * POST /api/threads/:id/create-pr — create a PR for a completed thread
18
- * GET /api/threads/:id/activities — get activity log
19
- * GET /api/providers — list available providers
20
17
  */
21
18
  import { requireAuth, signAuthToken } from "../security/http-auth.js";
22
19
  import { extractTodoResultItems } from "../providers/todo-result.js";
@@ -74,64 +71,6 @@ function resolveThreadProviderId(userSelectedProvider, requestedProvider, fallba
74
71
  }
75
72
  return resolveSelectedProvider();
76
73
  }
77
- /** Fetch models from OpenRouter API with a 5-second timeout and in-memory cache. */
78
- let orCache = null;
79
- const OR_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
80
- async function fetchOpenRouterModels(apiKey) {
81
- if (orCache && Date.now() - orCache.fetchedAt < OR_CACHE_TTL) {
82
- return orCache.models;
83
- }
84
- const controller = new AbortController();
85
- const timeout = setTimeout(() => controller.abort(), 5000);
86
- try {
87
- const res = await fetch("https://openrouter.ai/api/v1/models", {
88
- headers: { Authorization: `Bearer ${apiKey}` },
89
- signal: controller.signal,
90
- });
91
- if (!res.ok)
92
- return [];
93
- const data = (await res.json());
94
- const models = (data.data ?? [])
95
- .filter((m) => m.id && !m.id.includes(":free"))
96
- .slice(0, 100)
97
- .map((m) => ({
98
- id: m.id,
99
- name: m.name || m.id.split("/").pop() || m.id,
100
- description: m.description?.slice(0, 80),
101
- }));
102
- orCache = { models, fetchedAt: Date.now() };
103
- return models;
104
- }
105
- finally {
106
- clearTimeout(timeout);
107
- }
108
- }
109
- let ollamaCache = null;
110
- const OLLAMA_CACHE_TTL = 30 * 1000; // 30 seconds (local, fast)
111
- async function fetchOllamaModels(baseUrl) {
112
- const url = baseUrl.replace(/\/+$/, "");
113
- if (ollamaCache && ollamaCache.url === url && Date.now() - ollamaCache.fetchedAt < OLLAMA_CACHE_TTL) {
114
- return ollamaCache.models;
115
- }
116
- const controller = new AbortController();
117
- const timeout = setTimeout(() => controller.abort(), 5000);
118
- try {
119
- const res = await fetch(`${url}/api/tags`, { signal: controller.signal });
120
- if (!res.ok)
121
- return [];
122
- const data = (await res.json());
123
- const models = (data.models ?? []).map((m) => ({
124
- id: m.name,
125
- name: m.name,
126
- description: [m.details?.family, m.details?.parameter_size].filter(Boolean).join(" · ") || undefined,
127
- }));
128
- ollamaCache = { models, fetchedAt: Date.now(), url };
129
- return models;
130
- }
131
- finally {
132
- clearTimeout(timeout);
133
- }
134
- }
135
74
  const QUEUED_THREAD_MESSAGES_KEY = "queued_thread_messages";
136
75
  function parseQueuedThreadMessagesState(raw) {
137
76
  if (!raw || typeof raw !== "object" || Array.isArray(raw))
@@ -1596,175 +1535,6 @@ export function registerThreadRoutes(app, config, deps) {
1596
1535
  const activities = threadService.getActivities(id, limit);
1597
1536
  return { activities };
1598
1537
  });
1599
- // ── Provider info ────────────────────────────────────────────────
1600
- /** List available providers (local + remote) */
1601
- app.get("/api/providers", async (request, reply) => {
1602
- const authUser = await requireAuth(request, reply, config.jwtSecret);
1603
- if (!authUser)
1604
- return;
1605
- const providers = providerRegistry.list();
1606
- const providerSnapshots = await Promise.all(providers.map(async (p) => {
1607
- await p.checkAvailability().catch(() => false);
1608
- const auth = await p.getAuthStatus?.().catch(() => p.info.auth
1609
- ? { ...p.info.auth, authenticated: null, detail: "Failed to check provider auth status." }
1610
- : undefined);
1611
- return { provider: p, auth };
1612
- }));
1613
- // Collect remote provider info from connected filesystem nodes
1614
- const remoteProviders = [];
1615
- if (ws) {
1616
- for (const node of ws.getFsNodes()) {
1617
- if (node.isGateway)
1618
- continue;
1619
- remoteProviders.push({
1620
- nodeId: node.id,
1621
- nodeName: node.name,
1622
- platform: node.platform,
1623
- providers: node.providers ?? [],
1624
- });
1625
- }
1626
- }
1627
- return {
1628
- providers: providerSnapshots.map(({ provider: p, auth }) => ({
1629
- id: p.id,
1630
- name: p.info.name,
1631
- description: p.info.description,
1632
- available: p.info.available,
1633
- unavailableReason: p.info.unavailableReason,
1634
- modes: p.info.modes,
1635
- auth: auth ?? p.info.auth,
1636
- })),
1637
- remoteProviders,
1638
- };
1639
- });
1640
- /** Get provider auth status */
1641
- app.get("/api/providers/:id/auth/status", async (request, reply) => {
1642
- const authUser = await requireAuth(request, reply, config.jwtSecret);
1643
- if (!authUser)
1644
- return;
1645
- const { id } = request.params;
1646
- const provider = providerRegistry.get(id);
1647
- if (!provider)
1648
- return reply.status(404).send({ error: `Unknown provider: ${id}` });
1649
- if (!provider.getAuthStatus) {
1650
- return reply.status(501).send({ error: `Provider ${id} does not support auth status` });
1651
- }
1652
- return provider.getAuthStatus();
1653
- });
1654
- /** Start provider login */
1655
- app.post("/api/providers/:id/auth/login", async (request, reply) => {
1656
- const authUser = await requireAuth(request, reply, config.jwtSecret);
1657
- if (!authUser)
1658
- return;
1659
- const { id } = request.params;
1660
- const provider = providerRegistry.get(id);
1661
- if (!provider)
1662
- return reply.status(404).send({ error: `Unknown provider: ${id}` });
1663
- if (!provider.startLogin) {
1664
- return reply.status(501).send({ error: `Provider ${id} does not support login` });
1665
- }
1666
- const result = await provider.startLogin();
1667
- if (!result.ok && result.status === "unsupported") {
1668
- return reply.status(501).send(result);
1669
- }
1670
- if (!result.ok) {
1671
- return reply.status(500).send(result);
1672
- }
1673
- return result;
1674
- });
1675
- /** Log out provider */
1676
- app.post("/api/providers/:id/auth/logout", async (request, reply) => {
1677
- const authUser = await requireAuth(request, reply, config.jwtSecret);
1678
- if (!authUser)
1679
- return;
1680
- const { id } = request.params;
1681
- const provider = providerRegistry.get(id);
1682
- if (!provider)
1683
- return reply.status(404).send({ error: `Unknown provider: ${id}` });
1684
- if (!provider.logout) {
1685
- return reply.status(501).send({ error: `Provider ${id} does not support logout` });
1686
- }
1687
- const result = await provider.logout();
1688
- if (!result.ok && result.status === "unsupported") {
1689
- return reply.status(501).send(result);
1690
- }
1691
- if (!result.ok) {
1692
- return reply.status(500).send(result);
1693
- }
1694
- return result;
1695
- });
1696
- /** List models for a specific provider */
1697
- app.get("/api/providers/:id/models", async (request, reply) => {
1698
- const authUser = await requireAuth(request, reply, config.jwtSecret);
1699
- if (!authUser)
1700
- return;
1701
- const { id } = request.params;
1702
- const provider = providerRegistry.get(id);
1703
- if (!provider) {
1704
- return reply.status(404).send({ error: `Unknown provider: ${id}` });
1705
- }
1706
- if (!provider.listModels) {
1707
- return { models: [] };
1708
- }
1709
- try {
1710
- let models = await provider.listModels();
1711
- // For jait provider, return models from ALL configured backends, grouped
1712
- if (id === "jait" && deps.userService) {
1713
- const settings = deps.userService.getSettings(authUser.id);
1714
- const userApiKeys = settings.apiKeys ?? {};
1715
- const jaitBackend = settings.jaitBackend || "openai";
1716
- const allModels = [];
1717
- // ── OpenAI models (always shown) ──────────────────────────
1718
- allModels.push(...models.map((m) => ({ ...m, group: "OpenAI" })));
1719
- // ── OpenRouter models ─────────────────────────────────────
1720
- const openRouterKey = userApiKeys["OPENROUTER_API_KEY"]?.trim();
1721
- if (openRouterKey) {
1722
- try {
1723
- const orModels = await fetchOpenRouterModels(openRouterKey);
1724
- if (orModels.length > 0) {
1725
- allModels.push(...orModels.map((m) => ({ ...m, group: "OpenRouter" })));
1726
- }
1727
- else {
1728
- const { OPENROUTER_MODELS } = await import("../providers/jait-provider.js");
1729
- allModels.push(...OPENROUTER_MODELS.map((m) => ({ ...m, group: "OpenRouter" })));
1730
- }
1731
- }
1732
- catch {
1733
- const { OPENROUTER_MODELS } = await import("../providers/jait-provider.js");
1734
- allModels.push(...OPENROUTER_MODELS.map((m) => ({ ...m, group: "OpenRouter" })));
1735
- }
1736
- }
1737
- // ── Ollama models ─────────────────────────────────────────
1738
- const ollamaUrl = userApiKeys["OLLAMA_URL"]?.trim() || config.ollamaUrl;
1739
- if (ollamaUrl) {
1740
- try {
1741
- const ollamaModels = await fetchOllamaModels(ollamaUrl);
1742
- if (ollamaModels.length > 0) {
1743
- allModels.push(...ollamaModels.map((m) => ({ ...m, group: "Ollama" })));
1744
- }
1745
- }
1746
- catch {
1747
- // Ollama unreachable — skip
1748
- }
1749
- }
1750
- models = allModels;
1751
- // Prepend recent models (if they exist in the full list)
1752
- const recentIds = settings.recentModels ?? [];
1753
- if (recentIds.length > 0) {
1754
- const modelMap = new Map(models.map((m) => [m.id, m]));
1755
- const recents = recentIds
1756
- .filter((rid) => modelMap.has(rid))
1757
- .map((rid) => ({ ...modelMap.get(rid), isRecent: true }));
1758
- return { models, currentBackend: jaitBackend, recentModels: recents.slice(0, 5).map((r) => r.id) };
1759
- }
1760
- return { models, currentBackend: jaitBackend };
1761
- }
1762
- return { models };
1763
- }
1764
- catch (err) {
1765
- return reply.status(500).send({ error: err instanceof Error ? err.message : "Failed to list models" });
1766
- }
1767
- });
1768
1538
  app.log.info("Agent thread routes registered at /api/threads");
1769
1539
  }
1770
1540
  //# sourceMappingURL=threads.js.map