@idcloudhost/ai-connect 0.1.0

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 (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +287 -0
  3. package/dist/adapters/aider.d.ts +11 -0
  4. package/dist/adapters/aider.d.ts.map +1 -0
  5. package/dist/adapters/aider.js +69 -0
  6. package/dist/adapters/aider.js.map +1 -0
  7. package/dist/adapters/claude-code.d.ts +17 -0
  8. package/dist/adapters/claude-code.d.ts.map +1 -0
  9. package/dist/adapters/claude-code.js +73 -0
  10. package/dist/adapters/claude-code.js.map +1 -0
  11. package/dist/adapters/codex.d.ts +11 -0
  12. package/dist/adapters/codex.d.ts.map +1 -0
  13. package/dist/adapters/codex.js +71 -0
  14. package/dist/adapters/codex.js.map +1 -0
  15. package/dist/adapters/continue.d.ts +7 -0
  16. package/dist/adapters/continue.d.ts.map +1 -0
  17. package/dist/adapters/continue.js +79 -0
  18. package/dist/adapters/continue.js.map +1 -0
  19. package/dist/adapters/crush.d.ts +4 -0
  20. package/dist/adapters/crush.d.ts.map +1 -0
  21. package/dist/adapters/crush.js +72 -0
  22. package/dist/adapters/crush.js.map +1 -0
  23. package/dist/adapters/goose.d.ts +11 -0
  24. package/dist/adapters/goose.d.ts.map +1 -0
  25. package/dist/adapters/goose.js +68 -0
  26. package/dist/adapters/goose.js.map +1 -0
  27. package/dist/adapters/helpers.d.ts +33 -0
  28. package/dist/adapters/helpers.d.ts.map +1 -0
  29. package/dist/adapters/helpers.js +117 -0
  30. package/dist/adapters/helpers.js.map +1 -0
  31. package/dist/adapters/hermes.d.ts +11 -0
  32. package/dist/adapters/hermes.d.ts.map +1 -0
  33. package/dist/adapters/hermes.js +100 -0
  34. package/dist/adapters/hermes.js.map +1 -0
  35. package/dist/adapters/index.d.ts +20 -0
  36. package/dist/adapters/index.d.ts.map +1 -0
  37. package/dist/adapters/index.js +60 -0
  38. package/dist/adapters/index.js.map +1 -0
  39. package/dist/adapters/manual.d.ts +6 -0
  40. package/dist/adapters/manual.d.ts.map +1 -0
  41. package/dist/adapters/manual.js +87 -0
  42. package/dist/adapters/manual.js.map +1 -0
  43. package/dist/adapters/omp.d.ts +8 -0
  44. package/dist/adapters/omp.d.ts.map +1 -0
  45. package/dist/adapters/omp.js +64 -0
  46. package/dist/adapters/omp.js.map +1 -0
  47. package/dist/adapters/openclaw.d.ts +10 -0
  48. package/dist/adapters/openclaw.d.ts.map +1 -0
  49. package/dist/adapters/openclaw.js +107 -0
  50. package/dist/adapters/openclaw.js.map +1 -0
  51. package/dist/adapters/opencode.d.ts +11 -0
  52. package/dist/adapters/opencode.d.ts.map +1 -0
  53. package/dist/adapters/opencode.js +86 -0
  54. package/dist/adapters/opencode.js.map +1 -0
  55. package/dist/adapters/pi-family.d.ts +14 -0
  56. package/dist/adapters/pi-family.d.ts.map +1 -0
  57. package/dist/adapters/pi-family.js +27 -0
  58. package/dist/adapters/pi-family.js.map +1 -0
  59. package/dist/adapters/pi.d.ts +8 -0
  60. package/dist/adapters/pi.d.ts.map +1 -0
  61. package/dist/adapters/pi.js +56 -0
  62. package/dist/adapters/pi.js.map +1 -0
  63. package/dist/adapters/shell-env.d.ts +12 -0
  64. package/dist/adapters/shell-env.d.ts.map +1 -0
  65. package/dist/adapters/shell-env.js +81 -0
  66. package/dist/adapters/shell-env.js.map +1 -0
  67. package/dist/adapters/zed.d.ts +10 -0
  68. package/dist/adapters/zed.d.ts.map +1 -0
  69. package/dist/adapters/zed.js +91 -0
  70. package/dist/adapters/zed.js.map +1 -0
  71. package/dist/cli.d.ts +3 -0
  72. package/dist/cli.d.ts.map +1 -0
  73. package/dist/cli.js +207 -0
  74. package/dist/cli.js.map +1 -0
  75. package/dist/commands/connect.d.ts +3 -0
  76. package/dist/commands/connect.d.ts.map +1 -0
  77. package/dist/commands/connect.js +179 -0
  78. package/dist/commands/connect.js.map +1 -0
  79. package/dist/commands/context.d.ts +21 -0
  80. package/dist/commands/context.d.ts.map +1 -0
  81. package/dist/commands/context.js +4 -0
  82. package/dist/commands/context.js.map +1 -0
  83. package/dist/commands/doctor.d.ts +11 -0
  84. package/dist/commands/doctor.d.ts.map +1 -0
  85. package/dist/commands/doctor.js +85 -0
  86. package/dist/commands/doctor.js.map +1 -0
  87. package/dist/commands/env.d.ts +7 -0
  88. package/dist/commands/env.d.ts.map +1 -0
  89. package/dist/commands/env.js +37 -0
  90. package/dist/commands/env.js.map +1 -0
  91. package/dist/commands/list.d.ts +3 -0
  92. package/dist/commands/list.d.ts.map +1 -0
  93. package/dist/commands/list.js +39 -0
  94. package/dist/commands/list.js.map +1 -0
  95. package/dist/commands/login.d.ts +7 -0
  96. package/dist/commands/login.d.ts.map +1 -0
  97. package/dist/commands/login.js +130 -0
  98. package/dist/commands/login.js.map +1 -0
  99. package/dist/commands/models.d.ts +9 -0
  100. package/dist/commands/models.d.ts.map +1 -0
  101. package/dist/commands/models.js +51 -0
  102. package/dist/commands/models.js.map +1 -0
  103. package/dist/commands/remove.d.ts +3 -0
  104. package/dist/commands/remove.d.ts.map +1 -0
  105. package/dist/commands/remove.js +43 -0
  106. package/dist/commands/remove.js.map +1 -0
  107. package/dist/commands/snippet.d.ts +7 -0
  108. package/dist/commands/snippet.d.ts.map +1 -0
  109. package/dist/commands/snippet.js +91 -0
  110. package/dist/commands/snippet.js.map +1 -0
  111. package/dist/core/detect.d.ts +12 -0
  112. package/dist/core/detect.d.ts.map +1 -0
  113. package/dist/core/detect.js +59 -0
  114. package/dist/core/detect.js.map +1 -0
  115. package/dist/core/discovery.d.ts +46 -0
  116. package/dist/core/discovery.d.ts.map +1 -0
  117. package/dist/core/discovery.js +124 -0
  118. package/dist/core/discovery.js.map +1 -0
  119. package/dist/core/gateway.d.ts +59 -0
  120. package/dist/core/gateway.d.ts.map +1 -0
  121. package/dist/core/gateway.js +385 -0
  122. package/dist/core/gateway.js.map +1 -0
  123. package/dist/core/http.d.ts +18 -0
  124. package/dist/core/http.d.ts.map +1 -0
  125. package/dist/core/http.js +73 -0
  126. package/dist/core/http.js.map +1 -0
  127. package/dist/core/management.d.ts +47 -0
  128. package/dist/core/management.d.ts.map +1 -0
  129. package/dist/core/management.js +88 -0
  130. package/dist/core/management.js.map +1 -0
  131. package/dist/core/store.d.ts +25 -0
  132. package/dist/core/store.d.ts.map +1 -0
  133. package/dist/core/store.js +48 -0
  134. package/dist/core/store.js.map +1 -0
  135. package/dist/fsutil/edit.d.ts +18 -0
  136. package/dist/fsutil/edit.d.ts.map +1 -0
  137. package/dist/fsutil/edit.js +102 -0
  138. package/dist/fsutil/edit.js.map +1 -0
  139. package/dist/fsutil/formats.d.ts +32 -0
  140. package/dist/fsutil/formats.d.ts.map +1 -0
  141. package/dist/fsutil/formats.js +154 -0
  142. package/dist/fsutil/formats.js.map +1 -0
  143. package/dist/index.d.ts +23 -0
  144. package/dist/index.d.ts.map +1 -0
  145. package/dist/index.js +8 -0
  146. package/dist/index.js.map +1 -0
  147. package/dist/types.d.ts +134 -0
  148. package/dist/types.d.ts.map +1 -0
  149. package/dist/types.js +3 -0
  150. package/dist/types.js.map +1 -0
  151. package/dist/ui.d.ts +20 -0
  152. package/dist/ui.d.ts.map +1 -0
  153. package/dist/ui.js +69 -0
  154. package/dist/ui.js.map +1 -0
  155. package/package.json +75 -0
@@ -0,0 +1,385 @@
1
+ import { HttpError, request, requestJson } from './http.js';
2
+ /** Split a base URL into an origin and the path prefix the OpenAI routes hang off. */
3
+ export function splitBase(apiBase) {
4
+ const url = new URL(apiBase);
5
+ const basePath = url.pathname.replace(/\/+$/, '');
6
+ const origin = url.origin;
7
+ return { origin, basePath, apiBase: origin + basePath };
8
+ }
9
+ function joinUrl(base, path) {
10
+ return base.replace(/\/+$/, '') + '/' + path.replace(/^\/+/, '');
11
+ }
12
+ export async function resolveApiBase(input, apiKey, opts = {}) {
13
+ const cleaned = normalizeUrl(input);
14
+ const { origin, basePath } = splitBase(cleaned);
15
+ // LiteLLM answers on both `/models` and `/v1/models`, so "it responded" is not
16
+ // enough to pick a base. Prefer the canonical `/v1` form: every OpenAI client
17
+ // assumes it, and some agents hard-code the suffix check.
18
+ const candidates = unique([
19
+ ...(basePath.endsWith('/v1') ? [origin + basePath] : [origin + basePath + '/v1']),
20
+ origin + '/v1',
21
+ origin + basePath,
22
+ origin,
23
+ ]).filter(Boolean);
24
+ const headers = apiKey ? { authorization: `Bearer ${apiKey}` } : {};
25
+ const timeoutMs = opts.timeoutMs ?? 8000;
26
+ let weakest = 'unknown';
27
+ for (const candidate of candidates) {
28
+ let res;
29
+ try {
30
+ res = await request(joinUrl(candidate, 'models'), { headers, timeoutMs });
31
+ }
32
+ catch {
33
+ continue; // unreachable candidate; try the next
34
+ }
35
+ // A 200 is unambiguous.
36
+ if (res.ok)
37
+ return { ...splitBase(candidate), probed: true, discrimination: 'not-needed' };
38
+ // 404 means no such route here — a real miss, keep looking.
39
+ if (res.status === 404)
40
+ continue;
41
+ // Everything else (401/403 = key problem not URL problem, 405 = route exists
42
+ // but wants another method) only proves the route exists IF this host answers
43
+ // 404 for paths that do not exist. That is an assumption about the stack in
44
+ // front of the gateway, so check it instead of trusting it.
45
+ if (res.status === 401 || res.status === 403 || res.status === 405) {
46
+ const verdict = await controlProbe(candidate, timeoutMs);
47
+ if (verdict === 'live')
48
+ return { ...splitBase(candidate), probed: true, discrimination: 'live' };
49
+ // Collapsed or unchecked: this candidate proves nothing. Record the weaker
50
+ // finding and keep going, in case a later candidate answers 200 outright.
51
+ if (verdict === 'collapsed')
52
+ weakest = 'collapsed';
53
+ else if (weakest !== 'collapsed')
54
+ weakest = 'unknown';
55
+ }
56
+ }
57
+ // Nothing answered conclusively. Fall back to what the user gave us and let the
58
+ // caller explain which of the two failures this was.
59
+ return { apiBase: origin + basePath, origin, basePath, probed: false, discrimination: weakest };
60
+ }
61
+ /**
62
+ * Ask for a path that cannot exist. A 404 proves this host distinguishes routes,
63
+ * which is what makes an auth error on a real path meaningful. A uniform answer
64
+ * means something is replying before routing, and every status-code inference we
65
+ * would otherwise make is worthless.
66
+ *
67
+ * The random segment keeps a cache or WAF from ever holding a stored answer.
68
+ */
69
+ async function controlProbe(candidate, timeoutMs) {
70
+ const nonce = Math.random().toString(36).slice(2, 12);
71
+ try {
72
+ // Deliberately unauthenticated: we are testing routing, not credentials.
73
+ const res = await request(joinUrl(candidate, `__idch-probe-${nonce}`), { timeoutMs });
74
+ return res.status === 404 ? 'live' : 'collapsed';
75
+ }
76
+ catch {
77
+ return 'unknown';
78
+ }
79
+ }
80
+ export function normalizeUrl(input) {
81
+ let s = input.trim().replace(/\/+$/, '');
82
+ if (!/^https?:\/\//i.test(s))
83
+ s = 'https://' + s;
84
+ // Users paste the full endpoint often enough that stripping it is worth doing.
85
+ s = s.replace(/\/(chat\/completions|completions|responses|embeddings|models)$/i, '');
86
+ return s;
87
+ }
88
+ function unique(xs) {
89
+ return [...new Set(xs.map((x) => x.replace(/\/+$/, '')))];
90
+ }
91
+ /**
92
+ * List the models this key may use.
93
+ *
94
+ * `/models` is the OpenAI-standard, always-present source of truth for ids.
95
+ * `/model/info` is a LiteLLM extension that adds context windows, pricing and
96
+ * capability flags — nice to have, so a failure there is not fatal.
97
+ */
98
+ export async function listModels(apiBase, apiKey, opts = {}) {
99
+ const headers = { authorization: `Bearer ${apiKey}` };
100
+ const timeoutMs = opts.timeoutMs ?? 20_000;
101
+ const list = await requestJson(joinUrl(apiBase, 'models'), { headers, timeoutMs });
102
+ const ids = (list.data ?? []).map((m) => m.id).filter((x) => typeof x === 'string' && x.length > 0);
103
+ const byId = new Map();
104
+ for (const id of ids)
105
+ byId.set(id, { id, label: id });
106
+ const info = await fetchModelInfo(apiBase, apiKey, timeoutMs);
107
+ for (const row of info) {
108
+ const existing = byId.get(row.id);
109
+ if (existing)
110
+ Object.assign(existing, row, { id: existing.id });
111
+ // A model present in /model/info but not /models is not usable by this key; skip it.
112
+ }
113
+ return [...byId.values()].sort((a, b) => a.id.localeCompare(b.id));
114
+ }
115
+ async function fetchModelInfo(apiBase, apiKey, timeoutMs) {
116
+ const headers = { authorization: `Bearer ${apiKey}` };
117
+ const { origin, basePath } = splitBase(apiBase);
118
+ // LiteLLM serves this at /v1/model/info and, on older builds, /model/info.
119
+ const urls = unique([joinUrl(apiBase, 'model/info'), joinUrl(origin + basePath, 'model/info'), joinUrl(origin, 'model/info')]);
120
+ for (const url of urls) {
121
+ try {
122
+ const res = await requestJson(url, { headers, timeoutMs });
123
+ const rows = (res.data ?? [])
124
+ .map((row) => toGatewayModel(row))
125
+ .filter((x) => x !== null);
126
+ if (rows.length)
127
+ return rows;
128
+ }
129
+ catch {
130
+ /* optional enrichment — keep going */
131
+ }
132
+ }
133
+ return [];
134
+ }
135
+ function toGatewayModel(row) {
136
+ const id = row.model_name?.trim();
137
+ if (!id)
138
+ return null;
139
+ const mi = row.model_info ?? {};
140
+ const num = (k) => (typeof mi[k] === 'number' ? mi[k] : undefined);
141
+ const bool = (k) => (typeof mi[k] === 'boolean' ? mi[k] : undefined);
142
+ const inputPerToken = num('input_cost_per_token');
143
+ const outputPerToken = num('output_cost_per_token');
144
+ const provider = derivedProvider(row);
145
+ const model = { id, label: id };
146
+ if (provider)
147
+ model.provider = provider;
148
+ const ctx = num('max_input_tokens') ?? num('max_tokens');
149
+ if (ctx)
150
+ model.contextWindow = ctx;
151
+ const out = num('max_output_tokens');
152
+ if (out)
153
+ model.maxOutputTokens = out;
154
+ if (inputPerToken !== undefined)
155
+ model.inputUsdPer1M = round(inputPerToken * 1_000_000);
156
+ if (outputPerToken !== undefined)
157
+ model.outputUsdPer1M = round(outputPerToken * 1_000_000);
158
+ if (typeof mi.mode === 'string')
159
+ model.mode = mi.mode;
160
+ const vision = bool('supports_vision');
161
+ if (vision !== undefined)
162
+ model.supportsVision = vision;
163
+ const tools = bool('supports_function_calling');
164
+ if (tools !== undefined)
165
+ model.supportsTools = tools;
166
+ return model;
167
+ }
168
+ function derivedProvider(row) {
169
+ const p = row.litellm_params;
170
+ if (!p)
171
+ return undefined;
172
+ if (p.custom_llm_provider)
173
+ return p.custom_llm_provider;
174
+ const m = p.model;
175
+ if (m && m.includes('/'))
176
+ return m.split('/')[0];
177
+ return undefined;
178
+ }
179
+ function round(n) {
180
+ return Math.round(n * 1e6) / 1e6;
181
+ }
182
+ /** Models that make sense to register with a coding agent. */
183
+ export function chatModels(models) {
184
+ return models.filter((m) => !m.mode || m.mode === 'chat' || m.mode === 'completion' || m.mode === 'responses');
185
+ }
186
+ /* ----------------------------------------------------------- capabilities */
187
+ const PROBE_PROMPT = [{ role: 'user', content: 'Reply with the single word: ok' }];
188
+ /**
189
+ * Ask the running gateway what it actually supports rather than trusting a
190
+ * static compatibility table. Every adapter's README section is generated from
191
+ * this, so users never get told a feature works when it does not.
192
+ */
193
+ export async function probeCapabilities(apiBase, apiKey, model, opts = {}) {
194
+ const headers = { authorization: `Bearer ${apiKey}` };
195
+ const timeoutMs = opts.timeoutMs ?? 45_000;
196
+ const checks = [];
197
+ const wanted = opts.include ? new Set(opts.include) : null;
198
+ const want = (id) => !wanted || wanted.has(id);
199
+ const record = async (id, label, fn) => {
200
+ if (!want(id)) {
201
+ checks.push({ id, label, status: 'skip' });
202
+ return false;
203
+ }
204
+ try {
205
+ const detail = await fn();
206
+ const check = { id, label, status: 'pass' };
207
+ if (detail)
208
+ check.detail = detail;
209
+ checks.push(check);
210
+ return true;
211
+ }
212
+ catch (err) {
213
+ checks.push({ id, label, status: 'fail', detail: errText(err) });
214
+ return false;
215
+ }
216
+ };
217
+ await record('models', 'GET /models', async () => {
218
+ const r = await requestJson(joinUrl(apiBase, 'models'), { headers, timeoutMs: 15_000 });
219
+ return `${(r.data ?? []).length} models visible to this key`;
220
+ });
221
+ await record('chat', 'POST /chat/completions', async () => {
222
+ const r = await requestJson(joinUrl(apiBase, 'chat/completions'), { method: 'POST', headers, timeoutMs, body: { model, messages: PROBE_PROMPT, max_tokens: 16 } });
223
+ const text = r.choices?.[0]?.message?.content?.trim();
224
+ return text ? `replied ${JSON.stringify(text.slice(0, 40))}` : 'replied with an empty message';
225
+ });
226
+ await record('streaming', 'Server-sent event streaming (stream: true)', async () => {
227
+ const res = await request(joinUrl(apiBase, 'chat/completions'), {
228
+ method: 'POST',
229
+ headers,
230
+ timeoutMs,
231
+ body: { model, messages: PROBE_PROMPT, max_tokens: 16, stream: true },
232
+ });
233
+ if (!res.ok)
234
+ throw new HttpError(res.status, res.url, await res.text());
235
+ const body = await res.text();
236
+ if (!body.includes('data:'))
237
+ throw new Error('response was not an SSE stream');
238
+ return `${body.split('data:').length - 1} chunks`;
239
+ });
240
+ await record('tools', 'Tool / function calling', async () => {
241
+ const r = await requestJson(joinUrl(apiBase, 'chat/completions'), {
242
+ method: 'POST',
243
+ headers,
244
+ timeoutMs,
245
+ body: {
246
+ model,
247
+ messages: [{ role: 'user', content: 'What is the weather in Jakarta? Use the tool.' }],
248
+ max_tokens: 128,
249
+ tools: [
250
+ {
251
+ type: 'function',
252
+ function: {
253
+ name: 'get_weather',
254
+ description: 'Get the current weather for a city',
255
+ parameters: {
256
+ type: 'object',
257
+ properties: { city: { type: 'string' } },
258
+ required: ['city'],
259
+ },
260
+ },
261
+ },
262
+ ],
263
+ },
264
+ });
265
+ const calls = r.choices?.[0]?.message?.tool_calls;
266
+ // The gateway accepted the tools field; whether the model chose to call is its own business.
267
+ return calls?.length ? 'model returned a tool_call' : 'request accepted (model chose not to call a tool)';
268
+ });
269
+ await record('response_format_json', 'response_format: json_object', async () => {
270
+ await requestJson(joinUrl(apiBase, 'chat/completions'), {
271
+ method: 'POST',
272
+ headers,
273
+ timeoutMs,
274
+ body: {
275
+ model,
276
+ messages: [{ role: 'user', content: 'Return {"ok":true} as JSON.' }],
277
+ max_tokens: 32,
278
+ response_format: { type: 'json_object' },
279
+ },
280
+ });
281
+ return 'accepted';
282
+ });
283
+ await record('response_format_schema', 'response_format: json_schema (structured output)', async () => {
284
+ await requestJson(joinUrl(apiBase, 'chat/completions'), {
285
+ method: 'POST',
286
+ headers,
287
+ timeoutMs,
288
+ body: {
289
+ model,
290
+ messages: [{ role: 'user', content: 'Return ok=true.' }],
291
+ max_tokens: 32,
292
+ response_format: {
293
+ type: 'json_schema',
294
+ json_schema: {
295
+ name: 'probe',
296
+ strict: true,
297
+ schema: { type: 'object', properties: { ok: { type: 'boolean' } }, required: ['ok'], additionalProperties: false },
298
+ },
299
+ },
300
+ },
301
+ });
302
+ return 'accepted';
303
+ });
304
+ await record('vision', 'Image input (multimodal content parts)', async () => {
305
+ // 1x1 transparent PNG — smallest legal image we can send.
306
+ const png = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
307
+ await requestJson(joinUrl(apiBase, 'chat/completions'), {
308
+ method: 'POST',
309
+ headers,
310
+ timeoutMs,
311
+ body: {
312
+ model,
313
+ max_tokens: 16,
314
+ messages: [
315
+ {
316
+ role: 'user',
317
+ content: [
318
+ { type: 'text', text: 'What colour is this?' },
319
+ { type: 'image_url', image_url: { url: png } },
320
+ ],
321
+ },
322
+ ],
323
+ },
324
+ });
325
+ return 'accepted';
326
+ });
327
+ await record('embeddings', 'POST /embeddings', async () => {
328
+ const r = await requestJson(joinUrl(apiBase, 'embeddings'), {
329
+ method: 'POST',
330
+ headers,
331
+ timeoutMs,
332
+ body: { model, input: 'probe' },
333
+ });
334
+ return `${(r.data ?? []).length} vector(s)`;
335
+ });
336
+ await record('responses_api', 'POST /responses (OpenAI Responses API)', async () => {
337
+ await requestJson(joinUrl(apiBase, 'responses'), {
338
+ method: 'POST',
339
+ headers,
340
+ timeoutMs,
341
+ body: { model, input: 'Reply with: ok' },
342
+ });
343
+ return 'accepted';
344
+ });
345
+ await record('anthropic_messages', 'POST /messages (Anthropic wire format)', async () => {
346
+ const { origin, basePath } = splitBase(apiBase);
347
+ const url = joinUrl(origin + basePath, 'messages');
348
+ await requestJson(url, {
349
+ method: 'POST',
350
+ headers: { ...headers, 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' },
351
+ timeoutMs,
352
+ body: { model, max_tokens: 16, messages: PROBE_PROMPT },
353
+ });
354
+ return 'accepted';
355
+ });
356
+ await record('rate_limit_headers', 'Rate limit / quota headers', async () => {
357
+ const res = await request(joinUrl(apiBase, 'chat/completions'), {
358
+ method: 'POST',
359
+ headers,
360
+ timeoutMs,
361
+ body: { model, messages: PROBE_PROMPT, max_tokens: 8 },
362
+ });
363
+ const found = [...res.headers.keys()].filter((h) => /ratelimit|rate-limit|retry-after/i.test(h));
364
+ if (!found.length)
365
+ throw new Error('gateway sent no rate-limit headers');
366
+ return found.join(', ');
367
+ });
368
+ return { model, checks };
369
+ }
370
+ function errText(err) {
371
+ if (err instanceof HttpError)
372
+ return `HTTP ${err.status}: ${err.friendly}`;
373
+ return err instanceof Error ? err.message : String(err);
374
+ }
375
+ /** Single non-streaming chat call. Used by `connect --verify` and `doctor`. */
376
+ export async function testChat(apiBase, apiKey, model, prompt = 'Reply with the single word: ok') {
377
+ const r = await requestJson(joinUrl(apiBase, 'chat/completions'), {
378
+ method: 'POST',
379
+ headers: { authorization: `Bearer ${apiKey}` },
380
+ timeoutMs: 60_000,
381
+ body: { model, messages: [{ role: 'user', content: prompt }], max_tokens: 32 },
382
+ });
383
+ return r.choices?.[0]?.message?.content?.trim() ?? '';
384
+ }
385
+ //# sourceMappingURL=gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../src/core/gateway.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export declare class HttpError extends Error {
2
+ readonly status: number;
3
+ readonly url: string;
4
+ readonly body: string;
5
+ constructor(status: number, url: string, body: string, message?: string);
6
+ /** Best-effort extraction of a human message from OpenAI/LiteLLM/our-API error bodies. */
7
+ get friendly(): string;
8
+ }
9
+ export interface RequestOptions {
10
+ method?: string;
11
+ headers?: Record<string, string>;
12
+ body?: unknown;
13
+ timeoutMs?: number;
14
+ signal?: AbortSignal;
15
+ }
16
+ export declare function request(url: string, opts?: RequestOptions): Promise<Response>;
17
+ export declare function requestJson<T>(url: string, opts?: RequestOptions): Promise<T>;
18
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/core/http.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAU,SAAQ,KAAK;IAEhC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAFZ,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,MAAM;IAMlB,0FAA0F;IAC1F,IAAI,QAAQ,IAAI,MAAM,CAcrB;CACF;AAMD,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqBvF;AAED,wBAAsB,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC,CAUvF"}
@@ -0,0 +1,73 @@
1
+ export class HttpError extends Error {
2
+ status;
3
+ url;
4
+ body;
5
+ constructor(status, url, body, message) {
6
+ super(message ?? `HTTP ${status} from ${url}${body ? `: ${truncate(body, 400)}` : ''}`);
7
+ this.status = status;
8
+ this.url = url;
9
+ this.body = body;
10
+ this.name = 'HttpError';
11
+ }
12
+ /** Best-effort extraction of a human message from OpenAI/LiteLLM/our-API error bodies. */
13
+ get friendly() {
14
+ try {
15
+ const j = JSON.parse(this.body);
16
+ const err = j.error;
17
+ if (err && typeof err === 'object' && typeof err.message === 'string') {
18
+ return String(err.message);
19
+ }
20
+ if (typeof err === 'string')
21
+ return err;
22
+ if (typeof j.message === 'string')
23
+ return j.message;
24
+ if (typeof j.detail === 'string')
25
+ return j.detail;
26
+ }
27
+ catch {
28
+ /* body was not JSON */
29
+ }
30
+ return truncate(this.body || `HTTP ${this.status}`, 300);
31
+ }
32
+ }
33
+ function truncate(s, n) {
34
+ return s.length > n ? s.slice(0, n) + '…' : s;
35
+ }
36
+ export async function request(url, opts = {}) {
37
+ const timeout = opts.timeoutMs ?? 30_000;
38
+ const controller = new AbortController();
39
+ const timer = setTimeout(() => controller.abort(new Error(`timed out after ${timeout}ms`)), timeout);
40
+ if (opts.signal)
41
+ opts.signal.addEventListener('abort', () => controller.abort(opts.signal.reason), { once: true });
42
+ const headers = { accept: 'application/json', ...opts.headers };
43
+ let body;
44
+ if (opts.body !== undefined) {
45
+ body = JSON.stringify(opts.body);
46
+ headers['content-type'] ??= 'application/json';
47
+ }
48
+ try {
49
+ return await fetch(url, { method: opts.method ?? 'GET', headers, body, signal: controller.signal });
50
+ }
51
+ catch (err) {
52
+ const cause = err instanceof Error ? err.message : String(err);
53
+ throw new Error(`request to ${url} failed: ${cause}`);
54
+ }
55
+ finally {
56
+ clearTimeout(timer);
57
+ }
58
+ }
59
+ export async function requestJson(url, opts = {}) {
60
+ const res = await request(url, opts);
61
+ const text = await res.text();
62
+ if (!res.ok)
63
+ throw new HttpError(res.status, url, text);
64
+ if (!text.trim())
65
+ return undefined;
66
+ try {
67
+ return JSON.parse(text);
68
+ }
69
+ catch {
70
+ throw new Error(`expected JSON from ${url} but got: ${truncate(text, 200)}`);
71
+ }
72
+ }
73
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/core/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Thin client for the IDCloudHost PaaS dashboard API.
3
+ *
4
+ * The dashboard does not serve inference. It manages LiteLLM teams, virtual keys,
5
+ * budgets and usage, and it is where the gateway URL is published. Using it is
6
+ * optional: a customer who already has a key and a base URL never needs it.
7
+ */
8
+ import type { GatewayModel } from '../types.js';
9
+ export declare const DEFAULT_DASHBOARD_URL = "https://dash.paas.id";
10
+ export interface AiStatus {
11
+ enabled: boolean;
12
+ integration_available: boolean;
13
+ litellm_team_id?: string;
14
+ usd_idr_rate?: number;
15
+ /** The OpenAI-compatible gateway URL. Discovered, never hard-coded. */
16
+ public_base_url?: string;
17
+ }
18
+ export interface KeyRow {
19
+ key_id: string;
20
+ key_alias?: string;
21
+ models?: string[];
22
+ spend?: number;
23
+ max_budget?: number;
24
+ created_at?: string;
25
+ }
26
+ export declare class ManagementClient {
27
+ private readonly token;
28
+ private readonly orgId?;
29
+ private readonly root;
30
+ constructor(dashboardUrl: string, token: string, orgId?: string | undefined);
31
+ private headers;
32
+ private url;
33
+ status(): Promise<AiStatus>;
34
+ models(): Promise<GatewayModel[]>;
35
+ keys(): Promise<KeyRow[]>;
36
+ /** Requires an organization admin token. The secret is returned exactly once. */
37
+ createKey(alias: string, models?: string[]): Promise<{
38
+ key: string;
39
+ key_alias?: string;
40
+ models?: string[];
41
+ }>;
42
+ /** Public catalog — no organization context, no auth. */
43
+ static publicModels(dashboardUrl?: string): Promise<GatewayModel[]>;
44
+ }
45
+ /** Turn a management-API failure into something a customer can act on. */
46
+ export declare function explainManagementError(err: unknown): string;
47
+ //# sourceMappingURL=management.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"management.d.ts","sourceRoot":"","sources":["../../src/core/management.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,eAAO,MAAM,qBAAqB,yBAAyB,CAAC;AAE5D,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAWD,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,gBAAgB;IAKzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IALzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAG5B,YAAY,EAAE,MAAM,EACH,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,MAAM,YAAA;IAKjC,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,GAAG;IAKL,MAAM,IAAI,OAAO,CAAC,QAAQ,CAAC;IAI3B,MAAM,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAQjC,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAQ/B,iFAAiF;IAC3E,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAMlH,yDAAyD;WAC5C,YAAY,CAAC,YAAY,SAAwB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CAKzF;AAcD,0EAA0E;AAC1E,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAc3D"}
@@ -0,0 +1,88 @@
1
+ import { HttpError, requestJson } from './http.js';
2
+ export const DEFAULT_DASHBOARD_URL = 'https://dash.paas.id';
3
+ export class ManagementClient {
4
+ token;
5
+ orgId;
6
+ root;
7
+ constructor(dashboardUrl, token, orgId) {
8
+ this.token = token;
9
+ this.orgId = orgId;
10
+ this.root = dashboardUrl.trim().replace(/\/+$/, '').replace(/\/api(\/v1)?$/, '');
11
+ }
12
+ headers() {
13
+ const h = { authorization: `Bearer ${this.token}` };
14
+ if (this.orgId)
15
+ h['x-organization-id'] = this.orgId;
16
+ return h;
17
+ }
18
+ url(suffix) {
19
+ if (!this.orgId)
20
+ throw new Error('an organization id is required for this call');
21
+ return `${this.root}/api/v1/organizations/${encodeURIComponent(this.orgId)}/ai${suffix}`;
22
+ }
23
+ async status() {
24
+ return requestJson(this.url('/status'), { headers: this.headers(), timeoutMs: 20_000 });
25
+ }
26
+ async models() {
27
+ const res = await requestJson(this.url('/models'), {
28
+ headers: this.headers(),
29
+ timeoutMs: 20_000,
30
+ });
31
+ return (res.models ?? []).map(toModel).filter((m) => m !== null);
32
+ }
33
+ async keys() {
34
+ const res = await requestJson(this.url('/keys'), {
35
+ headers: this.headers(),
36
+ timeoutMs: 20_000,
37
+ });
38
+ return res.keys ?? [];
39
+ }
40
+ /** Requires an organization admin token. The secret is returned exactly once. */
41
+ async createKey(alias, models) {
42
+ const body = { key_alias: alias };
43
+ if (models?.length)
44
+ body.models = models;
45
+ return requestJson(this.url('/keys'), { method: 'POST', headers: this.headers(), body, timeoutMs: 30_000 });
46
+ }
47
+ /** Public catalog — no organization context, no auth. */
48
+ static async publicModels(dashboardUrl = DEFAULT_DASHBOARD_URL) {
49
+ const root = dashboardUrl.replace(/\/+$/, '').replace(/\/api(\/v1)?$/, '');
50
+ const res = await requestJson(`${root}/api/v1/ai/models`, { timeoutMs: 20_000 });
51
+ return (res.models ?? []).map(toModel).filter((m) => m !== null);
52
+ }
53
+ }
54
+ function toModel(row) {
55
+ const id = row.model_name?.trim();
56
+ if (!id)
57
+ return null;
58
+ const m = { id, label: id };
59
+ if (row.provider)
60
+ m.provider = row.provider;
61
+ if (row.max_context_tokens)
62
+ m.contextWindow = row.max_context_tokens;
63
+ if (row.input_usd_per_1m !== undefined)
64
+ m.inputUsdPer1M = row.input_usd_per_1m;
65
+ if (row.output_usd_per_1m !== undefined)
66
+ m.outputUsdPer1M = row.output_usd_per_1m;
67
+ if (row.mode)
68
+ m.mode = row.mode;
69
+ return m;
70
+ }
71
+ /** Turn a management-API failure into something a customer can act on. */
72
+ export function explainManagementError(err) {
73
+ if (!(err instanceof HttpError))
74
+ return err instanceof Error ? err.message : String(err);
75
+ switch (err.status) {
76
+ case 401:
77
+ return 'the dashboard rejected your token (401). Generate a fresh one and pass it with --token.';
78
+ case 403:
79
+ return 'your account is not allowed to do this (403). Creating keys needs an organization admin.';
80
+ case 404:
81
+ return 'no such organization, or AI is not enabled for it (404). Check --org.';
82
+ case 503:
83
+ return 'the AI integration is not configured on this environment (503).';
84
+ default:
85
+ return err.friendly;
86
+ }
87
+ }
88
+ //# sourceMappingURL=management.js.map