pi2dsh 0.3.0 → 0.3.2
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 +31 -11
- package/README.zh.md +31 -11
- package/dist/all-Rt4K68QA.mjs +28512 -0
- package/dist/all-Rt4K68QA.mjs.map +1 -0
- package/dist/anthropic-messages-Beym0_aC.mjs +6438 -0
- package/dist/anthropic-messages-Beym0_aC.mjs.map +1 -0
- package/dist/azure-openai-responses-cHqZTgLD.mjs +209 -0
- package/dist/azure-openai-responses-cHqZTgLD.mjs.map +1 -0
- package/dist/{build-DsGYAgiT.mjs → build-BG7p2Lbr.mjs} +2 -2
- package/dist/{build-DsGYAgiT.mjs.map → build-BG7p2Lbr.mjs.map} +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/compat/pi-ai.d.mts +25 -3
- package/dist/compat/pi-ai.d.mts.map +1 -1
- package/dist/compat/pi-ai.mjs +3 -2919
- package/dist/compat/pi-coding-agent.d.mts +12 -1
- package/dist/compat/pi-coding-agent.d.mts.map +1 -1
- package/dist/compat/pi-coding-agent.mjs +2 -2
- package/dist/credentials-oauth.d.mts +27 -0
- package/dist/credentials-oauth.d.mts.map +1 -0
- package/dist/credentials-oauth.mjs +91 -0
- package/dist/credentials-oauth.mjs.map +1 -0
- package/dist/deferred-tools-BD4g5QUx.mjs +32 -0
- package/dist/deferred-tools-BD4g5QUx.mjs.map +1 -0
- package/dist/diagnostics-CJye1UFh.mjs +99 -0
- package/dist/diagnostics-CJye1UFh.mjs.map +1 -0
- package/dist/dist-IQKOgQyt.mjs +10035 -0
- package/dist/dist-IQKOgQyt.mjs.map +1 -0
- package/dist/dist-QBBA-dL_.mjs +1246 -0
- package/dist/dist-QBBA-dL_.mjs.map +1 -0
- package/dist/error-body-DKA3lknR.mjs +104 -0
- package/dist/error-body-DKA3lknR.mjs.map +1 -0
- package/dist/github-copilot-headers-CZo2QHrt.mjs +25 -0
- package/dist/github-copilot-headers-CZo2QHrt.mjs.map +1 -0
- package/dist/google-generative-ai-B7OZs5lu.mjs +358 -0
- package/dist/google-generative-ai-B7OZs5lu.mjs.map +1 -0
- package/dist/google-shared-CRsAUItF.mjs +29042 -0
- package/dist/google-shared-CRsAUItF.mjs.map +1 -0
- package/dist/google-vertex-DmdaHQtB.mjs +402 -0
- package/dist/google-vertex-DmdaHQtB.mjs.map +1 -0
- package/dist/hash-Dbggamac.mjs +19 -0
- package/dist/hash-Dbggamac.mjs.map +1 -0
- package/dist/headers-CPzZhJQn.mjs +17 -0
- package/dist/headers-CPzZhJQn.mjs.map +1 -0
- package/dist/host.d.mts.map +1 -1
- package/dist/host.mjs +15 -3
- package/dist/host.mjs.map +1 -1
- package/dist/images-models-DJtHo9Rp.mjs +1068 -0
- package/dist/images-models-DJtHo9Rp.mjs.map +1 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/json-parse-CFyFZSLJ.mjs +384 -0
- package/dist/json-parse-CFyFZSLJ.mjs.map +1 -0
- package/dist/{mcp-config-gqg7GJEE.mjs → mcp-config-D2B3kv-Z.mjs} +34 -16
- package/dist/mcp-config-D2B3kv-Z.mjs.map +1 -0
- package/dist/mistral-conversations-HHZCcFv_.mjs +42007 -0
- package/dist/mistral-conversations-HHZCcFv_.mjs.map +1 -0
- package/dist/multipart-parser-CIa5BbwO.mjs +301 -0
- package/dist/multipart-parser-CIa5BbwO.mjs.map +1 -0
- package/dist/oauth-bridge-C6fL1qSv.mjs +375 -0
- package/dist/oauth-bridge-C6fL1qSv.mjs.map +1 -0
- package/dist/openai-DkzRh5_G.mjs +6732 -0
- package/dist/openai-DkzRh5_G.mjs.map +1 -0
- package/dist/openai-codex-responses-vmovNu-q.mjs +1169 -0
- package/dist/openai-codex-responses-vmovNu-q.mjs.map +1 -0
- package/dist/openai-completions-fXHhRolF.mjs +947 -0
- package/dist/openai-completions-fXHhRolF.mjs.map +1 -0
- package/dist/openai-prompt-cache-BDWtZRKh.mjs +11 -0
- package/dist/openai-prompt-cache-BDWtZRKh.mjs.map +1 -0
- package/dist/openai-responses-DKdCYf3h.mjs +247 -0
- package/dist/openai-responses-DKdCYf3h.mjs.map +1 -0
- package/dist/openai-responses-shared-D0Jq7yVP.mjs +572 -0
- package/dist/openai-responses-shared-D0Jq7yVP.mjs.map +1 -0
- package/dist/openrouter-images-fG3Aj6M4.mjs +127 -0
- package/dist/openrouter-images-fG3Aj6M4.mjs.map +1 -0
- package/dist/otel-BQSQRBLF.mjs +24935 -0
- package/dist/otel-BQSQRBLF.mjs.map +1 -0
- package/dist/pi-ai-DhYGgq4Y.mjs +2984 -0
- package/dist/pi-ai-DhYGgq4Y.mjs.map +1 -0
- package/dist/{pi-coding-agent-Z1hTs61i.mjs → pi-coding-agent-fPHwKP4d.mjs} +27 -3
- package/dist/{pi-coding-agent-Z1hTs61i.mjs.map → pi-coding-agent-fPHwKP4d.mjs.map} +1 -1
- package/dist/pi-messages-CV-Ts8An.mjs +306 -0
- package/dist/pi-messages-CV-Ts8An.mjs.map +1 -0
- package/dist/provider-env-C72pF4vP.mjs +40 -0
- package/dist/provider-env-C72pF4vP.mjs.map +1 -0
- package/dist/provider-retry-Cw6YJ4cr.mjs +80 -0
- package/dist/provider-retry-Cw6YJ4cr.mjs.map +1 -0
- package/dist/rolldown-runtime-CTfmNlz1.mjs +44 -0
- package/dist/{runtime-oLd2EInK.mjs → runtime-B9R7bDWT.mjs} +838 -345
- package/dist/runtime-B9R7bDWT.mjs.map +1 -0
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/sanitize-unicode-wLA11KvZ.mjs +29 -0
- package/dist/sanitize-unicode-wLA11KvZ.mjs.map +1 -0
- package/dist/src-C3WBfOks.mjs +5031 -0
- package/dist/src-C3WBfOks.mjs.map +1 -0
- package/dist/transform-messages-DGq9mvhA.mjs +379 -0
- package/dist/transform-messages-DGq9mvhA.mjs.map +1 -0
- package/dist/uuid-DtFT7tOE.mjs +65 -0
- package/dist/uuid-DtFT7tOE.mjs.map +1 -0
- package/package.json +11 -1
- package/dist/compat/pi-ai.mjs.map +0 -1
- package/dist/mcp-config-gqg7GJEE.mjs.map +0 -1
- package/dist/rolldown-runtime-D-uZhY3_.mjs +0 -16
- package/dist/runtime-oLd2EInK.mjs.map +0 -1
|
@@ -0,0 +1,1068 @@
|
|
|
1
|
+
|
|
2
|
+
import { a as AssistantMessageEventStream, i as formatThrownValue } from "./diagnostics-CJye1UFh.mjs";
|
|
3
|
+
//#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/api/lazy.js
|
|
4
|
+
function createSetupErrorMessage(model, error) {
|
|
5
|
+
return {
|
|
6
|
+
role: "assistant",
|
|
7
|
+
content: [],
|
|
8
|
+
api: model.api,
|
|
9
|
+
provider: model.provider,
|
|
10
|
+
model: model.id,
|
|
11
|
+
usage: {
|
|
12
|
+
input: 0,
|
|
13
|
+
output: 0,
|
|
14
|
+
cacheRead: 0,
|
|
15
|
+
cacheWrite: 0,
|
|
16
|
+
totalTokens: 0,
|
|
17
|
+
cost: {
|
|
18
|
+
input: 0,
|
|
19
|
+
output: 0,
|
|
20
|
+
cacheRead: 0,
|
|
21
|
+
cacheWrite: 0,
|
|
22
|
+
total: 0
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
stopReason: "error",
|
|
26
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
27
|
+
timestamp: Date.now()
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function hasResult(source) {
|
|
31
|
+
return typeof source.result === "function";
|
|
32
|
+
}
|
|
33
|
+
async function forwardStream(target, source) {
|
|
34
|
+
for await (const event of source) target.push(event);
|
|
35
|
+
target.end(hasResult(source) ? await source.result() : void 0);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns a stream synchronously while running async setup (auth resolution,
|
|
39
|
+
* lazy module loading) behind it. Setup failures terminate the stream with an
|
|
40
|
+
* error event.
|
|
41
|
+
*/
|
|
42
|
+
function lazyStream(model, setup) {
|
|
43
|
+
const outer = new AssistantMessageEventStream();
|
|
44
|
+
setup().then((inner) => forwardStream(outer, inner)).catch((error) => {
|
|
45
|
+
const message = createSetupErrorMessage(model, error);
|
|
46
|
+
outer.push({
|
|
47
|
+
type: "error",
|
|
48
|
+
reason: "error",
|
|
49
|
+
error: message
|
|
50
|
+
});
|
|
51
|
+
outer.end(message);
|
|
52
|
+
});
|
|
53
|
+
return outer;
|
|
54
|
+
}
|
|
55
|
+
function lazyApi(load, capabilities) {
|
|
56
|
+
const api = {
|
|
57
|
+
stream: (model, context, options) => lazyStream(model, async () => (await load()).stream(model, context, options)),
|
|
58
|
+
streamSimple: (model, context, options) => lazyStream(model, async () => (await load()).streamSimple(model, context, options))
|
|
59
|
+
};
|
|
60
|
+
if (capabilities?.fetchDeferred) api.fetchDeferred = (model, handle, options) => lazyStream(model, async () => {
|
|
61
|
+
const implementation = await load();
|
|
62
|
+
if (!implementation.fetchDeferred) throw new Error("API does not support deferred responses");
|
|
63
|
+
return implementation.fetchDeferred(model, handle, options);
|
|
64
|
+
});
|
|
65
|
+
if (capabilities?.cancelDeferred) api.cancelDeferred = async (model, handle, options) => {
|
|
66
|
+
const implementation = await load();
|
|
67
|
+
if (!implementation.cancelDeferred) throw new Error("API cannot cancel deferred responses");
|
|
68
|
+
await implementation.cancelDeferred(model, handle, options);
|
|
69
|
+
};
|
|
70
|
+
return api;
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/auth/context.js
|
|
74
|
+
var __rewriteRelativeImportExtension = function(path, preserveJsx) {
|
|
75
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
|
|
76
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
|
|
77
|
+
});
|
|
78
|
+
return path;
|
|
79
|
+
};
|
|
80
|
+
const importNodeModule = (specifier) => import(__rewriteRelativeImportExtension(specifier));
|
|
81
|
+
function getProcessEnv() {
|
|
82
|
+
return globalThis.process?.env;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Default auth context: env vars from `process.env` (undefined in browsers),
|
|
86
|
+
* file existence via node:fs (always false in browsers).
|
|
87
|
+
*/
|
|
88
|
+
function defaultProviderAuthContext() {
|
|
89
|
+
return {
|
|
90
|
+
async env(name) {
|
|
91
|
+
const value = getProcessEnv()?.[name];
|
|
92
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
93
|
+
},
|
|
94
|
+
async fileExists(path) {
|
|
95
|
+
try {
|
|
96
|
+
const fs = await importNodeModule("node:fs/promises");
|
|
97
|
+
let resolved = path;
|
|
98
|
+
if (resolved.startsWith("~")) resolved = (await importNodeModule("node:os")).homedir() + resolved.slice(1);
|
|
99
|
+
await fs.access(resolved);
|
|
100
|
+
return true;
|
|
101
|
+
} catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/utils/abort.js
|
|
109
|
+
function abortReason(signal) {
|
|
110
|
+
if (signal.reason !== void 0) return signal.reason;
|
|
111
|
+
const error = /* @__PURE__ */ new Error("The operation was aborted");
|
|
112
|
+
error.name = "AbortError";
|
|
113
|
+
return error;
|
|
114
|
+
}
|
|
115
|
+
/** Create an operation-local signal for public APIs whose signal is optional. */
|
|
116
|
+
function operationSignal(signal) {
|
|
117
|
+
return signal ?? new AbortController().signal;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Stop waiting for an operation when its signal aborts while continuing to
|
|
121
|
+
* observe the abandoned promise so a later rejection is always handled.
|
|
122
|
+
*/
|
|
123
|
+
function raceWithAbortSignal(operation, signal) {
|
|
124
|
+
if (signal.aborted) {
|
|
125
|
+
operation.catch(() => {});
|
|
126
|
+
return Promise.reject(abortReason(signal));
|
|
127
|
+
}
|
|
128
|
+
return new Promise((resolve, reject) => {
|
|
129
|
+
let settled = false;
|
|
130
|
+
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
131
|
+
const onAbort = () => {
|
|
132
|
+
if (settled) return;
|
|
133
|
+
settled = true;
|
|
134
|
+
cleanup();
|
|
135
|
+
reject(abortReason(signal));
|
|
136
|
+
};
|
|
137
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
138
|
+
operation.then((value) => {
|
|
139
|
+
if (settled) return;
|
|
140
|
+
settled = true;
|
|
141
|
+
cleanup();
|
|
142
|
+
resolve(value);
|
|
143
|
+
}, (error) => {
|
|
144
|
+
if (settled) return;
|
|
145
|
+
settled = true;
|
|
146
|
+
cleanup();
|
|
147
|
+
reject(error);
|
|
148
|
+
});
|
|
149
|
+
if (signal.aborted) onAbort();
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js
|
|
154
|
+
/**
|
|
155
|
+
* Default in-memory credential store. Apps inject persistent stores.
|
|
156
|
+
* Keyed by `Provider.id`, one credential per provider; see `CredentialStore`.
|
|
157
|
+
* Writes are serialized per provider through a promise chain.
|
|
158
|
+
*/
|
|
159
|
+
var InMemoryCredentialStore = class {
|
|
160
|
+
credentials = /* @__PURE__ */ new Map();
|
|
161
|
+
chains = /* @__PURE__ */ new Map();
|
|
162
|
+
/** Serialize tasks per provider id without releasing the chain before active work settles. */
|
|
163
|
+
enqueue(providerId, task, options) {
|
|
164
|
+
const signal = operationSignal(options?.signal);
|
|
165
|
+
const previous = this.chains.get(providerId) ?? Promise.resolve();
|
|
166
|
+
const queued = (async () => {
|
|
167
|
+
await previous.catch(() => {});
|
|
168
|
+
signal.throwIfAborted();
|
|
169
|
+
return task();
|
|
170
|
+
})();
|
|
171
|
+
const tail = queued.catch(() => {});
|
|
172
|
+
this.chains.set(providerId, tail);
|
|
173
|
+
tail.then(() => {
|
|
174
|
+
if (this.chains.get(providerId) === tail) this.chains.delete(providerId);
|
|
175
|
+
});
|
|
176
|
+
return raceWithAbortSignal(queued, signal);
|
|
177
|
+
}
|
|
178
|
+
async read(providerId, options) {
|
|
179
|
+
options?.signal?.throwIfAborted();
|
|
180
|
+
return this.credentials.get(providerId);
|
|
181
|
+
}
|
|
182
|
+
async list(options) {
|
|
183
|
+
options?.signal?.throwIfAborted();
|
|
184
|
+
return [...this.credentials].map(([providerId, credential]) => ({
|
|
185
|
+
providerId,
|
|
186
|
+
type: credential.type
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
modify(providerId, fn, options) {
|
|
190
|
+
return this.enqueue(providerId, async () => {
|
|
191
|
+
const current = this.credentials.get(providerId);
|
|
192
|
+
const next = await fn(current);
|
|
193
|
+
options?.signal?.throwIfAborted();
|
|
194
|
+
if (next !== void 0) this.credentials.set(providerId, next);
|
|
195
|
+
return next ?? current;
|
|
196
|
+
}, options);
|
|
197
|
+
}
|
|
198
|
+
delete(providerId, options) {
|
|
199
|
+
return this.enqueue(providerId, async () => {
|
|
200
|
+
this.credentials.delete(providerId);
|
|
201
|
+
}, options);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js
|
|
206
|
+
var ModelsError = class extends Error {
|
|
207
|
+
code;
|
|
208
|
+
constructor(code, message, options) {
|
|
209
|
+
super(withCauseDetail(message, options?.cause), options);
|
|
210
|
+
this.name = "ModelsError";
|
|
211
|
+
this.code = code;
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
/** Callers surface `error.message` only, so keep the underlying reason in it. */
|
|
215
|
+
function withCauseDetail(message, cause) {
|
|
216
|
+
if (cause === void 0 || cause === null) return message;
|
|
217
|
+
const detail = formatThrownValue(cause).trim();
|
|
218
|
+
if (!detail || message.includes(detail)) return message;
|
|
219
|
+
return `${message}: ${detail}`;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Auth resolution shared by the `Models` and `ImagesModels` collections.
|
|
223
|
+
* A stored credential owns the provider: ambient/env is consulted only when
|
|
224
|
+
* nothing is stored. No silent env fallback after a failed refresh or for a
|
|
225
|
+
* credential type without a matching handler.
|
|
226
|
+
*/
|
|
227
|
+
function resolveProviderAuth(provider, credentials, authContext, overrides) {
|
|
228
|
+
const signal = operationSignal(overrides?.signal);
|
|
229
|
+
return raceWithAbortSignal(resolveProviderAuthWithSignal(provider, credentials, authContext, overrides, signal), signal);
|
|
230
|
+
}
|
|
231
|
+
async function resolveProviderAuthWithSignal(provider, credentials, authContext, overrides, signal) {
|
|
232
|
+
signal.throwIfAborted();
|
|
233
|
+
const requestAuthContext = overrides?.env ? overlayEnvAuthContext(authContext, overrides.env) : authContext;
|
|
234
|
+
if (overrides?.apiKey !== void 0 && provider.auth.apiKey) return resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, {
|
|
235
|
+
type: "api_key",
|
|
236
|
+
key: overrides.apiKey,
|
|
237
|
+
env: overrides.env
|
|
238
|
+
}, signal);
|
|
239
|
+
const stored = await readCredential(credentials, provider.id, signal);
|
|
240
|
+
if (stored) {
|
|
241
|
+
if (stored.type === "oauth" && provider.auth.oauth) return resolveStoredOAuth(credentials, provider.id, provider.auth.oauth, stored, signal, overrides?.minOAuthValidityMs);
|
|
242
|
+
if (stored.type === "api_key" && provider.auth.apiKey) {
|
|
243
|
+
const credential = overrides?.env ? {
|
|
244
|
+
...stored,
|
|
245
|
+
env: {
|
|
246
|
+
...stored.env,
|
|
247
|
+
...overrides.env
|
|
248
|
+
}
|
|
249
|
+
} : stored;
|
|
250
|
+
return resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, credential, signal);
|
|
251
|
+
}
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
return provider.auth.apiKey ? resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, void 0, signal) : void 0;
|
|
255
|
+
}
|
|
256
|
+
function overlayEnvAuthContext(base, env) {
|
|
257
|
+
return {
|
|
258
|
+
env: async (name) => env[name] || await base.env(name),
|
|
259
|
+
fileExists: (path) => base.fileExists(path)
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
const DEFAULT_OAUTH_MINIMUM_VALIDITY_MS = 3e5;
|
|
263
|
+
const DEFAULT_OAUTH_REFRESH_TIMEOUT_MS = 15e3;
|
|
264
|
+
/**
|
|
265
|
+
* OAuth resolution with double-checked locking: tokens with less than five
|
|
266
|
+
* minutes remaining lock, re-check expiry under the lock, refresh once
|
|
267
|
+
* globally, and persist the rotated credential before release.
|
|
268
|
+
*/
|
|
269
|
+
async function resolveStoredOAuth(credentials, providerId, oauth, stored, signal, minOAuthValidityMs) {
|
|
270
|
+
const minimumValidityMs = Math.max(DEFAULT_OAUTH_MINIMUM_VALIDITY_MS, minOAuthValidityMs ?? 0);
|
|
271
|
+
const expiresSoon = (credential) => Date.now() + minimumValidityMs >= credential.expires;
|
|
272
|
+
let credential = stored;
|
|
273
|
+
if (expiresSoon(credential)) {
|
|
274
|
+
let post;
|
|
275
|
+
try {
|
|
276
|
+
post = await credentials.modify(providerId, async (current) => {
|
|
277
|
+
if (current?.type !== "oauth") return void 0;
|
|
278
|
+
if (!expiresSoon(current)) return void 0;
|
|
279
|
+
try {
|
|
280
|
+
const refreshSignal = AbortSignal.any([signal, AbortSignal.timeout(DEFAULT_OAUTH_REFRESH_TIMEOUT_MS)]);
|
|
281
|
+
return await oauth.refresh(current, refreshSignal);
|
|
282
|
+
} catch (error) {
|
|
283
|
+
throw new ModelsError("oauth", `OAuth refresh failed for ${providerId}`, { cause: error });
|
|
284
|
+
}
|
|
285
|
+
}, { signal });
|
|
286
|
+
} catch (error) {
|
|
287
|
+
if (error instanceof ModelsError) throw error;
|
|
288
|
+
throw new ModelsError("auth", `Credential store modify failed for ${providerId}`, { cause: error });
|
|
289
|
+
}
|
|
290
|
+
if (post?.type !== "oauth") return void 0;
|
|
291
|
+
credential = post;
|
|
292
|
+
if (minOAuthValidityMs !== void 0 && expiresSoon(credential)) throw new ModelsError("oauth", `OAuth refresh returned a token that expires too soon for ${providerId}`);
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
return {
|
|
296
|
+
auth: await oauth.toAuth(credential),
|
|
297
|
+
source: "OAuth"
|
|
298
|
+
};
|
|
299
|
+
} catch (error) {
|
|
300
|
+
throw new ModelsError("oauth", `OAuth auth derivation failed for ${providerId}`, { cause: error });
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
async function resolveApiKey(authContext, apiKey, providerId, credential, signal) {
|
|
304
|
+
try {
|
|
305
|
+
return await apiKey.resolve({
|
|
306
|
+
ctx: authContext,
|
|
307
|
+
credential,
|
|
308
|
+
signal
|
|
309
|
+
});
|
|
310
|
+
} catch (error) {
|
|
311
|
+
throw new ModelsError("auth", `API key auth failed for provider ${providerId}`, { cause: error });
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
async function readCredential(credentials, providerId, signal) {
|
|
315
|
+
try {
|
|
316
|
+
return await credentials.read(providerId, { signal });
|
|
317
|
+
} catch (error) {
|
|
318
|
+
throw new ModelsError("auth", `Credential store read failed for ${providerId}`, { cause: error });
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
//#endregion
|
|
322
|
+
//#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/models-store.js
|
|
323
|
+
var InMemoryModelsStore = class {
|
|
324
|
+
entries = /* @__PURE__ */ new Map();
|
|
325
|
+
async read(providerId, options) {
|
|
326
|
+
options?.signal?.throwIfAborted();
|
|
327
|
+
const entry = this.entries.get(providerId);
|
|
328
|
+
return entry ? structuredClone(entry) : void 0;
|
|
329
|
+
}
|
|
330
|
+
async write(providerId, entry, options) {
|
|
331
|
+
options?.signal?.throwIfAborted();
|
|
332
|
+
this.entries.set(providerId, structuredClone(entry));
|
|
333
|
+
}
|
|
334
|
+
async delete(providerId, options) {
|
|
335
|
+
options?.signal?.throwIfAborted();
|
|
336
|
+
this.entries.delete(providerId);
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
//#endregion
|
|
340
|
+
//#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/models.js
|
|
341
|
+
function mergeHeaders(base, override) {
|
|
342
|
+
if (!base && !override) return void 0;
|
|
343
|
+
const merged = { ...base };
|
|
344
|
+
for (const [name, value] of Object.entries(override ?? {})) {
|
|
345
|
+
const lowerName = name.toLowerCase();
|
|
346
|
+
for (const existingName of Object.keys(merged)) if (existingName.toLowerCase() === lowerName) delete merged[existingName];
|
|
347
|
+
merged[name] = value;
|
|
348
|
+
}
|
|
349
|
+
return merged;
|
|
350
|
+
}
|
|
351
|
+
var ModelsImpl = class {
|
|
352
|
+
providers = /* @__PURE__ */ new Map();
|
|
353
|
+
credentials;
|
|
354
|
+
modelsStore;
|
|
355
|
+
authContext;
|
|
356
|
+
refreshGenerations = /* @__PURE__ */ new Map();
|
|
357
|
+
refreshControllers = /* @__PURE__ */ new Map();
|
|
358
|
+
publicationChains = /* @__PURE__ */ new Map();
|
|
359
|
+
constructor(options) {
|
|
360
|
+
this.credentials = options?.credentials ?? new InMemoryCredentialStore();
|
|
361
|
+
this.modelsStore = options?.modelsStore ?? new InMemoryModelsStore();
|
|
362
|
+
this.authContext = options?.authContext ?? defaultProviderAuthContext();
|
|
363
|
+
}
|
|
364
|
+
setProvider(provider) {
|
|
365
|
+
this.supersedeProviderRefresh(provider.id);
|
|
366
|
+
this.providers.set(provider.id, provider);
|
|
367
|
+
}
|
|
368
|
+
deleteProvider(id) {
|
|
369
|
+
this.supersedeProviderRefresh(id);
|
|
370
|
+
this.providers.delete(id);
|
|
371
|
+
}
|
|
372
|
+
clearProviders() {
|
|
373
|
+
for (const id of /* @__PURE__ */ new Set([...this.providers.keys(), ...this.refreshControllers.keys()])) this.supersedeProviderRefresh(id);
|
|
374
|
+
this.providers.clear();
|
|
375
|
+
}
|
|
376
|
+
getProviders() {
|
|
377
|
+
return Array.from(this.providers.values());
|
|
378
|
+
}
|
|
379
|
+
getProvider(id) {
|
|
380
|
+
return this.providers.get(id);
|
|
381
|
+
}
|
|
382
|
+
getModels(provider) {
|
|
383
|
+
if (provider !== void 0) {
|
|
384
|
+
const entry = this.providers.get(provider);
|
|
385
|
+
if (!entry) return [];
|
|
386
|
+
try {
|
|
387
|
+
return entry.getModels();
|
|
388
|
+
} catch {
|
|
389
|
+
return [];
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const models = [];
|
|
393
|
+
for (const entry of this.providers.values()) try {
|
|
394
|
+
models.push(...entry.getModels());
|
|
395
|
+
} catch {}
|
|
396
|
+
return models;
|
|
397
|
+
}
|
|
398
|
+
getModel(provider, id) {
|
|
399
|
+
return this.getModels(provider).find((model) => model.id === id);
|
|
400
|
+
}
|
|
401
|
+
supersedeProviderRefresh(providerId) {
|
|
402
|
+
const generation = (this.refreshGenerations.get(providerId) ?? 0) + 1;
|
|
403
|
+
this.refreshGenerations.set(providerId, generation);
|
|
404
|
+
const previous = this.refreshControllers.get(providerId);
|
|
405
|
+
if (previous) {
|
|
406
|
+
this.refreshControllers.delete(providerId);
|
|
407
|
+
previous.abort();
|
|
408
|
+
}
|
|
409
|
+
return generation;
|
|
410
|
+
}
|
|
411
|
+
beginProviderRefresh(providerId) {
|
|
412
|
+
const generation = this.supersedeProviderRefresh(providerId);
|
|
413
|
+
const controller = new AbortController();
|
|
414
|
+
this.refreshControllers.set(providerId, controller);
|
|
415
|
+
return {
|
|
416
|
+
generation,
|
|
417
|
+
controller
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
publishProviderModels(providerId, generation, signal, publication) {
|
|
421
|
+
const previous = this.publicationChains.get(providerId) ?? Promise.resolve();
|
|
422
|
+
const queued = (async () => {
|
|
423
|
+
await previous.catch(() => {});
|
|
424
|
+
if (signal.aborted || this.refreshGenerations.get(providerId) !== generation) return false;
|
|
425
|
+
if (publication.persist === null) await this.modelsStore.delete(providerId, { signal });
|
|
426
|
+
else if (publication.persist !== void 0) await this.modelsStore.write(providerId, structuredClone(publication.persist), { signal });
|
|
427
|
+
if (signal.aborted || this.refreshGenerations.get(providerId) !== generation) return false;
|
|
428
|
+
publication.update?.();
|
|
429
|
+
return true;
|
|
430
|
+
})();
|
|
431
|
+
const tail = queued.catch(() => {});
|
|
432
|
+
this.publicationChains.set(providerId, tail);
|
|
433
|
+
tail.then(() => {
|
|
434
|
+
if (this.publicationChains.get(providerId) === tail) this.publicationChains.delete(providerId);
|
|
435
|
+
});
|
|
436
|
+
return raceWithAbortSignal(queued, signal);
|
|
437
|
+
}
|
|
438
|
+
async runProviderRefreshPhase(provider, credential, allowNetwork, force, generation, signal) {
|
|
439
|
+
const stored = await this.modelsStore.read(provider.id, { signal });
|
|
440
|
+
await provider.refreshModels({
|
|
441
|
+
credential,
|
|
442
|
+
stored: stored ? structuredClone(stored) : void 0,
|
|
443
|
+
publish: (publication) => this.publishProviderModels(provider.id, generation, signal, publication),
|
|
444
|
+
allowNetwork,
|
|
445
|
+
force: allowNetwork ? force : void 0,
|
|
446
|
+
signal
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
async refresh(options = {}) {
|
|
450
|
+
const allowNetwork = options.allowNetwork ?? true;
|
|
451
|
+
const callerSignal = operationSignal(options.signal);
|
|
452
|
+
const errors = /* @__PURE__ */ new Map();
|
|
453
|
+
if (callerSignal.aborted) return {
|
|
454
|
+
aborted: true,
|
|
455
|
+
errors
|
|
456
|
+
};
|
|
457
|
+
const selected = options.providers ? new Set(options.providers) : void 0;
|
|
458
|
+
const refreshable = Array.from(this.providers.values()).filter((provider) => provider.refreshModels !== void 0 && (!selected || selected.has(provider.id)));
|
|
459
|
+
const refresh = Promise.all(refreshable.map(async (provider) => {
|
|
460
|
+
const { generation, controller } = this.beginProviderRefresh(provider.id);
|
|
461
|
+
const signal = AbortSignal.any([callerSignal, controller.signal]);
|
|
462
|
+
const operation = (async () => {
|
|
463
|
+
let storedCredential;
|
|
464
|
+
let credentialError;
|
|
465
|
+
try {
|
|
466
|
+
storedCredential = await this.readCredential(provider.id, signal);
|
|
467
|
+
} catch (error) {
|
|
468
|
+
credentialError = error;
|
|
469
|
+
}
|
|
470
|
+
await this.runProviderRefreshPhase(provider, storedCredential, false, void 0, generation, signal);
|
|
471
|
+
if (credentialError !== void 0) throw credentialError;
|
|
472
|
+
if (!allowNetwork || signal.aborted) return;
|
|
473
|
+
const credential = await this.resolveRefreshCredential(provider, storedCredential, signal);
|
|
474
|
+
if (!credential) return;
|
|
475
|
+
await this.runProviderRefreshPhase(provider, credential, true, options.force, generation, signal);
|
|
476
|
+
})();
|
|
477
|
+
try {
|
|
478
|
+
await raceWithAbortSignal(operation, signal);
|
|
479
|
+
} catch (error) {
|
|
480
|
+
if (!signal.aborted) errors.set(provider.id, error instanceof Error ? error : new ModelsError("model_source", `Model refresh failed for ${provider.id}`, { cause: error }));
|
|
481
|
+
} finally {
|
|
482
|
+
if (this.refreshControllers.get(provider.id) === controller) this.refreshControllers.delete(provider.id);
|
|
483
|
+
}
|
|
484
|
+
}));
|
|
485
|
+
try {
|
|
486
|
+
await raceWithAbortSignal(refresh, callerSignal);
|
|
487
|
+
} catch (error) {
|
|
488
|
+
if (!callerSignal.aborted) throw error;
|
|
489
|
+
}
|
|
490
|
+
return {
|
|
491
|
+
aborted: callerSignal.aborted,
|
|
492
|
+
errors: new Map(errors)
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
async resolveRefreshCredential(provider, stored, signal) {
|
|
496
|
+
if (stored?.type === "oauth") {
|
|
497
|
+
const oauth = provider.auth.oauth;
|
|
498
|
+
if (!oauth) return void 0;
|
|
499
|
+
if (Date.now() < stored.expires) return stored;
|
|
500
|
+
if (signal.aborted) return void 0;
|
|
501
|
+
const post = await this.credentials.modify(provider.id, async (current) => {
|
|
502
|
+
if (current?.type !== "oauth" || Date.now() < current.expires) return void 0;
|
|
503
|
+
return oauth.refresh(current, signal);
|
|
504
|
+
}, { signal });
|
|
505
|
+
return post?.type === "oauth" ? post : void 0;
|
|
506
|
+
}
|
|
507
|
+
const apiKey = provider.auth.apiKey;
|
|
508
|
+
if (!apiKey) return void 0;
|
|
509
|
+
const credential = stored?.type === "api_key" ? stored : void 0;
|
|
510
|
+
const result = await apiKey.resolve({
|
|
511
|
+
ctx: this.authContext,
|
|
512
|
+
credential,
|
|
513
|
+
signal
|
|
514
|
+
});
|
|
515
|
+
if (!result) return void 0;
|
|
516
|
+
return {
|
|
517
|
+
type: "api_key",
|
|
518
|
+
key: result.auth.apiKey,
|
|
519
|
+
env: result.env
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
async readCredential(providerId, signal) {
|
|
523
|
+
try {
|
|
524
|
+
return await this.credentials.read(providerId, { signal });
|
|
525
|
+
} catch (error) {
|
|
526
|
+
throw new ModelsError("auth", `Credential store read failed for ${providerId}`, { cause: error });
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
async checkProviderAuth(provider, credential, signal) {
|
|
530
|
+
if (credential?.type === "oauth") return provider.auth.oauth ? {
|
|
531
|
+
source: "OAuth",
|
|
532
|
+
type: "oauth"
|
|
533
|
+
} : void 0;
|
|
534
|
+
const apiKey = provider.auth.apiKey;
|
|
535
|
+
if (!apiKey) return void 0;
|
|
536
|
+
if (apiKey.check) try {
|
|
537
|
+
return await apiKey.check({
|
|
538
|
+
ctx: this.authContext,
|
|
539
|
+
credential: credential?.type === "api_key" ? credential : void 0,
|
|
540
|
+
signal
|
|
541
|
+
});
|
|
542
|
+
} catch (error) {
|
|
543
|
+
throw new ModelsError("auth", `API key auth check failed for provider ${provider.id}`, { cause: error });
|
|
544
|
+
}
|
|
545
|
+
const resolution = await resolveProviderAuth(provider, this.credentials, this.authContext, { signal });
|
|
546
|
+
return resolution ? {
|
|
547
|
+
source: resolution.source,
|
|
548
|
+
type: "api_key"
|
|
549
|
+
} : void 0;
|
|
550
|
+
}
|
|
551
|
+
checkAuth(providerId, options) {
|
|
552
|
+
const signal = operationSignal(options?.signal);
|
|
553
|
+
return raceWithAbortSignal((async () => {
|
|
554
|
+
signal.throwIfAborted();
|
|
555
|
+
const provider = this.providers.get(providerId);
|
|
556
|
+
if (!provider) return void 0;
|
|
557
|
+
return this.checkProviderAuth(provider, await this.readCredential(providerId, signal), signal);
|
|
558
|
+
})(), signal);
|
|
559
|
+
}
|
|
560
|
+
getAvailable(providerId, options) {
|
|
561
|
+
const signal = operationSignal(options?.signal);
|
|
562
|
+
return raceWithAbortSignal((async () => {
|
|
563
|
+
signal.throwIfAborted();
|
|
564
|
+
const providers = providerId ? [this.providers.get(providerId)].filter((entry) => entry !== void 0) : this.getProviders();
|
|
565
|
+
return (await Promise.all(providers.map(async (provider) => {
|
|
566
|
+
const credential = await this.readCredential(provider.id, signal);
|
|
567
|
+
return {
|
|
568
|
+
provider,
|
|
569
|
+
credential,
|
|
570
|
+
auth: await this.checkProviderAuth(provider, credential, signal)
|
|
571
|
+
};
|
|
572
|
+
}))).flatMap(({ provider, credential, auth }) => {
|
|
573
|
+
if (!auth) return [];
|
|
574
|
+
const models = provider.getModels();
|
|
575
|
+
return provider.filterModels?.(models, credential) ?? models;
|
|
576
|
+
});
|
|
577
|
+
})(), signal);
|
|
578
|
+
}
|
|
579
|
+
async getAuth(providerOrModel, overrides) {
|
|
580
|
+
const signal = operationSignal(overrides?.signal);
|
|
581
|
+
const providerId = typeof providerOrModel === "string" ? providerOrModel : providerOrModel.provider;
|
|
582
|
+
const provider = this.providers.get(providerId);
|
|
583
|
+
if (!provider) return void 0;
|
|
584
|
+
const result = await resolveProviderAuth(provider, this.credentials, this.authContext, {
|
|
585
|
+
...overrides,
|
|
586
|
+
signal
|
|
587
|
+
});
|
|
588
|
+
if (!result || typeof providerOrModel === "string" || !providerOrModel.headers) return result;
|
|
589
|
+
return {
|
|
590
|
+
...result,
|
|
591
|
+
auth: {
|
|
592
|
+
...result.auth,
|
|
593
|
+
headers: mergeHeaders(result.auth.headers, providerOrModel.headers)
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
async login(providerId, type, interaction) {
|
|
598
|
+
const signal = operationSignal(interaction.signal);
|
|
599
|
+
signal.throwIfAborted();
|
|
600
|
+
const provider = this.providers.get(providerId);
|
|
601
|
+
if (!provider) throw new ModelsError("provider", `Unknown provider: ${providerId}`);
|
|
602
|
+
const method = type === "oauth" ? provider.auth.oauth : provider.auth.apiKey;
|
|
603
|
+
if (!method?.login) throw new ModelsError("auth", `${provider.name} does not support ${type} login`);
|
|
604
|
+
const credential = await raceWithAbortSignal(method.login({
|
|
605
|
+
...interaction,
|
|
606
|
+
signal
|
|
607
|
+
}), signal);
|
|
608
|
+
let mutationStarted = false;
|
|
609
|
+
let markMutationStarted;
|
|
610
|
+
const started = new Promise((resolve) => {
|
|
611
|
+
markMutationStarted = resolve;
|
|
612
|
+
});
|
|
613
|
+
const mutation = this.credentials.modify(providerId, async () => {
|
|
614
|
+
mutationStarted = true;
|
|
615
|
+
markMutationStarted?.();
|
|
616
|
+
return credential;
|
|
617
|
+
}, { signal });
|
|
618
|
+
mutation.catch(() => {});
|
|
619
|
+
try {
|
|
620
|
+
await new Promise((resolve, reject) => {
|
|
621
|
+
const onAbort = () => {
|
|
622
|
+
if (!mutationStarted) reject(signal.reason);
|
|
623
|
+
};
|
|
624
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
625
|
+
Promise.race([started, mutation]).then(() => {
|
|
626
|
+
signal.removeEventListener("abort", onAbort);
|
|
627
|
+
resolve();
|
|
628
|
+
}, (error) => {
|
|
629
|
+
signal.removeEventListener("abort", onAbort);
|
|
630
|
+
reject(error);
|
|
631
|
+
});
|
|
632
|
+
if (signal.aborted) onAbort();
|
|
633
|
+
});
|
|
634
|
+
await mutation;
|
|
635
|
+
} catch (error) {
|
|
636
|
+
signal.throwIfAborted();
|
|
637
|
+
throw new ModelsError("auth", `Credential store modify failed for ${providerId}`, { cause: error });
|
|
638
|
+
}
|
|
639
|
+
return credential;
|
|
640
|
+
}
|
|
641
|
+
async logout(providerId, options) {
|
|
642
|
+
const signal = operationSignal(options?.signal);
|
|
643
|
+
signal.throwIfAborted();
|
|
644
|
+
try {
|
|
645
|
+
await this.credentials.delete(providerId, { signal });
|
|
646
|
+
} catch (error) {
|
|
647
|
+
signal.throwIfAborted();
|
|
648
|
+
throw new ModelsError("auth", `Credential store delete failed for ${providerId}`, { cause: error });
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
requireProvider(model) {
|
|
652
|
+
const provider = this.providers.get(model.provider);
|
|
653
|
+
if (!provider) throw new ModelsError("provider", `Unknown provider: ${model.provider}`);
|
|
654
|
+
return provider;
|
|
655
|
+
}
|
|
656
|
+
async applyAuth(model, options) {
|
|
657
|
+
this.requireProvider(model);
|
|
658
|
+
const resolution = await this.getAuth(model, {
|
|
659
|
+
apiKey: options?.apiKey,
|
|
660
|
+
env: options?.env,
|
|
661
|
+
signal: options?.signal
|
|
662
|
+
});
|
|
663
|
+
if (!resolution) throw new ModelsError("auth", `Provider is not configured: ${model.provider}`);
|
|
664
|
+
const auth = resolution.auth;
|
|
665
|
+
const apiKey = options?.apiKey ?? auth.apiKey;
|
|
666
|
+
let headers = mergeHeaders(auth.headers, options?.headers);
|
|
667
|
+
if (options?.transformHeaders) headers = await options.transformHeaders(headers ?? {});
|
|
668
|
+
const env = resolution.env || options?.env ? {
|
|
669
|
+
...resolution.env ?? {},
|
|
670
|
+
...options?.env ?? {}
|
|
671
|
+
} : void 0;
|
|
672
|
+
const requestModel = auth.baseUrl ? {
|
|
673
|
+
...model,
|
|
674
|
+
baseUrl: auth.baseUrl
|
|
675
|
+
} : model;
|
|
676
|
+
const { transformHeaders: _transformHeaders, ...providerOptions } = options ?? {};
|
|
677
|
+
return {
|
|
678
|
+
requestModel,
|
|
679
|
+
requestOptions: {
|
|
680
|
+
...providerOptions,
|
|
681
|
+
apiKey,
|
|
682
|
+
headers,
|
|
683
|
+
env
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
stream(model, context, options) {
|
|
688
|
+
return lazyStream(model, async () => {
|
|
689
|
+
const provider = this.requireProvider(model);
|
|
690
|
+
const { requestModel, requestOptions } = await this.applyAuth(model, options);
|
|
691
|
+
return provider.stream(requestModel, context, requestOptions);
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
async complete(model, context, options) {
|
|
695
|
+
return this.stream(model, context, options).result();
|
|
696
|
+
}
|
|
697
|
+
streamSimple(model, context, options) {
|
|
698
|
+
return lazyStream(model, async () => {
|
|
699
|
+
const provider = this.requireProvider(model);
|
|
700
|
+
const { requestModel, requestOptions } = await this.applyAuth(model, options);
|
|
701
|
+
return provider.streamSimple(requestModel, context, requestOptions);
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
async completeSimple(model, context, options) {
|
|
705
|
+
return this.streamSimple(model, context, options).result();
|
|
706
|
+
}
|
|
707
|
+
async fetchDeferred(model, handle, options) {
|
|
708
|
+
return lazyStream(model, async () => {
|
|
709
|
+
const provider = this.requireProvider(model);
|
|
710
|
+
if (!provider.fetchDeferred) throw new ModelsError("provider", `Provider ${model.provider} does not support deferred responses`);
|
|
711
|
+
const { requestModel, requestOptions } = await this.applyAuth(model, options);
|
|
712
|
+
return provider.fetchDeferred(requestModel, handle, requestOptions);
|
|
713
|
+
}).result();
|
|
714
|
+
}
|
|
715
|
+
async cancelDeferred(model, handle, options) {
|
|
716
|
+
const provider = this.requireProvider(model);
|
|
717
|
+
if (!provider.cancelDeferred) throw new ModelsError("provider", `Provider ${model.provider} does not support deferred responses`);
|
|
718
|
+
const { requestModel, requestOptions } = await this.applyAuth(model, options);
|
|
719
|
+
await provider.cancelDeferred(requestModel, handle, requestOptions);
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
function createModels(options) {
|
|
723
|
+
return new ModelsImpl(options);
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Builds a provider from parts. Built-in provider factories and models.json
|
|
727
|
+
* custom providers both go through this. A single `api` streams all models;
|
|
728
|
+
* an `api` map dispatches on `model.api`, and a model whose api has no entry
|
|
729
|
+
* produces a stream error.
|
|
730
|
+
*/
|
|
731
|
+
function createProvider(input) {
|
|
732
|
+
const baselineModels = input.models;
|
|
733
|
+
let dynamicModels = [];
|
|
734
|
+
const fetchModels = input.fetchModels;
|
|
735
|
+
const currentModels = () => {
|
|
736
|
+
const merged = [...baselineModels];
|
|
737
|
+
for (const model of dynamicModels) {
|
|
738
|
+
const index = merged.findIndex((entry) => entry.id === model.id);
|
|
739
|
+
if (index >= 0) merged[index] = model;
|
|
740
|
+
else merged.push(model);
|
|
741
|
+
}
|
|
742
|
+
return merged;
|
|
743
|
+
};
|
|
744
|
+
const single = typeof input.api.stream === "function" ? input.api : void 0;
|
|
745
|
+
const byApi = single ? void 0 : input.api;
|
|
746
|
+
const apiFor = (model) => single ?? byApi?.[model.api];
|
|
747
|
+
const dispatch = (model, run) => {
|
|
748
|
+
const streams = apiFor(model);
|
|
749
|
+
if (!streams) return lazyStream(model, async () => {
|
|
750
|
+
throw new ModelsError("stream", `Provider ${input.id} has no API implementation for "${model.api}"`);
|
|
751
|
+
});
|
|
752
|
+
return run(streams);
|
|
753
|
+
};
|
|
754
|
+
const provider = {
|
|
755
|
+
id: input.id,
|
|
756
|
+
name: input.name ?? input.id,
|
|
757
|
+
baseUrl: input.baseUrl,
|
|
758
|
+
headers: input.headers,
|
|
759
|
+
auth: input.auth,
|
|
760
|
+
getModels: currentModels,
|
|
761
|
+
refreshModels: fetchModels ? async (context) => {
|
|
762
|
+
if (context.stored) {
|
|
763
|
+
const restored = context.stored.models.filter((model) => model.provider === input.id).map((model) => model);
|
|
764
|
+
if (!await context.publish({ update: () => {
|
|
765
|
+
dynamicModels = restored;
|
|
766
|
+
} })) return;
|
|
767
|
+
}
|
|
768
|
+
if (!context.allowNetwork || context.signal.aborted) return;
|
|
769
|
+
const refreshed = await fetchModels(context);
|
|
770
|
+
if (context.signal.aborted) return;
|
|
771
|
+
await context.publish({
|
|
772
|
+
persist: {
|
|
773
|
+
models: refreshed,
|
|
774
|
+
checkedAt: Date.now()
|
|
775
|
+
},
|
|
776
|
+
update: () => {
|
|
777
|
+
dynamicModels = refreshed;
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
} : void 0,
|
|
781
|
+
filterModels: input.filterModels,
|
|
782
|
+
stream: (model, context, options) => dispatch(model, (streams) => streams.stream(model, context, options)),
|
|
783
|
+
streamSimple: (model, context, options) => dispatch(model, (streams) => streams.streamSimple(model, context, options))
|
|
784
|
+
};
|
|
785
|
+
const streams = single ? [single] : Object.values(byApi ?? {}).filter((entry) => entry !== void 0);
|
|
786
|
+
if (streams.some((entry) => entry.fetchDeferred !== void 0)) provider.fetchDeferred = (model, handle, options) => lazyStream(model, async () => {
|
|
787
|
+
const implementation = apiFor(model);
|
|
788
|
+
if (!implementation?.fetchDeferred) throw new ModelsError("provider", `Provider ${input.id} does not support deferred responses for "${model.api}"`);
|
|
789
|
+
return implementation.fetchDeferred(model, handle, options);
|
|
790
|
+
});
|
|
791
|
+
if (streams.some((entry) => entry.cancelDeferred !== void 0)) provider.cancelDeferred = async (model, handle, options) => {
|
|
792
|
+
const implementation = apiFor(model);
|
|
793
|
+
if (!implementation?.cancelDeferred) throw new ModelsError("provider", `Provider ${input.id} cannot cancel deferred responses for "${model.api}"`);
|
|
794
|
+
await implementation.cancelDeferred(model, handle, options);
|
|
795
|
+
};
|
|
796
|
+
return provider;
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Runtime-checked narrowing for dynamically looked-up models:
|
|
800
|
+
*
|
|
801
|
+
* ```ts
|
|
802
|
+
* const model = models.getModel("anthropic", "claude-opus-4-7");
|
|
803
|
+
* if (model && hasApi(model, "anthropic-messages")) {
|
|
804
|
+
* // model: Model<"anthropic-messages">, stream options fully typed
|
|
805
|
+
* }
|
|
806
|
+
* ```
|
|
807
|
+
*/
|
|
808
|
+
function hasApi(model, api) {
|
|
809
|
+
return model.api === api;
|
|
810
|
+
}
|
|
811
|
+
function calculateCost(model, usage) {
|
|
812
|
+
const inputTokens = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
813
|
+
let rates = model.cost;
|
|
814
|
+
let matchedThreshold = -1;
|
|
815
|
+
for (const tier of model.cost.tiers ?? []) if (inputTokens > tier.inputTokensAbove && tier.inputTokensAbove > matchedThreshold) {
|
|
816
|
+
rates = tier;
|
|
817
|
+
matchedThreshold = tier.inputTokensAbove;
|
|
818
|
+
}
|
|
819
|
+
const longWrite = usage.cacheWrite1h ?? 0;
|
|
820
|
+
const shortWrite = usage.cacheWrite - longWrite;
|
|
821
|
+
usage.cost.input = rates.input / 1e6 * usage.input;
|
|
822
|
+
usage.cost.output = rates.output / 1e6 * usage.output;
|
|
823
|
+
usage.cost.cacheRead = rates.cacheRead / 1e6 * usage.cacheRead;
|
|
824
|
+
usage.cost.cacheWrite = (rates.cacheWrite * shortWrite + rates.input * 2 * longWrite) / 1e6;
|
|
825
|
+
usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
|
|
826
|
+
return usage.cost;
|
|
827
|
+
}
|
|
828
|
+
const EXTENDED_THINKING_LEVELS = [
|
|
829
|
+
"off",
|
|
830
|
+
"minimal",
|
|
831
|
+
"low",
|
|
832
|
+
"medium",
|
|
833
|
+
"high",
|
|
834
|
+
"xhigh",
|
|
835
|
+
"max"
|
|
836
|
+
];
|
|
837
|
+
function getSupportedThinkingLevels(model) {
|
|
838
|
+
if (!model.reasoning) return ["off"];
|
|
839
|
+
return EXTENDED_THINKING_LEVELS.filter((level) => {
|
|
840
|
+
const mapped = model.thinkingLevelMap?.[level];
|
|
841
|
+
if (mapped === null) return false;
|
|
842
|
+
if (level === "xhigh" || level === "max") return mapped !== void 0;
|
|
843
|
+
return true;
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
function clampThinkingLevel(model, level) {
|
|
847
|
+
const availableLevels = getSupportedThinkingLevels(model);
|
|
848
|
+
if (availableLevels.includes(level)) return level;
|
|
849
|
+
const requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);
|
|
850
|
+
if (requestedIndex === -1) return availableLevels[0] ?? "off";
|
|
851
|
+
for (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {
|
|
852
|
+
const candidate = EXTENDED_THINKING_LEVELS[i];
|
|
853
|
+
if (availableLevels.includes(candidate)) return candidate;
|
|
854
|
+
}
|
|
855
|
+
for (let i = requestedIndex - 1; i >= 0; i--) {
|
|
856
|
+
const candidate = EXTENDED_THINKING_LEVELS[i];
|
|
857
|
+
if (availableLevels.includes(candidate)) return candidate;
|
|
858
|
+
}
|
|
859
|
+
return availableLevels[0] ?? "off";
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Check if two models are equal by comparing both their id and provider.
|
|
863
|
+
* Returns false if either model is null or undefined.
|
|
864
|
+
*/
|
|
865
|
+
function modelsAreEqual(a, b) {
|
|
866
|
+
if (!a || !b) return false;
|
|
867
|
+
return a.id === b.id && a.provider === b.provider;
|
|
868
|
+
}
|
|
869
|
+
//#endregion
|
|
870
|
+
//#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/auth/helpers.js
|
|
871
|
+
/**
|
|
872
|
+
* Standard api-key auth: a stored credential key wins, otherwise the first
|
|
873
|
+
* set env var resolves. Includes a `login` that prompts for the key.
|
|
874
|
+
* Providers with non-standard resolution (provider env, ambient files, IAM)
|
|
875
|
+
* write their own `ApiKeyAuth`.
|
|
876
|
+
*/
|
|
877
|
+
function envApiKeyAuth(name, envVars) {
|
|
878
|
+
return {
|
|
879
|
+
name,
|
|
880
|
+
login: async (interaction) => {
|
|
881
|
+
interaction.signal.throwIfAborted();
|
|
882
|
+
const key = await interaction.prompt({
|
|
883
|
+
type: "secret",
|
|
884
|
+
message: `Enter ${name}`
|
|
885
|
+
});
|
|
886
|
+
interaction.signal.throwIfAborted();
|
|
887
|
+
return {
|
|
888
|
+
type: "api_key",
|
|
889
|
+
key
|
|
890
|
+
};
|
|
891
|
+
},
|
|
892
|
+
resolve: async ({ ctx, credential, signal }) => {
|
|
893
|
+
signal.throwIfAborted();
|
|
894
|
+
if (credential?.key) return {
|
|
895
|
+
auth: { apiKey: credential.key },
|
|
896
|
+
env: credential.env,
|
|
897
|
+
source: "stored credential"
|
|
898
|
+
};
|
|
899
|
+
for (const envVar of envVars) {
|
|
900
|
+
const value = await ctx.env(envVar);
|
|
901
|
+
signal.throwIfAborted();
|
|
902
|
+
if (value) return {
|
|
903
|
+
auth: { apiKey: value },
|
|
904
|
+
source: envVar
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Wraps a dynamically imported `OAuthAuth` so provider definitions can
|
|
912
|
+
* advertise OAuth without importing the implementation. The flow loads on
|
|
913
|
+
* first `login`/`refresh`/`toAuth` call; callers keep Node-only flow code out
|
|
914
|
+
* of bundles by loading through a bundler-opaque dynamic import (variable
|
|
915
|
+
* specifier, see the bedrock lazy wrapper).
|
|
916
|
+
*/
|
|
917
|
+
function lazyOAuth(input) {
|
|
918
|
+
let promise;
|
|
919
|
+
const loaded = () => {
|
|
920
|
+
promise ??= input.load();
|
|
921
|
+
return promise;
|
|
922
|
+
};
|
|
923
|
+
return {
|
|
924
|
+
name: input.name,
|
|
925
|
+
isSubscription: input.isSubscription,
|
|
926
|
+
loginLabel: input.loginLabel,
|
|
927
|
+
login: async (interaction) => (await loaded()).login(interaction),
|
|
928
|
+
refresh: async (credential, signal) => (await loaded()).refresh(credential, signal),
|
|
929
|
+
toAuth: async (credential) => (await loaded()).toAuth(credential)
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
//#endregion
|
|
933
|
+
//#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/images-models.js
|
|
934
|
+
var ImagesModelsImpl = class {
|
|
935
|
+
providers = /* @__PURE__ */ new Map();
|
|
936
|
+
credentials;
|
|
937
|
+
authContext;
|
|
938
|
+
constructor(options) {
|
|
939
|
+
this.credentials = options?.credentials ?? new InMemoryCredentialStore();
|
|
940
|
+
this.authContext = options?.authContext ?? defaultProviderAuthContext();
|
|
941
|
+
}
|
|
942
|
+
setProvider(provider) {
|
|
943
|
+
this.providers.set(provider.id, provider);
|
|
944
|
+
}
|
|
945
|
+
deleteProvider(id) {
|
|
946
|
+
this.providers.delete(id);
|
|
947
|
+
}
|
|
948
|
+
clearProviders() {
|
|
949
|
+
this.providers.clear();
|
|
950
|
+
}
|
|
951
|
+
getProviders() {
|
|
952
|
+
return Array.from(this.providers.values());
|
|
953
|
+
}
|
|
954
|
+
getProvider(id) {
|
|
955
|
+
return this.providers.get(id);
|
|
956
|
+
}
|
|
957
|
+
getModels(provider) {
|
|
958
|
+
if (provider !== void 0) {
|
|
959
|
+
const entry = this.providers.get(provider);
|
|
960
|
+
if (!entry) return [];
|
|
961
|
+
try {
|
|
962
|
+
return entry.getModels();
|
|
963
|
+
} catch {
|
|
964
|
+
return [];
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
const models = [];
|
|
968
|
+
for (const entry of this.providers.values()) try {
|
|
969
|
+
models.push(...entry.getModels());
|
|
970
|
+
} catch {}
|
|
971
|
+
return models;
|
|
972
|
+
}
|
|
973
|
+
getModel(provider, id) {
|
|
974
|
+
return this.getModels(provider).find((model) => model.id === id);
|
|
975
|
+
}
|
|
976
|
+
async refresh(provider) {
|
|
977
|
+
if (provider !== void 0) {
|
|
978
|
+
const entry = this.providers.get(provider);
|
|
979
|
+
if (!entry?.refreshModels) return;
|
|
980
|
+
try {
|
|
981
|
+
await entry.refreshModels();
|
|
982
|
+
} catch (error) {
|
|
983
|
+
if (error instanceof ModelsError) throw error;
|
|
984
|
+
throw new ModelsError("model_source", `Model refresh failed for ${provider}`, { cause: error });
|
|
985
|
+
}
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
await Promise.allSettled(Array.from(this.providers.values(), async (entry) => entry.refreshModels?.()));
|
|
989
|
+
}
|
|
990
|
+
async getAuth(providerOrModel, overrides) {
|
|
991
|
+
const providerId = typeof providerOrModel === "string" ? providerOrModel : providerOrModel.provider;
|
|
992
|
+
const provider = this.providers.get(providerId);
|
|
993
|
+
if (!provider) return void 0;
|
|
994
|
+
return resolveProviderAuth(provider, this.credentials, this.authContext, overrides);
|
|
995
|
+
}
|
|
996
|
+
async generateImages(model, context, options) {
|
|
997
|
+
try {
|
|
998
|
+
const provider = this.providers.get(model.provider);
|
|
999
|
+
if (!provider) throw new ModelsError("provider", `Unknown provider: ${model.provider}`);
|
|
1000
|
+
const resolution = await this.getAuth(model, {
|
|
1001
|
+
apiKey: options?.apiKey,
|
|
1002
|
+
env: options?.env,
|
|
1003
|
+
signal: options?.signal
|
|
1004
|
+
});
|
|
1005
|
+
const auth = resolution?.auth;
|
|
1006
|
+
if (!auth) return provider.generateImages(model, context, options);
|
|
1007
|
+
const requestModel = auth.baseUrl ? {
|
|
1008
|
+
...model,
|
|
1009
|
+
baseUrl: auth.baseUrl
|
|
1010
|
+
} : model;
|
|
1011
|
+
const apiKey = options?.apiKey ?? auth.apiKey;
|
|
1012
|
+
const headers = auth.headers || options?.headers ? {
|
|
1013
|
+
...auth.headers,
|
|
1014
|
+
...options?.headers
|
|
1015
|
+
} : void 0;
|
|
1016
|
+
const env = resolution.env || options?.env ? {
|
|
1017
|
+
...resolution.env ?? {},
|
|
1018
|
+
...options?.env ?? {}
|
|
1019
|
+
} : void 0;
|
|
1020
|
+
return await provider.generateImages(requestModel, context, {
|
|
1021
|
+
...options,
|
|
1022
|
+
apiKey,
|
|
1023
|
+
headers,
|
|
1024
|
+
env
|
|
1025
|
+
});
|
|
1026
|
+
} catch (error) {
|
|
1027
|
+
return {
|
|
1028
|
+
api: model.api,
|
|
1029
|
+
provider: model.provider,
|
|
1030
|
+
model: model.id,
|
|
1031
|
+
output: [],
|
|
1032
|
+
stopReason: "error",
|
|
1033
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
1034
|
+
timestamp: Date.now()
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
1039
|
+
function createImagesModels(options) {
|
|
1040
|
+
return new ImagesModelsImpl(options);
|
|
1041
|
+
}
|
|
1042
|
+
/** Builds an image-generation provider from parts. */
|
|
1043
|
+
function createImagesProvider(input) {
|
|
1044
|
+
let models = input.models;
|
|
1045
|
+
let inflightRefresh;
|
|
1046
|
+
const refreshModels = input.refreshModels;
|
|
1047
|
+
return {
|
|
1048
|
+
id: input.id,
|
|
1049
|
+
name: input.name ?? input.id,
|
|
1050
|
+
auth: input.auth,
|
|
1051
|
+
getModels: () => models,
|
|
1052
|
+
refreshModels: refreshModels ? () => {
|
|
1053
|
+
inflightRefresh ??= (async () => {
|
|
1054
|
+
try {
|
|
1055
|
+
models = await refreshModels();
|
|
1056
|
+
} finally {
|
|
1057
|
+
inflightRefresh = void 0;
|
|
1058
|
+
}
|
|
1059
|
+
})();
|
|
1060
|
+
return inflightRefresh;
|
|
1061
|
+
} : void 0,
|
|
1062
|
+
generateImages: (model, context, options) => input.api.generateImages(model, context, options)
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
//#endregion
|
|
1066
|
+
export { lazyStream as _, calculateCost as a, createProvider as c, modelsAreEqual as d, InMemoryModelsStore as f, lazyApi as g, defaultProviderAuthContext as h, lazyOAuth as i, getSupportedThinkingLevels as l, InMemoryCredentialStore as m, createImagesProvider as n, clampThinkingLevel as o, ModelsError as p, envApiKeyAuth as r, createModels as s, createImagesModels as t, hasApi as u };
|
|
1067
|
+
|
|
1068
|
+
//# sourceMappingURL=images-models-DJtHo9Rp.mjs.map
|