@jini-ai/agent-runtime 0.2.1 → 0.3.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.
- package/README.md +2 -2
- package/dist/agent-protocol/acp/session.d.ts +206 -1
- package/dist/agent-protocol/acp/session.d.ts.map +1 -1
- package/dist/agent-protocol/acp/session.js +505 -350
- package/dist/agent-protocol/acp/session.js.map +1 -1
- package/dist/agent-protocol/core/json-line-stream.d.ts +53 -0
- package/dist/agent-protocol/core/json-line-stream.d.ts.map +1 -1
- package/dist/agent-protocol/core/json-line-stream.js +307 -255
- package/dist/agent-protocol/core/json-line-stream.js.map +1 -1
- package/dist/agent-protocol/pi-rpc/events.d.ts +22 -1
- package/dist/agent-protocol/pi-rpc/events.d.ts.map +1 -1
- package/dist/agent-protocol/pi-rpc/events.js +189 -153
- package/dist/agent-protocol/pi-rpc/events.js.map +1 -1
- package/dist/agent-protocol/pi-rpc/session.d.ts +39 -0
- package/dist/agent-protocol/pi-rpc/session.d.ts.map +1 -1
- package/dist/agent-protocol/pi-rpc/session.js +143 -107
- package/dist/agent-protocol/pi-rpc/session.js.map +1 -1
- package/dist/claude-stream.d.ts +64 -1
- package/dist/claude-stream.d.ts.map +1 -1
- package/dist/claude-stream.js +568 -441
- package/dist/claude-stream.js.map +1 -1
- package/dist/defs/aider.d.ts.map +1 -1
- package/dist/defs/aider.js +13 -1
- package/dist/defs/aider.js.map +1 -1
- package/dist/defs/amp.d.ts.map +1 -1
- package/dist/defs/amp.js +16 -1
- package/dist/defs/amp.js.map +1 -1
- package/dist/defs/amr.d.ts +2 -1
- package/dist/defs/amr.d.ts.map +1 -1
- package/dist/defs/amr.js +12 -1
- package/dist/defs/amr.js.map +1 -1
- package/dist/defs/antigravity.d.ts +41 -2
- package/dist/defs/antigravity.d.ts.map +1 -1
- package/dist/defs/antigravity.js +201 -22
- package/dist/defs/antigravity.js.map +1 -1
- package/dist/defs/claude.d.ts +2 -0
- package/dist/defs/claude.d.ts.map +1 -1
- package/dist/defs/claude.js +58 -3
- package/dist/defs/claude.js.map +1 -1
- package/dist/defs/codebuddy.d.ts.map +1 -1
- package/dist/defs/codebuddy.js +9 -1
- package/dist/defs/codebuddy.js.map +1 -1
- package/dist/defs/codex.d.ts +1 -0
- package/dist/defs/codex.d.ts.map +1 -1
- package/dist/defs/codex.js +34 -0
- package/dist/defs/codex.js.map +1 -1
- package/dist/defs/copilot.d.ts.map +1 -1
- package/dist/defs/copilot.js +15 -1
- package/dist/defs/copilot.js.map +1 -1
- package/dist/defs/cursor-agent.d.ts.map +1 -1
- package/dist/defs/cursor-agent.js +24 -2
- package/dist/defs/cursor-agent.js.map +1 -1
- package/dist/defs/deepseek.d.ts.map +1 -1
- package/dist/defs/deepseek.js +12 -0
- package/dist/defs/deepseek.js.map +1 -1
- package/dist/defs/devin.d.ts +2 -1
- package/dist/defs/devin.d.ts.map +1 -1
- package/dist/defs/devin.js +12 -7
- package/dist/defs/devin.js.map +1 -1
- package/dist/defs/grok-build.d.ts.map +1 -1
- package/dist/defs/grok-build.js +10 -0
- package/dist/defs/grok-build.js.map +1 -1
- package/dist/defs/hermes.d.ts +1 -0
- package/dist/defs/hermes.d.ts.map +1 -1
- package/dist/defs/hermes.js +3 -0
- package/dist/defs/hermes.js.map +1 -1
- package/dist/defs/kilo.d.ts +1 -0
- package/dist/defs/kilo.d.ts.map +1 -1
- package/dist/defs/kilo.js +3 -0
- package/dist/defs/kilo.js.map +1 -1
- package/dist/defs/kimi.d.ts +1 -0
- package/dist/defs/kimi.d.ts.map +1 -1
- package/dist/defs/kimi.js +3 -0
- package/dist/defs/kimi.js.map +1 -1
- package/dist/defs/kiro.d.ts +1 -0
- package/dist/defs/kiro.d.ts.map +1 -1
- package/dist/defs/kiro.js +3 -0
- package/dist/defs/kiro.js.map +1 -1
- package/dist/defs/pi.d.ts +1 -1
- package/dist/defs/pi.d.ts.map +1 -1
- package/dist/defs/pi.js +6 -1
- package/dist/defs/pi.js.map +1 -1
- package/dist/defs/qoder.d.ts +1 -0
- package/dist/defs/qoder.d.ts.map +1 -1
- package/dist/defs/qoder.js +15 -0
- package/dist/defs/qoder.js.map +1 -1
- package/dist/defs/qwen.d.ts.map +1 -1
- package/dist/defs/qwen.js +9 -0
- package/dist/defs/qwen.js.map +1 -1
- package/dist/defs/reasonix.d.ts +1 -0
- package/dist/defs/reasonix.d.ts.map +1 -1
- package/dist/defs/reasonix.js +3 -0
- package/dist/defs/reasonix.js.map +1 -1
- package/dist/defs/shared.d.ts +31 -1
- package/dist/defs/shared.d.ts.map +1 -1
- package/dist/defs/shared.js +35 -0
- package/dist/defs/shared.js.map +1 -1
- package/dist/defs/trae-cli.d.ts +1 -0
- package/dist/defs/trae-cli.d.ts.map +1 -1
- package/dist/defs/trae-cli.js +3 -0
- package/dist/defs/trae-cli.js.map +1 -1
- package/dist/defs/vibe.d.ts +1 -0
- package/dist/defs/vibe.d.ts.map +1 -1
- package/dist/defs/vibe.js +3 -0
- package/dist/defs/vibe.js.map +1 -1
- package/dist/detection.d.ts +1 -1
- package/dist/detection.d.ts.map +1 -1
- package/dist/detection.js +7 -2
- package/dist/detection.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/log-file.d.ts +23 -0
- package/dist/log-file.d.ts.map +1 -0
- package/dist/log-file.js +56 -0
- package/dist/log-file.js.map +1 -0
- package/dist/model-registry.d.ts +7 -45
- package/dist/model-registry.d.ts.map +1 -1
- package/dist/model-registry.js.map +1 -1
- package/dist/providers/anthropic-messages.d.ts +198 -6
- package/dist/providers/anthropic-messages.d.ts.map +1 -1
- package/dist/providers/anthropic-messages.js +317 -140
- package/dist/providers/anthropic-messages.js.map +1 -1
- package/dist/providers/azure-chat.d.ts +113 -3
- package/dist/providers/azure-chat.d.ts.map +1 -1
- package/dist/providers/azure-chat.js +114 -21
- package/dist/providers/azure-chat.js.map +1 -1
- package/dist/providers/connection-guard.d.ts +121 -1
- package/dist/providers/connection-guard.d.ts.map +1 -1
- package/dist/providers/connection-guard.js +205 -3
- package/dist/providers/connection-guard.js.map +1 -1
- package/dist/providers/connection-test.d.ts +62 -0
- package/dist/providers/connection-test.d.ts.map +1 -0
- package/dist/providers/connection-test.js +404 -0
- package/dist/providers/connection-test.js.map +1 -0
- package/dist/providers/elevenlabs.d.ts.map +1 -1
- package/dist/providers/elevenlabs.js +3 -2
- package/dist/providers/elevenlabs.js.map +1 -1
- package/dist/providers/google-messages.d.ts +208 -7
- package/dist/providers/google-messages.d.ts.map +1 -1
- package/dist/providers/google-messages.js +331 -105
- package/dist/providers/google-messages.js.map +1 -1
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +1 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/model-catalog.d.ts.map +1 -1
- package/dist/providers/model-catalog.js +21 -0
- package/dist/providers/model-catalog.js.map +1 -1
- package/dist/providers/ollama-chat.d.ts +190 -1
- package/dist/providers/ollama-chat.d.ts.map +1 -1
- package/dist/providers/ollama-chat.js +319 -110
- package/dist/providers/ollama-chat.js.map +1 -1
- package/dist/providers/openai-chat.d.ts +222 -14
- package/dist/providers/openai-chat.d.ts.map +1 -1
- package/dist/providers/openai-chat.js +377 -128
- package/dist/providers/openai-chat.js.map +1 -1
- package/dist/providers/sse-decode.d.ts +2 -2
- package/dist/providers/sse-decode.js +2 -2
- package/dist/types.d.ts +169 -87
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -4
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module providers/connection-test
|
|
3
|
+
*
|
|
4
|
+
* BYOK connection smoke test — sends a tiny "Reply with only: ok" completion
|
|
5
|
+
* request to the configured provider endpoint and classifies the outcome, so
|
|
6
|
+
* a settings UI can tell the operator "this endpoint works" without spending
|
|
7
|
+
* a real chat turn to find out. Ported from OD's `apps/daemon/src/connectionTest.ts`
|
|
8
|
+
* (`testProviderConnection` + `buildProviderCall` + `inspectProviderCompletion`),
|
|
9
|
+
* narrowed to the four protocols `@jini-ai/ui`'s execution-tab canary exposes
|
|
10
|
+
* (`anthropic` / `openai` / `azure` / `google`) — the origin also covers
|
|
11
|
+
* `ollama` / `senseaudio` / `aihubmix` / `bedrock`, which stay out of scope
|
|
12
|
+
* here the same way `model-catalog.ts` keeps Bedrock to a static seed and
|
|
13
|
+
* Azure to an explicit "unsupported" response for model discovery.
|
|
14
|
+
*
|
|
15
|
+
* Shares this package's own vendored SSRF guard / secret redaction
|
|
16
|
+
* (`connection-guard.ts`) and vendored connectivity types (`types.ts`) —
|
|
17
|
+
* no OD workspace-package imports, matching every other file in this
|
|
18
|
+
* directory.
|
|
19
|
+
*/
|
|
20
|
+
import { defaultDnsLookup, redactSecrets, validateBaseUrlResolved } from './connection-guard.js';
|
|
21
|
+
import { googleGenerateContentUrl } from './google.js';
|
|
22
|
+
import { buildOpenAIChatTokenParam, buildLegacyMaxTokensParam, buildMaxCompletionTokensParam } from './token-params.js';
|
|
23
|
+
const SMOKE_PROMPT = 'Reply with only: ok';
|
|
24
|
+
/**
|
|
25
|
+
* Headroom for a reasoning model's hidden thinking, plus the two-character answer.
|
|
26
|
+
*
|
|
27
|
+
* Was 64, chosen with the right instinct ("a reasoning model can spend the first few dozen tokens
|
|
28
|
+
* on hidden reasoning") and the wrong number. On Gemini 2.5 models thinking tokens are billed
|
|
29
|
+
* against `maxOutputTokens`, and their dynamic thinking budget routinely exceeds 64 on its own — so
|
|
30
|
+
* the model spends the entire allowance thinking, stops at `finishReason: MAX_TOKENS`, and returns
|
|
31
|
+
* a 2xx candidate with NO `content.parts` at all. The operator sees "Provider returned a 2xx
|
|
32
|
+
* response without assistant text" against a key that provably works, which reads as a broken key.
|
|
33
|
+
*
|
|
34
|
+
* 512 rather than a thinking-disabling flag (`generationConfig.thinkingConfig.thinkingBudget: 0`)
|
|
35
|
+
* because that field is Gemini-2.5-only and the Gemini API rejects unknown `generationConfig`
|
|
36
|
+
* members outright — it would fix current models by breaking older ones. A larger ceiling is
|
|
37
|
+
* provider-agnostic, and it is a ceiling, not a spend: a model that answers "ok" in two tokens
|
|
38
|
+
* still costs two tokens.
|
|
39
|
+
*/
|
|
40
|
+
const CONNECTION_TEST_MAX_TOKENS = 512;
|
|
41
|
+
const CONNECTION_TEST_TIMEOUT_MS = 12_000;
|
|
42
|
+
const SAMPLE_MAX_CHARS = 120;
|
|
43
|
+
function isSupportedProtocol(protocol) {
|
|
44
|
+
return protocol === 'anthropic' || protocol === 'openai' || protocol === 'azure' || protocol === 'google';
|
|
45
|
+
}
|
|
46
|
+
function appendVersionedApiPath(baseUrl, suffix) {
|
|
47
|
+
const url = new URL(baseUrl);
|
|
48
|
+
const pathname = url.pathname.replace(/\/+$/, '');
|
|
49
|
+
url.pathname = /\/v\d+(\/|$)/.test(pathname) ? `${pathname}${suffix}` : `${pathname}/v1${suffix}`;
|
|
50
|
+
return url.toString();
|
|
51
|
+
}
|
|
52
|
+
function truncateSample(text) {
|
|
53
|
+
if (typeof text !== 'string')
|
|
54
|
+
return '';
|
|
55
|
+
const trimmed = text.replace(/\s+/g, ' ').trim();
|
|
56
|
+
if (trimmed.length <= SAMPLE_MAX_CHARS)
|
|
57
|
+
return trimmed;
|
|
58
|
+
return `${trimmed.slice(0, SAMPLE_MAX_CHARS - 1)}…`;
|
|
59
|
+
}
|
|
60
|
+
function isSmokeOkReply(text) {
|
|
61
|
+
return typeof text === 'string' && text.trim().toLowerCase() === 'ok';
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The provider's own reason for stopping, when a 2xx carried no usable text.
|
|
65
|
+
*
|
|
66
|
+
* Exists because "Provider returned a 2xx response without assistant text" is a true statement that
|
|
67
|
+
* tells the operator nothing they can act on — it names the symptom and hides the cause. Every
|
|
68
|
+
* supported protocol reports a stop reason under a different key, and the useful ones
|
|
69
|
+
* (`MAX_TOKENS`, `content_filter`, `safety`) each imply a different fix.
|
|
70
|
+
*
|
|
71
|
+
* Read defensively: any of these may be absent, and a missing reason must degrade to the old
|
|
72
|
+
* message rather than to `"undefined"`.
|
|
73
|
+
*/
|
|
74
|
+
function extractFinishReason(data) {
|
|
75
|
+
const root = data;
|
|
76
|
+
const raw = root?.candidates?.[0]?.finishReason ?? root?.choices?.[0]?.finish_reason ?? root?.stop_reason;
|
|
77
|
+
return typeof raw === 'string' && raw.trim() ? raw.trim() : '';
|
|
78
|
+
}
|
|
79
|
+
function isLikelyAuthErrorText(text) {
|
|
80
|
+
return /(?:api[_ -]?key|x-goog-api-key|unauthorized|unauthenticated|permission denied|invalid credentials|authentication credentials|access denied|invalid key)/i.test(text);
|
|
81
|
+
}
|
|
82
|
+
function isLikelyModelErrorText(text) {
|
|
83
|
+
return (/model/i.test(text) &&
|
|
84
|
+
/(not found|not exist|does not exist|unknown|invalid|unsupported|not supported|not have access|no access)/i.test(text));
|
|
85
|
+
}
|
|
86
|
+
function statusToKind(status, detailText = '') {
|
|
87
|
+
if (status === 401 || (status === 400 && isLikelyAuthErrorText(detailText)))
|
|
88
|
+
return 'auth_failed';
|
|
89
|
+
if (status === 403)
|
|
90
|
+
return isLikelyAuthErrorText(detailText) ? 'auth_failed' : 'forbidden';
|
|
91
|
+
if (status === 404)
|
|
92
|
+
return isLikelyModelErrorText(detailText) ? 'not_found_model' : 'invalid_base_url';
|
|
93
|
+
if (status === 429)
|
|
94
|
+
return 'rate_limited';
|
|
95
|
+
if (status >= 500)
|
|
96
|
+
return 'upstream_unavailable';
|
|
97
|
+
return 'unknown';
|
|
98
|
+
}
|
|
99
|
+
function networkErrorToKind(err) {
|
|
100
|
+
if (err instanceof Error) {
|
|
101
|
+
if (err.name === 'AbortError')
|
|
102
|
+
return 'timeout';
|
|
103
|
+
const cause = err.cause;
|
|
104
|
+
const code = cause?.code;
|
|
105
|
+
if (code === 'ENOTFOUND' ||
|
|
106
|
+
code === 'EAI_AGAIN' ||
|
|
107
|
+
code === 'ECONNREFUSED' ||
|
|
108
|
+
code === 'ECONNRESET' ||
|
|
109
|
+
code === 'ETIMEDOUT' ||
|
|
110
|
+
code === 'EHOSTUNREACH' ||
|
|
111
|
+
code === 'ENETUNREACH' ||
|
|
112
|
+
code === 'CERT_HAS_EXPIRED' ||
|
|
113
|
+
code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
|
|
114
|
+
return 'invalid_base_url';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return 'unknown';
|
|
118
|
+
}
|
|
119
|
+
function extractProviderErrorDetail(data, rawText) {
|
|
120
|
+
const obj = data && typeof data === 'object' ? data : null;
|
|
121
|
+
const error = obj ? obj.error : null;
|
|
122
|
+
if (typeof error === 'string')
|
|
123
|
+
return error;
|
|
124
|
+
if (error && typeof error === 'object') {
|
|
125
|
+
const message = error.message;
|
|
126
|
+
if (typeof message === 'string' && message.trim())
|
|
127
|
+
return message;
|
|
128
|
+
}
|
|
129
|
+
const message = obj ? obj.message : null;
|
|
130
|
+
if (typeof message === 'string' && message.trim())
|
|
131
|
+
return message;
|
|
132
|
+
return rawText.trim().slice(0, 240);
|
|
133
|
+
}
|
|
134
|
+
function extractOpenAIMessageText(data) {
|
|
135
|
+
const choices = data.choices;
|
|
136
|
+
if (!Array.isArray(choices) || choices.length === 0)
|
|
137
|
+
return '';
|
|
138
|
+
const first = choices[0];
|
|
139
|
+
if (typeof first?.message?.content === 'string')
|
|
140
|
+
return first.message.content;
|
|
141
|
+
if (typeof first?.text === 'string')
|
|
142
|
+
return first.text;
|
|
143
|
+
return '';
|
|
144
|
+
}
|
|
145
|
+
function buildProviderCall(input) {
|
|
146
|
+
const baseUrl = input.baseUrl;
|
|
147
|
+
const apiKey = input.apiKey;
|
|
148
|
+
const model = input.model;
|
|
149
|
+
switch (input.protocol) {
|
|
150
|
+
case 'anthropic':
|
|
151
|
+
return {
|
|
152
|
+
url: appendVersionedApiPath(baseUrl, '/messages'),
|
|
153
|
+
headers: {
|
|
154
|
+
'content-type': 'application/json',
|
|
155
|
+
'x-api-key': apiKey,
|
|
156
|
+
'anthropic-version': '2023-06-01',
|
|
157
|
+
},
|
|
158
|
+
body: {
|
|
159
|
+
model,
|
|
160
|
+
max_tokens: CONNECTION_TEST_MAX_TOKENS,
|
|
161
|
+
messages: [{ role: 'user', content: SMOKE_PROMPT }],
|
|
162
|
+
stream: false,
|
|
163
|
+
},
|
|
164
|
+
extractText: (data) => {
|
|
165
|
+
const blocks = data.content;
|
|
166
|
+
if (!Array.isArray(blocks))
|
|
167
|
+
return '';
|
|
168
|
+
for (const block of blocks) {
|
|
169
|
+
if (block &&
|
|
170
|
+
typeof block === 'object' &&
|
|
171
|
+
block.type === 'text' &&
|
|
172
|
+
typeof block.text === 'string') {
|
|
173
|
+
return block.text;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return '';
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
case 'openai':
|
|
180
|
+
return {
|
|
181
|
+
url: appendVersionedApiPath(baseUrl, '/chat/completions'),
|
|
182
|
+
headers: {
|
|
183
|
+
'content-type': 'application/json',
|
|
184
|
+
authorization: `Bearer ${apiKey}`,
|
|
185
|
+
},
|
|
186
|
+
body: {
|
|
187
|
+
model,
|
|
188
|
+
...buildOpenAIChatTokenParam(model, CONNECTION_TEST_MAX_TOKENS),
|
|
189
|
+
messages: [{ role: 'user', content: SMOKE_PROMPT }],
|
|
190
|
+
stream: false,
|
|
191
|
+
},
|
|
192
|
+
extractText: extractOpenAIMessageText,
|
|
193
|
+
};
|
|
194
|
+
case 'azure': {
|
|
195
|
+
const url = new URL(baseUrl);
|
|
196
|
+
const basePath = url.pathname.replace(/\/+$/, '');
|
|
197
|
+
const usesVersionedOpenAIPath = /\/openai\/v\d+(?:$|\/)/.test(basePath);
|
|
198
|
+
const apiVersion = input.apiVersion?.trim() || (usesVersionedOpenAIPath ? '' : '2024-10-21');
|
|
199
|
+
url.pathname = usesVersionedOpenAIPath
|
|
200
|
+
? `${basePath}/chat/completions`
|
|
201
|
+
: `${basePath}/openai/deployments/${encodeURIComponent(model)}/chat/completions`;
|
|
202
|
+
if (apiVersion)
|
|
203
|
+
url.searchParams.set('api-version', apiVersion);
|
|
204
|
+
return {
|
|
205
|
+
url: url.toString(),
|
|
206
|
+
headers: { 'content-type': 'application/json', 'api-key': apiKey },
|
|
207
|
+
body: {
|
|
208
|
+
...(usesVersionedOpenAIPath ? { model } : {}),
|
|
209
|
+
...buildLegacyMaxTokensParam(CONNECTION_TEST_MAX_TOKENS),
|
|
210
|
+
messages: [{ role: 'user', content: SMOKE_PROMPT }],
|
|
211
|
+
stream: false,
|
|
212
|
+
},
|
|
213
|
+
extractText: extractOpenAIMessageText,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
case 'google': {
|
|
217
|
+
const effectiveBaseUrl = baseUrl.trim() || 'https://generativelanguage.googleapis.com';
|
|
218
|
+
return {
|
|
219
|
+
url: googleGenerateContentUrl(effectiveBaseUrl, model),
|
|
220
|
+
headers: { 'content-type': 'application/json', 'x-goog-api-key': apiKey },
|
|
221
|
+
body: {
|
|
222
|
+
contents: [{ role: 'user', parts: [{ text: SMOKE_PROMPT }] }],
|
|
223
|
+
generationConfig: { maxOutputTokens: CONNECTION_TEST_MAX_TOKENS },
|
|
224
|
+
},
|
|
225
|
+
extractText: (data) => {
|
|
226
|
+
const candidates = data.candidates;
|
|
227
|
+
if (!Array.isArray(candidates) || candidates.length === 0)
|
|
228
|
+
return '';
|
|
229
|
+
const parts = candidates[0].content?.parts;
|
|
230
|
+
if (!Array.isArray(parts))
|
|
231
|
+
return '';
|
|
232
|
+
return parts
|
|
233
|
+
// Gemini 2.5 returns its hidden reasoning as ordinary parts flagged `thought: true`,
|
|
234
|
+
// interleaved with the real answer. Joining them all turns a correct "ok" into
|
|
235
|
+
// "<paragraph of reasoning>ok", which `isSmokeOkReply`'s exact match then rejects — a
|
|
236
|
+
// model that answered correctly reported as a failed connection. Only the answer counts.
|
|
237
|
+
.filter((p) => p?.thought !== true)
|
|
238
|
+
.map((p) => (typeof p?.text === 'string' ? p.text : ''))
|
|
239
|
+
.join('');
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// `buildLegacyMaxTokensParam`/`buildMaxCompletionTokensParam` cover the Azure
|
|
246
|
+
// legacy-vs-`max_completion_tokens` split the same way OD's daemon retries a
|
|
247
|
+
// rejected `max_tokens` param; this smoke test keeps the simpler single-shot
|
|
248
|
+
// legacy param (a connection test failing on a param-name mismatch on a
|
|
249
|
+
// reasoning-tier Azure deployment is a known, narrow gap — see this
|
|
250
|
+
// package's `source-map.md`) rather than porting OD's full retry-on-400 loop.
|
|
251
|
+
void buildMaxCompletionTokensParam;
|
|
252
|
+
/**
|
|
253
|
+
* Probes a BYOK provider endpoint with the supplied credentials by sending a
|
|
254
|
+
* tiny smoke-test completion request, and classifies the result. Validates
|
|
255
|
+
* the base URL (sync + DNS-resolved SSRF guard) before issuing any request,
|
|
256
|
+
* exactly like {@link import('./model-catalog.js').listProviderModels}.
|
|
257
|
+
*
|
|
258
|
+
* Never throws for provider-side or network failures — every failure path
|
|
259
|
+
* resolves to `{ ok: false, kind, detail }`. Only truly unsupported
|
|
260
|
+
* protocols short-circuit before any network access.
|
|
261
|
+
*
|
|
262
|
+
* @complexity O(1) — one bounded-size HTTP request with a hard timeout.
|
|
263
|
+
* @overallScore 100
|
|
264
|
+
*/
|
|
265
|
+
export async function testProviderConnection(input) {
|
|
266
|
+
const start = Date.now();
|
|
267
|
+
const model = input.model.trim();
|
|
268
|
+
if (!isSupportedProtocol(input.protocol)) {
|
|
269
|
+
return {
|
|
270
|
+
ok: false,
|
|
271
|
+
kind: 'unknown',
|
|
272
|
+
latencyMs: Date.now() - start,
|
|
273
|
+
model,
|
|
274
|
+
detail: `Connection test is not supported for protocol "${input.protocol}".`,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
// Every supported protocol here (anthropic/openai/azure/google) puts the
|
|
278
|
+
// key straight into the outbound request (`buildProviderCall` below), so
|
|
279
|
+
// an empty key is never a legitimate probe — the provider would reject it
|
|
280
|
+
// with a generic "no credential" error indistinguishable from a broken
|
|
281
|
+
// integration. Same fail-fast rationale as `listProviderModels`'s
|
|
282
|
+
// `PROTOCOLS_REQUIRING_API_KEY` guard, checked first so a missing key
|
|
283
|
+
// short-circuits before any DNS/network access.
|
|
284
|
+
if (!input.apiKey.trim()) {
|
|
285
|
+
return {
|
|
286
|
+
ok: false,
|
|
287
|
+
kind: 'auth_failed',
|
|
288
|
+
latencyMs: Date.now() - start,
|
|
289
|
+
model,
|
|
290
|
+
detail: 'No API key — connection test needs the key from this browser.',
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
const validated = await validateBaseUrlResolved(input.baseUrl, input.dnsLookup ?? defaultDnsLookup);
|
|
294
|
+
if (validated.error || !validated.parsed) {
|
|
295
|
+
return {
|
|
296
|
+
ok: false,
|
|
297
|
+
kind: validated.forbidden ? 'forbidden' : 'invalid_base_url',
|
|
298
|
+
latencyMs: Date.now() - start,
|
|
299
|
+
model,
|
|
300
|
+
detail: validated.error ?? '',
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
let call;
|
|
304
|
+
try {
|
|
305
|
+
call = buildProviderCall({ ...input, protocol: input.protocol, model });
|
|
306
|
+
}
|
|
307
|
+
catch (err) {
|
|
308
|
+
return {
|
|
309
|
+
ok: false,
|
|
310
|
+
kind: 'unknown',
|
|
311
|
+
latencyMs: Date.now() - start,
|
|
312
|
+
model,
|
|
313
|
+
detail: redactSecrets(err instanceof Error ? err.message : String(err), [input.apiKey]),
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const controller = new AbortController();
|
|
317
|
+
const abortFromParent = () => controller.abort();
|
|
318
|
+
if (input.signal?.aborted) {
|
|
319
|
+
controller.abort();
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
input.signal?.addEventListener('abort', abortFromParent, { once: true });
|
|
323
|
+
}
|
|
324
|
+
const timer = setTimeout(() => controller.abort(), CONNECTION_TEST_TIMEOUT_MS);
|
|
325
|
+
let result;
|
|
326
|
+
try {
|
|
327
|
+
const response = await fetch(call.url, {
|
|
328
|
+
...input.requestInit,
|
|
329
|
+
method: 'POST',
|
|
330
|
+
headers: call.headers,
|
|
331
|
+
body: JSON.stringify(call.body),
|
|
332
|
+
signal: controller.signal,
|
|
333
|
+
});
|
|
334
|
+
const latencyMs = Date.now() - start;
|
|
335
|
+
const rawText = await response.text().catch(() => '');
|
|
336
|
+
let data = {};
|
|
337
|
+
try {
|
|
338
|
+
data = rawText ? JSON.parse(rawText) : {};
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
// Non-JSON body — fall through to the not-`response.ok` / smoke-reply
|
|
342
|
+
// paths below, both of which treat an empty `data` as "no usable text".
|
|
343
|
+
}
|
|
344
|
+
if (!response.ok) {
|
|
345
|
+
const redactedDetail = redactSecrets(extractProviderErrorDetail(data, rawText).slice(0, 240), [input.apiKey]);
|
|
346
|
+
result = {
|
|
347
|
+
ok: false,
|
|
348
|
+
kind: statusToKind(response.status, redactedDetail),
|
|
349
|
+
latencyMs,
|
|
350
|
+
model,
|
|
351
|
+
status: response.status,
|
|
352
|
+
detail: redactedDetail || (response.status === 404 ? 'HTTP 404 from provider; check the Base URL path.' : ''),
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
const text = call.extractText(data);
|
|
357
|
+
if (isSmokeOkReply(text)) {
|
|
358
|
+
result = { ok: true, kind: 'success', latencyMs, model, status: response.status, detail: 'valid completion' };
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
// Redacted for exactly the reason the `!response.ok` branch above
|
|
362
|
+
// redacts. The transport succeeded here (HTTP 2xx) but the smoke reply
|
|
363
|
+
// did not match, so this is still a failure path echoing arbitrary
|
|
364
|
+
// provider text straight back into the admin UI — and a misbehaving or
|
|
365
|
+
// hostile endpoint that reflects the request's own `Authorization`
|
|
366
|
+
// header puts the operator's key in `detail` verbatim. Two independent
|
|
367
|
+
// audits reproduced that, each from a different call boundary; the
|
|
368
|
+
// redaction was simply missing on this one branch.
|
|
369
|
+
const sample = truncateSample(redactSecrets(text, [input.apiKey]));
|
|
370
|
+
// Naming the stop reason turns an unactionable "it returned nothing" into a diagnosis:
|
|
371
|
+
// `MAX_TOKENS` means the smoke budget was too small (usually a thinking model), a safety or
|
|
372
|
+
// content-filter reason means the probe was blocked, not that the endpoint is broken.
|
|
373
|
+
const finishReason = extractFinishReason(data);
|
|
374
|
+
result = {
|
|
375
|
+
ok: false,
|
|
376
|
+
kind: 'unknown',
|
|
377
|
+
latencyMs,
|
|
378
|
+
model,
|
|
379
|
+
status: response.status,
|
|
380
|
+
detail: sample
|
|
381
|
+
? `Expected smoke test reply "ok"; got "${sample}"`
|
|
382
|
+
: finishReason
|
|
383
|
+
? `Provider returned a 2xx response without assistant text (finish reason: ${finishReason})`
|
|
384
|
+
: 'Provider returned a 2xx response without assistant text',
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
catch (err) {
|
|
390
|
+
result = {
|
|
391
|
+
ok: false,
|
|
392
|
+
kind: networkErrorToKind(err),
|
|
393
|
+
latencyMs: Date.now() - start,
|
|
394
|
+
model,
|
|
395
|
+
detail: redactSecrets(err instanceof Error ? err.message : String(err), [input.apiKey]),
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
finally {
|
|
399
|
+
clearTimeout(timer);
|
|
400
|
+
input.signal?.removeEventListener('abort', abortFromParent);
|
|
401
|
+
}
|
|
402
|
+
return result;
|
|
403
|
+
}
|
|
404
|
+
//# sourceMappingURL=connection-test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-test.js","sourceRoot":"","sources":["../../src/providers/connection-test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elevenlabs.d.ts","sourceRoot":"","sources":["../../src/providers/elevenlabs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"elevenlabs.d.ts","sourceRoot":"","sources":["../../src/providers/elevenlabs.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,2FAA2F;AAC3F,MAAM,MAAM,4BAA4B,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAEpG,4EAA4E;AAC5E,qBAAa,gCAAiC,SAAQ,KAAK;;CAK1D;AA+ED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAC9C,YAAY,EAAE,MAAM,EACpB,kBAAkB,EAAE,4BAA4B,EAChD,OAAO,GAAE;IACP,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;CAC1C,GACL,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAoDlC"}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* ElevenLabs wire API once it has a key.
|
|
17
17
|
*/
|
|
18
18
|
import { createHash } from 'node:crypto';
|
|
19
|
+
import { FETCH_TIMEOUT_MS, fetchWithTimeout } from '@jini-ai/platform';
|
|
19
20
|
const ELEVENLABS_DEFAULT_BASE_URL = 'https://api.elevenlabs.io';
|
|
20
21
|
const ELEVENLABS_DEFAULT_VOICE_LIMIT = 100;
|
|
21
22
|
const ELEVENLABS_MAX_VOICE_LIMIT = 100;
|
|
@@ -110,14 +111,14 @@ export async function listElevenLabsVoiceOptions(workspaceKey, resolveCredential
|
|
|
110
111
|
if (cached && cached.expiresAt > now) {
|
|
111
112
|
return cloneVoiceOptions(cached.voices);
|
|
112
113
|
}
|
|
113
|
-
const resp = await
|
|
114
|
+
const resp = await fetchWithTimeout(`${baseUrl}/v2/voices?page_size=${pageSize}`, {
|
|
114
115
|
...options.requestInit,
|
|
115
116
|
method: 'GET',
|
|
116
117
|
headers: {
|
|
117
118
|
'xi-api-key': credentials.apiKey,
|
|
118
119
|
accept: 'application/json',
|
|
119
120
|
},
|
|
120
|
-
});
|
|
121
|
+
}, { timeoutMs: FETCH_TIMEOUT_MS.QUICK });
|
|
121
122
|
if (!resp.ok) {
|
|
122
123
|
const errText = await resp.text();
|
|
123
124
|
throw new Error(`elevenlabs voices ${resp.status}: ${errText.slice(0, 240)}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elevenlabs.js","sourceRoot":"","sources":["../../src/providers/elevenlabs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"elevenlabs.js","sourceRoot":"","sources":["../../src/providers/elevenlabs.ts"],"names":[],"mappings":"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"}
|