@scuffi/gardener 0.1.1
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/LICENSE +21 -0
- package/README.md +17 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/anthropic-messages-CpAYOexF.js +6431 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/deferred-tools-BwNJSp7E.js +31 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/error-body-D8mmocwO.js +6744 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/hash-DAk4mnwB.js +18 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/json-parse-DCA_fvRV.js +1094 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/mimetext.node.es-XQfmuX2L.js +8403 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/openai-completions-Dg9BYhy-.js +907 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/openai-prompt-cache-IAZGhS1U.js +12 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/openai-responses-shared-BptkVdeL.js +560 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/openai-responses-vjbR2NOB.js +240 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/rolldown-runtime-7_rZTKki.js +42 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/simple-options-tFhuCUzS.js +300 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/transform-messages-B41ICucH.js +246 -0
- package/assets/apps/gardener/dist/gardener_runtime/index.js +80307 -0
- package/assets/apps/gardener/migrations/0001_actions_baseline.sql +116 -0
- package/assets/gardener-distribution.json +5 -0
- package/dist/cli.js +24719 -0
- package/dist/cli.js.map +7 -0
- package/package.json +45 -0
|
@@ -0,0 +1,1094 @@
|
|
|
1
|
+
import { t as __commonJSMin } from "./rolldown-runtime-7_rZTKki.js";
|
|
2
|
+
//#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/utils/event-stream.js
|
|
3
|
+
var EventStream = class {
|
|
4
|
+
queue = [];
|
|
5
|
+
waiting = [];
|
|
6
|
+
done = false;
|
|
7
|
+
finalResultPromise;
|
|
8
|
+
resolveFinalResult;
|
|
9
|
+
isComplete;
|
|
10
|
+
extractResult;
|
|
11
|
+
constructor(isComplete, extractResult) {
|
|
12
|
+
this.isComplete = isComplete;
|
|
13
|
+
this.extractResult = extractResult;
|
|
14
|
+
this.finalResultPromise = new Promise((resolve) => {
|
|
15
|
+
this.resolveFinalResult = resolve;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
push(event) {
|
|
19
|
+
if (this.done) return;
|
|
20
|
+
if (this.isComplete(event)) {
|
|
21
|
+
this.done = true;
|
|
22
|
+
this.resolveFinalResult(this.extractResult(event));
|
|
23
|
+
}
|
|
24
|
+
const waiter = this.waiting.shift();
|
|
25
|
+
if (waiter) waiter({
|
|
26
|
+
value: event,
|
|
27
|
+
done: false
|
|
28
|
+
});
|
|
29
|
+
else this.queue.push(event);
|
|
30
|
+
}
|
|
31
|
+
end(result) {
|
|
32
|
+
this.done = true;
|
|
33
|
+
if (result !== void 0) this.resolveFinalResult(result);
|
|
34
|
+
while (this.waiting.length > 0) this.waiting.shift()({
|
|
35
|
+
value: void 0,
|
|
36
|
+
done: true
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
async *[Symbol.asyncIterator]() {
|
|
40
|
+
while (true) if (this.queue.length > 0) yield this.queue.shift();
|
|
41
|
+
else if (this.done) return;
|
|
42
|
+
else {
|
|
43
|
+
const result = await new Promise((resolve) => this.waiting.push(resolve));
|
|
44
|
+
if (result.done) return;
|
|
45
|
+
yield result.value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
result() {
|
|
49
|
+
return this.finalResultPromise;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var AssistantMessageEventStream = class extends EventStream {
|
|
53
|
+
constructor() {
|
|
54
|
+
super((event) => event.type === "done" || event.type === "error", (event) => {
|
|
55
|
+
if (event.type === "done") return event.message;
|
|
56
|
+
else if (event.type === "error") return event.error;
|
|
57
|
+
throw new Error("Unexpected event type for final result");
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
/** Factory function for AssistantMessageEventStream (for use in extensions) */
|
|
62
|
+
function createAssistantMessageEventStream() {
|
|
63
|
+
return new AssistantMessageEventStream();
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/api/lazy.js
|
|
67
|
+
function createSetupErrorMessage(model, error) {
|
|
68
|
+
return {
|
|
69
|
+
role: "assistant",
|
|
70
|
+
content: [],
|
|
71
|
+
api: model.api,
|
|
72
|
+
provider: model.provider,
|
|
73
|
+
model: model.id,
|
|
74
|
+
usage: {
|
|
75
|
+
input: 0,
|
|
76
|
+
output: 0,
|
|
77
|
+
cacheRead: 0,
|
|
78
|
+
cacheWrite: 0,
|
|
79
|
+
totalTokens: 0,
|
|
80
|
+
cost: {
|
|
81
|
+
input: 0,
|
|
82
|
+
output: 0,
|
|
83
|
+
cacheRead: 0,
|
|
84
|
+
cacheWrite: 0,
|
|
85
|
+
total: 0
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
stopReason: "error",
|
|
89
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
90
|
+
timestamp: Date.now()
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function hasResult(source) {
|
|
94
|
+
return typeof source.result === "function";
|
|
95
|
+
}
|
|
96
|
+
async function forwardStream(target, source) {
|
|
97
|
+
for await (const event of source) target.push(event);
|
|
98
|
+
target.end(hasResult(source) ? await source.result() : void 0);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Returns a stream synchronously while running async setup (auth resolution,
|
|
102
|
+
* lazy module loading) behind it. Setup failures terminate the stream with an
|
|
103
|
+
* error event.
|
|
104
|
+
*/
|
|
105
|
+
function lazyStream(model, setup) {
|
|
106
|
+
const outer = new AssistantMessageEventStream();
|
|
107
|
+
setup().then((inner) => forwardStream(outer, inner)).catch((error) => {
|
|
108
|
+
const message = createSetupErrorMessage(model, error);
|
|
109
|
+
outer.push({
|
|
110
|
+
type: "error",
|
|
111
|
+
reason: "error",
|
|
112
|
+
error: message
|
|
113
|
+
});
|
|
114
|
+
outer.end(message);
|
|
115
|
+
});
|
|
116
|
+
return outer;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Wraps a dynamically imported API implementation module as `ProviderStreams`.
|
|
120
|
+
* The module loads on first stream call; the host's import cache deduplicates
|
|
121
|
+
* loads. Load failures terminate the returned stream with an error event.
|
|
122
|
+
*/
|
|
123
|
+
function lazyApi(load) {
|
|
124
|
+
return {
|
|
125
|
+
stream: (model, context, options) => lazyStream(model, async () => (await load()).stream(model, context, options)),
|
|
126
|
+
streamSimple: (model, context, options) => lazyStream(model, async () => (await load()).streamSimple(model, context, options))
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/auth/context.js
|
|
131
|
+
var __rewriteRelativeImportExtension = function(path, preserveJsx) {
|
|
132
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
|
|
133
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
|
|
134
|
+
});
|
|
135
|
+
return path;
|
|
136
|
+
};
|
|
137
|
+
var importNodeModule = (specifier) => import(__rewriteRelativeImportExtension(specifier));
|
|
138
|
+
function getProcessEnv() {
|
|
139
|
+
return globalThis.process?.env;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Default auth context: env vars from `process.env` (undefined in browsers),
|
|
143
|
+
* file existence via node:fs (always false in browsers).
|
|
144
|
+
*/
|
|
145
|
+
function defaultProviderAuthContext() {
|
|
146
|
+
return {
|
|
147
|
+
async env(name) {
|
|
148
|
+
const value = getProcessEnv()?.[name];
|
|
149
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
150
|
+
},
|
|
151
|
+
async fileExists(path) {
|
|
152
|
+
try {
|
|
153
|
+
const fs = await importNodeModule("node:fs/promises");
|
|
154
|
+
let resolved = path;
|
|
155
|
+
if (resolved.startsWith("~")) resolved = (await importNodeModule("node:os")).homedir() + resolved.slice(1);
|
|
156
|
+
await fs.access(resolved);
|
|
157
|
+
return true;
|
|
158
|
+
} catch {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js
|
|
166
|
+
/**
|
|
167
|
+
* Default in-memory credential store. Apps inject persistent stores.
|
|
168
|
+
* Keyed by `Provider.id`, one credential per provider; see `CredentialStore`.
|
|
169
|
+
* Writes are serialized per provider through a promise chain.
|
|
170
|
+
*/
|
|
171
|
+
var InMemoryCredentialStore = class {
|
|
172
|
+
credentials = /* @__PURE__ */ new Map();
|
|
173
|
+
chains = /* @__PURE__ */ new Map();
|
|
174
|
+
/** Serialize tasks per provider id. */
|
|
175
|
+
enqueue(providerId, task) {
|
|
176
|
+
const previous = this.chains.get(providerId) ?? Promise.resolve();
|
|
177
|
+
const next = (async () => {
|
|
178
|
+
await previous.catch(() => {});
|
|
179
|
+
return task();
|
|
180
|
+
})();
|
|
181
|
+
this.chains.set(providerId, next.catch(() => {}));
|
|
182
|
+
return next;
|
|
183
|
+
}
|
|
184
|
+
async read(providerId) {
|
|
185
|
+
return this.credentials.get(providerId);
|
|
186
|
+
}
|
|
187
|
+
async list() {
|
|
188
|
+
return [...this.credentials].map(([providerId, credential]) => ({
|
|
189
|
+
providerId,
|
|
190
|
+
type: credential.type
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
193
|
+
modify(providerId, fn) {
|
|
194
|
+
return this.enqueue(providerId, async () => {
|
|
195
|
+
const current = this.credentials.get(providerId);
|
|
196
|
+
const next = await fn(current);
|
|
197
|
+
if (next !== void 0) this.credentials.set(providerId, next);
|
|
198
|
+
return next ?? current;
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
delete(providerId) {
|
|
202
|
+
return this.enqueue(providerId, async () => {
|
|
203
|
+
this.credentials.delete(providerId);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/utils/diagnostics.js
|
|
209
|
+
function formatThrownValue(value) {
|
|
210
|
+
if (value instanceof Error) return value.message || value.name;
|
|
211
|
+
if (typeof value === "string") return value;
|
|
212
|
+
return String(value);
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js
|
|
216
|
+
var ModelsError = class extends Error {
|
|
217
|
+
code;
|
|
218
|
+
constructor(code, message, options) {
|
|
219
|
+
super(withCauseDetail(message, options?.cause), options);
|
|
220
|
+
this.name = "ModelsError";
|
|
221
|
+
this.code = code;
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
/** Callers surface `error.message` only, so keep the underlying reason in it. */
|
|
225
|
+
function withCauseDetail(message, cause) {
|
|
226
|
+
if (cause === void 0 || cause === null) return message;
|
|
227
|
+
const detail = formatThrownValue(cause).trim();
|
|
228
|
+
if (!detail || message.includes(detail)) return message;
|
|
229
|
+
return `${message}: ${detail}`;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Auth resolution shared by the `Models` and `ImagesModels` collections.
|
|
233
|
+
* A stored credential owns the provider: ambient/env is consulted only when
|
|
234
|
+
* nothing is stored. No silent env fallback after a failed refresh or for a
|
|
235
|
+
* credential type without a matching handler.
|
|
236
|
+
*/
|
|
237
|
+
async function resolveProviderAuth(provider, credentials, authContext, overrides) {
|
|
238
|
+
const requestAuthContext = overrides?.env ? overlayEnvAuthContext(authContext, overrides.env) : authContext;
|
|
239
|
+
if (overrides?.apiKey !== void 0 && provider.auth.apiKey) return resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, {
|
|
240
|
+
type: "api_key",
|
|
241
|
+
key: overrides.apiKey,
|
|
242
|
+
env: overrides.env
|
|
243
|
+
});
|
|
244
|
+
const stored = await readCredential(credentials, provider.id);
|
|
245
|
+
if (stored) {
|
|
246
|
+
if (stored.type === "oauth" && provider.auth.oauth) return resolveStoredOAuth(credentials, provider.id, provider.auth.oauth, stored, overrides?.minOAuthValidityMs);
|
|
247
|
+
if (stored.type === "api_key" && provider.auth.apiKey) {
|
|
248
|
+
const credential = overrides?.env ? {
|
|
249
|
+
...stored,
|
|
250
|
+
env: {
|
|
251
|
+
...stored.env,
|
|
252
|
+
...overrides.env
|
|
253
|
+
}
|
|
254
|
+
} : stored;
|
|
255
|
+
return resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, credential);
|
|
256
|
+
}
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
return provider.auth.apiKey ? resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, void 0) : void 0;
|
|
260
|
+
}
|
|
261
|
+
function overlayEnvAuthContext(base, env) {
|
|
262
|
+
return {
|
|
263
|
+
env: async (name) => env[name] || await base.env(name),
|
|
264
|
+
fileExists: (path) => base.fileExists(path)
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
var DEFAULT_OAUTH_MINIMUM_VALIDITY_MS = 3e5;
|
|
268
|
+
/**
|
|
269
|
+
* OAuth resolution with double-checked locking: tokens with less than five
|
|
270
|
+
* minutes remaining lock, re-check expiry under the lock, refresh once
|
|
271
|
+
* globally, and persist the rotated credential before release.
|
|
272
|
+
*/
|
|
273
|
+
async function resolveStoredOAuth(credentials, providerId, oauth, stored, minOAuthValidityMs) {
|
|
274
|
+
const minimumValidityMs = Math.max(DEFAULT_OAUTH_MINIMUM_VALIDITY_MS, minOAuthValidityMs ?? 0);
|
|
275
|
+
const expiresSoon = (credential) => Date.now() + minimumValidityMs >= credential.expires;
|
|
276
|
+
let credential = stored;
|
|
277
|
+
if (expiresSoon(credential)) {
|
|
278
|
+
let post;
|
|
279
|
+
try {
|
|
280
|
+
post = await credentials.modify(providerId, async (current) => {
|
|
281
|
+
if (current?.type !== "oauth") return void 0;
|
|
282
|
+
if (!expiresSoon(current)) return void 0;
|
|
283
|
+
try {
|
|
284
|
+
return await oauth.refresh(current);
|
|
285
|
+
} catch (error) {
|
|
286
|
+
throw new ModelsError("oauth", `OAuth refresh failed for ${providerId}`, { cause: error });
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
} catch (error) {
|
|
290
|
+
if (error instanceof ModelsError) throw error;
|
|
291
|
+
throw new ModelsError("auth", `Credential store modify failed for ${providerId}`, { cause: error });
|
|
292
|
+
}
|
|
293
|
+
if (post?.type !== "oauth") return void 0;
|
|
294
|
+
credential = post;
|
|
295
|
+
if (minOAuthValidityMs !== void 0 && expiresSoon(credential)) throw new ModelsError("oauth", `OAuth refresh returned a token that expires too soon for ${providerId}`);
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
return {
|
|
299
|
+
auth: await oauth.toAuth(credential),
|
|
300
|
+
source: "OAuth"
|
|
301
|
+
};
|
|
302
|
+
} catch (error) {
|
|
303
|
+
throw new ModelsError("oauth", `OAuth auth derivation failed for ${providerId}`, { cause: error });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
async function resolveApiKey(authContext, apiKey, providerId, credential) {
|
|
307
|
+
try {
|
|
308
|
+
return await apiKey.resolve({
|
|
309
|
+
ctx: authContext,
|
|
310
|
+
credential
|
|
311
|
+
});
|
|
312
|
+
} catch (error) {
|
|
313
|
+
throw new ModelsError("auth", `API key auth failed for provider ${providerId}`, { cause: error });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
async function readCredential(credentials, providerId) {
|
|
317
|
+
try {
|
|
318
|
+
return await credentials.read(providerId);
|
|
319
|
+
} catch (error) {
|
|
320
|
+
throw new ModelsError("auth", `Credential store read failed for ${providerId}`, { cause: error });
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
//#endregion
|
|
324
|
+
//#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/models-store.js
|
|
325
|
+
var InMemoryModelsStore = class {
|
|
326
|
+
entries = /* @__PURE__ */ new Map();
|
|
327
|
+
async read(providerId) {
|
|
328
|
+
const entry = this.entries.get(providerId);
|
|
329
|
+
return entry ? structuredClone(entry) : void 0;
|
|
330
|
+
}
|
|
331
|
+
async write(providerId, entry) {
|
|
332
|
+
this.entries.set(providerId, structuredClone(entry));
|
|
333
|
+
}
|
|
334
|
+
async delete(providerId) {
|
|
335
|
+
this.entries.delete(providerId);
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
//#endregion
|
|
339
|
+
//#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/models.js
|
|
340
|
+
function mergeHeaders(base, override) {
|
|
341
|
+
if (!base && !override) return void 0;
|
|
342
|
+
const merged = { ...base };
|
|
343
|
+
for (const [name, value] of Object.entries(override ?? {})) {
|
|
344
|
+
const lowerName = name.toLowerCase();
|
|
345
|
+
for (const existingName of Object.keys(merged)) if (existingName.toLowerCase() === lowerName) delete merged[existingName];
|
|
346
|
+
merged[name] = value;
|
|
347
|
+
}
|
|
348
|
+
return merged;
|
|
349
|
+
}
|
|
350
|
+
var ModelsImpl = class {
|
|
351
|
+
providers = /* @__PURE__ */ new Map();
|
|
352
|
+
credentials;
|
|
353
|
+
modelsStore;
|
|
354
|
+
authContext;
|
|
355
|
+
constructor(options) {
|
|
356
|
+
this.credentials = options?.credentials ?? new InMemoryCredentialStore();
|
|
357
|
+
this.modelsStore = options?.modelsStore ?? new InMemoryModelsStore();
|
|
358
|
+
this.authContext = options?.authContext ?? defaultProviderAuthContext();
|
|
359
|
+
}
|
|
360
|
+
setProvider(provider) {
|
|
361
|
+
this.providers.set(provider.id, provider);
|
|
362
|
+
}
|
|
363
|
+
deleteProvider(id) {
|
|
364
|
+
this.providers.delete(id);
|
|
365
|
+
}
|
|
366
|
+
clearProviders() {
|
|
367
|
+
this.providers.clear();
|
|
368
|
+
}
|
|
369
|
+
getProviders() {
|
|
370
|
+
return Array.from(this.providers.values());
|
|
371
|
+
}
|
|
372
|
+
getProvider(id) {
|
|
373
|
+
return this.providers.get(id);
|
|
374
|
+
}
|
|
375
|
+
getModels(provider) {
|
|
376
|
+
if (provider !== void 0) {
|
|
377
|
+
const entry = this.providers.get(provider);
|
|
378
|
+
if (!entry) return [];
|
|
379
|
+
try {
|
|
380
|
+
return entry.getModels();
|
|
381
|
+
} catch {
|
|
382
|
+
return [];
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const models = [];
|
|
386
|
+
for (const entry of this.providers.values()) try {
|
|
387
|
+
models.push(...entry.getModels());
|
|
388
|
+
} catch {}
|
|
389
|
+
return models;
|
|
390
|
+
}
|
|
391
|
+
getModel(provider, id) {
|
|
392
|
+
return this.getModels(provider).find((model) => model.id === id);
|
|
393
|
+
}
|
|
394
|
+
async refresh(options = {}) {
|
|
395
|
+
const allowNetwork = options.allowNetwork ?? true;
|
|
396
|
+
const errors = /* @__PURE__ */ new Map();
|
|
397
|
+
const refreshable = Array.from(this.providers.values()).filter((provider) => provider.refreshModels !== void 0);
|
|
398
|
+
await Promise.all(refreshable.map(async (provider) => {
|
|
399
|
+
if (options.signal?.aborted) return;
|
|
400
|
+
const store = {
|
|
401
|
+
read: () => this.modelsStore.read(provider.id),
|
|
402
|
+
write: (entry) => this.modelsStore.write(provider.id, entry),
|
|
403
|
+
delete: () => this.modelsStore.delete(provider.id)
|
|
404
|
+
};
|
|
405
|
+
let stored;
|
|
406
|
+
try {
|
|
407
|
+
stored = await this.readCredential(provider.id);
|
|
408
|
+
const credential = await this.resolveRefreshCredential(provider, stored, allowNetwork, options.signal);
|
|
409
|
+
if (!credential) return;
|
|
410
|
+
await provider.refreshModels({
|
|
411
|
+
credential,
|
|
412
|
+
store,
|
|
413
|
+
allowNetwork,
|
|
414
|
+
force: options.force,
|
|
415
|
+
signal: options.signal
|
|
416
|
+
});
|
|
417
|
+
} catch (error) {
|
|
418
|
+
if (!options.signal?.aborted) errors.set(provider.id, error instanceof Error ? error : new ModelsError("model_source", `Model refresh failed for ${provider.id}`, { cause: error }));
|
|
419
|
+
try {
|
|
420
|
+
await provider.refreshModels({
|
|
421
|
+
credential: stored,
|
|
422
|
+
store,
|
|
423
|
+
allowNetwork: false,
|
|
424
|
+
signal: options.signal
|
|
425
|
+
});
|
|
426
|
+
} catch {}
|
|
427
|
+
}
|
|
428
|
+
}));
|
|
429
|
+
return {
|
|
430
|
+
aborted: options.signal?.aborted ?? false,
|
|
431
|
+
errors
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
async resolveRefreshCredential(provider, stored, allowNetwork, signal) {
|
|
435
|
+
if (stored?.type === "oauth") {
|
|
436
|
+
const oauth = provider.auth.oauth;
|
|
437
|
+
if (!oauth) return void 0;
|
|
438
|
+
if (!allowNetwork || Date.now() < stored.expires) return stored;
|
|
439
|
+
if (signal?.aborted) return void 0;
|
|
440
|
+
const post = await this.credentials.modify(provider.id, async (current) => {
|
|
441
|
+
if (current?.type !== "oauth" || Date.now() < current.expires) return void 0;
|
|
442
|
+
return oauth.refresh(current, signal);
|
|
443
|
+
});
|
|
444
|
+
return post?.type === "oauth" ? post : void 0;
|
|
445
|
+
}
|
|
446
|
+
const apiKey = provider.auth.apiKey;
|
|
447
|
+
if (!apiKey) return void 0;
|
|
448
|
+
const credential = stored?.type === "api_key" ? stored : void 0;
|
|
449
|
+
const result = await apiKey.resolve({
|
|
450
|
+
ctx: this.authContext,
|
|
451
|
+
credential
|
|
452
|
+
});
|
|
453
|
+
if (!result) return void 0;
|
|
454
|
+
return {
|
|
455
|
+
type: "api_key",
|
|
456
|
+
key: result.auth.apiKey,
|
|
457
|
+
env: result.env
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
async readCredential(providerId) {
|
|
461
|
+
try {
|
|
462
|
+
return await this.credentials.read(providerId);
|
|
463
|
+
} catch (error) {
|
|
464
|
+
throw new ModelsError("auth", `Credential store read failed for ${providerId}`, { cause: error });
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
async checkProviderAuth(provider, credential) {
|
|
468
|
+
if (credential?.type === "oauth") return provider.auth.oauth ? {
|
|
469
|
+
source: "OAuth",
|
|
470
|
+
type: "oauth"
|
|
471
|
+
} : void 0;
|
|
472
|
+
const apiKey = provider.auth.apiKey;
|
|
473
|
+
if (!apiKey) return void 0;
|
|
474
|
+
if (apiKey.check) try {
|
|
475
|
+
return await apiKey.check({
|
|
476
|
+
ctx: this.authContext,
|
|
477
|
+
credential: credential?.type === "api_key" ? credential : void 0
|
|
478
|
+
});
|
|
479
|
+
} catch (error) {
|
|
480
|
+
throw new ModelsError("auth", `API key auth check failed for provider ${provider.id}`, { cause: error });
|
|
481
|
+
}
|
|
482
|
+
const resolution = await resolveProviderAuth(provider, this.credentials, this.authContext);
|
|
483
|
+
return resolution ? {
|
|
484
|
+
source: resolution.source,
|
|
485
|
+
type: "api_key"
|
|
486
|
+
} : void 0;
|
|
487
|
+
}
|
|
488
|
+
async checkAuth(providerId) {
|
|
489
|
+
const provider = this.providers.get(providerId);
|
|
490
|
+
if (!provider) return void 0;
|
|
491
|
+
return this.checkProviderAuth(provider, await this.readCredential(providerId));
|
|
492
|
+
}
|
|
493
|
+
async getAvailable(providerId) {
|
|
494
|
+
const providers = providerId ? [this.providers.get(providerId)].filter((entry) => entry !== void 0) : this.getProviders();
|
|
495
|
+
return (await Promise.all(providers.map(async (provider) => {
|
|
496
|
+
const credential = await this.readCredential(provider.id);
|
|
497
|
+
return {
|
|
498
|
+
provider,
|
|
499
|
+
credential,
|
|
500
|
+
auth: await this.checkProviderAuth(provider, credential)
|
|
501
|
+
};
|
|
502
|
+
}))).flatMap(({ provider, credential, auth }) => {
|
|
503
|
+
if (!auth) return [];
|
|
504
|
+
const models = provider.getModels();
|
|
505
|
+
return provider.filterModels?.(models, credential) ?? models;
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
async getAuth(providerOrModel, overrides) {
|
|
509
|
+
const providerId = typeof providerOrModel === "string" ? providerOrModel : providerOrModel.provider;
|
|
510
|
+
const provider = this.providers.get(providerId);
|
|
511
|
+
if (!provider) return void 0;
|
|
512
|
+
const result = await resolveProviderAuth(provider, this.credentials, this.authContext, overrides);
|
|
513
|
+
if (!result || typeof providerOrModel === "string" || !providerOrModel.headers) return result;
|
|
514
|
+
return {
|
|
515
|
+
...result,
|
|
516
|
+
auth: {
|
|
517
|
+
...result.auth,
|
|
518
|
+
headers: mergeHeaders(result.auth.headers, providerOrModel.headers)
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
async login(providerId, type, interaction) {
|
|
523
|
+
const provider = this.providers.get(providerId);
|
|
524
|
+
if (!provider) throw new ModelsError("provider", `Unknown provider: ${providerId}`);
|
|
525
|
+
const method = type === "oauth" ? provider.auth.oauth : provider.auth.apiKey;
|
|
526
|
+
if (!method?.login) throw new ModelsError("auth", `${provider.name} does not support ${type} login`);
|
|
527
|
+
const credential = await method.login(interaction);
|
|
528
|
+
try {
|
|
529
|
+
await this.credentials.modify(providerId, async () => credential);
|
|
530
|
+
} catch (error) {
|
|
531
|
+
throw new ModelsError("auth", `Credential store modify failed for ${providerId}`, { cause: error });
|
|
532
|
+
}
|
|
533
|
+
return credential;
|
|
534
|
+
}
|
|
535
|
+
async logout(providerId) {
|
|
536
|
+
try {
|
|
537
|
+
await this.credentials.delete(providerId);
|
|
538
|
+
} catch (error) {
|
|
539
|
+
throw new ModelsError("auth", `Credential store delete failed for ${providerId}`, { cause: error });
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
requireProvider(model) {
|
|
543
|
+
const provider = this.providers.get(model.provider);
|
|
544
|
+
if (!provider) throw new ModelsError("provider", `Unknown provider: ${model.provider}`);
|
|
545
|
+
return provider;
|
|
546
|
+
}
|
|
547
|
+
async applyAuth(model, options) {
|
|
548
|
+
this.requireProvider(model);
|
|
549
|
+
const resolution = await this.getAuth(model, {
|
|
550
|
+
apiKey: options?.apiKey,
|
|
551
|
+
env: options?.env
|
|
552
|
+
});
|
|
553
|
+
if (!resolution) throw new ModelsError("auth", `Provider is not configured: ${model.provider}`);
|
|
554
|
+
const auth = resolution.auth;
|
|
555
|
+
const apiKey = options?.apiKey ?? auth.apiKey;
|
|
556
|
+
let headers = mergeHeaders(auth.headers, options?.headers);
|
|
557
|
+
if (options?.transformHeaders) headers = await options.transformHeaders(headers ?? {});
|
|
558
|
+
const env = resolution.env || options?.env ? {
|
|
559
|
+
...resolution.env ?? {},
|
|
560
|
+
...options?.env ?? {}
|
|
561
|
+
} : void 0;
|
|
562
|
+
const requestModel = auth.baseUrl ? {
|
|
563
|
+
...model,
|
|
564
|
+
baseUrl: auth.baseUrl
|
|
565
|
+
} : model;
|
|
566
|
+
const { transformHeaders: _transformHeaders, ...providerOptions } = options ?? {};
|
|
567
|
+
return {
|
|
568
|
+
requestModel,
|
|
569
|
+
requestOptions: {
|
|
570
|
+
...providerOptions,
|
|
571
|
+
apiKey,
|
|
572
|
+
headers,
|
|
573
|
+
env
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
stream(model, context, options) {
|
|
578
|
+
return lazyStream(model, async () => {
|
|
579
|
+
const provider = this.requireProvider(model);
|
|
580
|
+
const { requestModel, requestOptions } = await this.applyAuth(model, options);
|
|
581
|
+
return provider.stream(requestModel, context, requestOptions);
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
async complete(model, context, options) {
|
|
585
|
+
return this.stream(model, context, options).result();
|
|
586
|
+
}
|
|
587
|
+
streamSimple(model, context, options) {
|
|
588
|
+
return lazyStream(model, async () => {
|
|
589
|
+
const provider = this.requireProvider(model);
|
|
590
|
+
const { requestModel, requestOptions } = await this.applyAuth(model, options);
|
|
591
|
+
return provider.streamSimple(requestModel, context, requestOptions);
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
async completeSimple(model, context, options) {
|
|
595
|
+
return this.streamSimple(model, context, options).result();
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
function createModels(options) {
|
|
599
|
+
return new ModelsImpl(options);
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Builds a provider from parts. Built-in provider factories and models.json
|
|
603
|
+
* custom providers both go through this. A single `api` streams all models;
|
|
604
|
+
* an `api` map dispatches on `model.api`, and a model whose api has no entry
|
|
605
|
+
* produces a stream error.
|
|
606
|
+
*/
|
|
607
|
+
function createProvider(input) {
|
|
608
|
+
const baselineModels = input.models;
|
|
609
|
+
let dynamicModels = [];
|
|
610
|
+
let inflightRefresh;
|
|
611
|
+
const fetchModels = input.fetchModels;
|
|
612
|
+
const currentModels = () => {
|
|
613
|
+
const merged = [...baselineModels];
|
|
614
|
+
for (const model of dynamicModels) {
|
|
615
|
+
const index = merged.findIndex((entry) => entry.id === model.id);
|
|
616
|
+
if (index >= 0) merged[index] = model;
|
|
617
|
+
else merged.push(model);
|
|
618
|
+
}
|
|
619
|
+
return merged;
|
|
620
|
+
};
|
|
621
|
+
const single = typeof input.api.stream === "function" ? input.api : void 0;
|
|
622
|
+
const byApi = single ? void 0 : input.api;
|
|
623
|
+
const apiFor = (model) => single ?? byApi?.[model.api];
|
|
624
|
+
const dispatch = (model, run) => {
|
|
625
|
+
const streams = apiFor(model);
|
|
626
|
+
if (!streams) return lazyStream(model, async () => {
|
|
627
|
+
throw new ModelsError("stream", `Provider ${input.id} has no API implementation for "${model.api}"`);
|
|
628
|
+
});
|
|
629
|
+
return run(streams);
|
|
630
|
+
};
|
|
631
|
+
return {
|
|
632
|
+
id: input.id,
|
|
633
|
+
name: input.name ?? input.id,
|
|
634
|
+
baseUrl: input.baseUrl,
|
|
635
|
+
headers: input.headers,
|
|
636
|
+
auth: input.auth,
|
|
637
|
+
getModels: currentModels,
|
|
638
|
+
refreshModels: fetchModels ? (context) => {
|
|
639
|
+
inflightRefresh ??= (async () => {
|
|
640
|
+
try {
|
|
641
|
+
const stored = await context.store.read();
|
|
642
|
+
if (stored) dynamicModels = stored.models.filter((model) => model.provider === input.id).map((model) => model);
|
|
643
|
+
if (!context.allowNetwork || context.signal?.aborted) return;
|
|
644
|
+
const refreshed = await fetchModels(context);
|
|
645
|
+
if (context.signal?.aborted) return;
|
|
646
|
+
dynamicModels = refreshed;
|
|
647
|
+
await context.store.write({
|
|
648
|
+
models: refreshed,
|
|
649
|
+
checkedAt: Date.now()
|
|
650
|
+
});
|
|
651
|
+
} finally {
|
|
652
|
+
inflightRefresh = void 0;
|
|
653
|
+
}
|
|
654
|
+
})();
|
|
655
|
+
return inflightRefresh;
|
|
656
|
+
} : void 0,
|
|
657
|
+
filterModels: input.filterModels,
|
|
658
|
+
stream: (model, context, options) => dispatch(model, (streams) => streams.stream(model, context, options)),
|
|
659
|
+
streamSimple: (model, context, options) => dispatch(model, (streams) => streams.streamSimple(model, context, options))
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
function calculateCost(model, usage) {
|
|
663
|
+
const inputTokens = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
664
|
+
let rates = model.cost;
|
|
665
|
+
let matchedThreshold = -1;
|
|
666
|
+
for (const tier of model.cost.tiers ?? []) if (inputTokens > tier.inputTokensAbove && tier.inputTokensAbove > matchedThreshold) {
|
|
667
|
+
rates = tier;
|
|
668
|
+
matchedThreshold = tier.inputTokensAbove;
|
|
669
|
+
}
|
|
670
|
+
const longWrite = usage.cacheWrite1h ?? 0;
|
|
671
|
+
const shortWrite = usage.cacheWrite - longWrite;
|
|
672
|
+
usage.cost.input = rates.input / 1e6 * usage.input;
|
|
673
|
+
usage.cost.output = rates.output / 1e6 * usage.output;
|
|
674
|
+
usage.cost.cacheRead = rates.cacheRead / 1e6 * usage.cacheRead;
|
|
675
|
+
usage.cost.cacheWrite = (rates.cacheWrite * shortWrite + rates.input * 2 * longWrite) / 1e6;
|
|
676
|
+
usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
|
|
677
|
+
return usage.cost;
|
|
678
|
+
}
|
|
679
|
+
var EXTENDED_THINKING_LEVELS = [
|
|
680
|
+
"off",
|
|
681
|
+
"minimal",
|
|
682
|
+
"low",
|
|
683
|
+
"medium",
|
|
684
|
+
"high",
|
|
685
|
+
"xhigh",
|
|
686
|
+
"max"
|
|
687
|
+
];
|
|
688
|
+
function getSupportedThinkingLevels(model) {
|
|
689
|
+
if (!model.reasoning) return ["off"];
|
|
690
|
+
return EXTENDED_THINKING_LEVELS.filter((level) => {
|
|
691
|
+
const mapped = model.thinkingLevelMap?.[level];
|
|
692
|
+
if (mapped === null) return false;
|
|
693
|
+
if (level === "xhigh" || level === "max") return mapped !== void 0;
|
|
694
|
+
return true;
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
function clampThinkingLevel(model, level) {
|
|
698
|
+
const availableLevels = getSupportedThinkingLevels(model);
|
|
699
|
+
if (availableLevels.includes(level)) return level;
|
|
700
|
+
const requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);
|
|
701
|
+
if (requestedIndex === -1) return availableLevels[0] ?? "off";
|
|
702
|
+
for (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {
|
|
703
|
+
const candidate = EXTENDED_THINKING_LEVELS[i];
|
|
704
|
+
if (availableLevels.includes(candidate)) return candidate;
|
|
705
|
+
}
|
|
706
|
+
for (let i = requestedIndex - 1; i >= 0; i--) {
|
|
707
|
+
const candidate = EXTENDED_THINKING_LEVELS[i];
|
|
708
|
+
if (availableLevels.includes(candidate)) return candidate;
|
|
709
|
+
}
|
|
710
|
+
return availableLevels[0] ?? "off";
|
|
711
|
+
}
|
|
712
|
+
//#endregion
|
|
713
|
+
//#region ../../node_modules/.pnpm/partial-json@0.1.7/node_modules/partial-json/dist/options.js
|
|
714
|
+
var require_options = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
715
|
+
/**
|
|
716
|
+
* Sometimes you don't allow every type to be partially parsed.
|
|
717
|
+
* For example, you may not want a partial number because it may increase its size gradually before it's complete.
|
|
718
|
+
* In this case, you can use the `Allow` object to control what types you allow to be partially parsed.
|
|
719
|
+
* @module
|
|
720
|
+
*/
|
|
721
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
722
|
+
exports.Allow = exports.ALL = exports.COLLECTION = exports.ATOM = exports.SPECIAL = exports.INF = exports._INFINITY = exports.INFINITY = exports.NAN = exports.BOOL = exports.NULL = exports.OBJ = exports.ARR = exports.NUM = exports.STR = void 0;
|
|
723
|
+
/**
|
|
724
|
+
* allow partial strings like `"hello \u12` to be parsed as `"hello "`
|
|
725
|
+
*/
|
|
726
|
+
exports.STR = 1;
|
|
727
|
+
/**
|
|
728
|
+
* allow partial numbers like `123.` to be parsed as `123`
|
|
729
|
+
*/
|
|
730
|
+
exports.NUM = 2;
|
|
731
|
+
/**
|
|
732
|
+
* allow partial arrays like `[1, 2,` to be parsed as `[1, 2]`
|
|
733
|
+
*/
|
|
734
|
+
exports.ARR = 4;
|
|
735
|
+
/**
|
|
736
|
+
* allow partial objects like `{"a": 1, "b":` to be parsed as `{"a": 1}`
|
|
737
|
+
*/
|
|
738
|
+
exports.OBJ = 8;
|
|
739
|
+
/**
|
|
740
|
+
* allow `nu` to be parsed as `null`
|
|
741
|
+
*/
|
|
742
|
+
exports.NULL = 16;
|
|
743
|
+
/**
|
|
744
|
+
* allow `tr` to be parsed as `true`, and `fa` to be parsed as `false`
|
|
745
|
+
*/
|
|
746
|
+
exports.BOOL = 32;
|
|
747
|
+
/**
|
|
748
|
+
* allow `Na` to be parsed as `NaN`
|
|
749
|
+
*/
|
|
750
|
+
exports.NAN = 64;
|
|
751
|
+
/**
|
|
752
|
+
* allow `Inf` to be parsed as `Infinity`
|
|
753
|
+
*/
|
|
754
|
+
exports.INFINITY = 128;
|
|
755
|
+
/**
|
|
756
|
+
* allow `-Inf` to be parsed as `-Infinity`
|
|
757
|
+
*/
|
|
758
|
+
exports._INFINITY = 256;
|
|
759
|
+
exports.INF = exports.INFINITY | exports._INFINITY;
|
|
760
|
+
exports.SPECIAL = exports.NULL | exports.BOOL | exports.INF | exports.NAN;
|
|
761
|
+
exports.ATOM = exports.STR | exports.NUM | exports.SPECIAL;
|
|
762
|
+
exports.COLLECTION = exports.ARR | exports.OBJ;
|
|
763
|
+
exports.ALL = exports.ATOM | exports.COLLECTION;
|
|
764
|
+
/**
|
|
765
|
+
* Control what types you allow to be partially parsed.
|
|
766
|
+
* The default is to allow all types to be partially parsed, which in most casees is the best option.
|
|
767
|
+
* @example
|
|
768
|
+
* If you don't want to allow partial objects, you can use the following code:
|
|
769
|
+
* ```ts
|
|
770
|
+
* import { Allow, parse } from "partial-json";
|
|
771
|
+
* parse(`[{"a": 1, "b": 2}, {"a": 3,`, Allow.ARR); // [ { a: 1, b: 2 } ]
|
|
772
|
+
* ```
|
|
773
|
+
* Or you can use `~` to disallow a type:
|
|
774
|
+
* ```ts
|
|
775
|
+
* parse(`[{"a": 1, "b": 2}, {"a": 3,`, ~Allow.OBJ); // [ { a: 1, b: 2 } ]
|
|
776
|
+
* ```
|
|
777
|
+
* @example
|
|
778
|
+
* If you don't want to allow partial strings, you can use the following code:
|
|
779
|
+
* ```ts
|
|
780
|
+
* import { Allow, parse } from "partial-json";
|
|
781
|
+
* parse(`["complete string", "incompl`, ~Allow.STR); // [ 'complete string' ]
|
|
782
|
+
* ```
|
|
783
|
+
*/
|
|
784
|
+
exports.Allow = {
|
|
785
|
+
STR: exports.STR,
|
|
786
|
+
NUM: exports.NUM,
|
|
787
|
+
ARR: exports.ARR,
|
|
788
|
+
OBJ: exports.OBJ,
|
|
789
|
+
NULL: exports.NULL,
|
|
790
|
+
BOOL: exports.BOOL,
|
|
791
|
+
NAN: exports.NAN,
|
|
792
|
+
INFINITY: exports.INFINITY,
|
|
793
|
+
_INFINITY: exports._INFINITY,
|
|
794
|
+
INF: exports.INF,
|
|
795
|
+
SPECIAL: exports.SPECIAL,
|
|
796
|
+
ATOM: exports.ATOM,
|
|
797
|
+
COLLECTION: exports.COLLECTION,
|
|
798
|
+
ALL: exports.ALL
|
|
799
|
+
};
|
|
800
|
+
exports.default = exports.Allow;
|
|
801
|
+
}));
|
|
802
|
+
//#endregion
|
|
803
|
+
//#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/utils/json-parse.js
|
|
804
|
+
var import_dist = (/* @__PURE__ */ __commonJSMin(((exports) => {
|
|
805
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
806
|
+
if (k2 === void 0) k2 = k;
|
|
807
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
808
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) desc = {
|
|
809
|
+
enumerable: true,
|
|
810
|
+
get: function() {
|
|
811
|
+
return m[k];
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
Object.defineProperty(o, k2, desc);
|
|
815
|
+
}) : (function(o, m, k, k2) {
|
|
816
|
+
if (k2 === void 0) k2 = k;
|
|
817
|
+
o[k2] = m[k];
|
|
818
|
+
}));
|
|
819
|
+
var __exportStar = exports && exports.__exportStar || function(m, exports$1) {
|
|
820
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports$1, p)) __createBinding(exports$1, m, p);
|
|
821
|
+
};
|
|
822
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
823
|
+
exports.Allow = exports.MalformedJSON = exports.PartialJSON = exports.parseJSON = exports.parse = void 0;
|
|
824
|
+
var options_1 = require_options();
|
|
825
|
+
Object.defineProperty(exports, "Allow", {
|
|
826
|
+
enumerable: true,
|
|
827
|
+
get: function() {
|
|
828
|
+
return options_1.Allow;
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
__exportStar(require_options(), exports);
|
|
832
|
+
var PartialJSON = class extends Error {};
|
|
833
|
+
exports.PartialJSON = PartialJSON;
|
|
834
|
+
var MalformedJSON = class extends Error {};
|
|
835
|
+
exports.MalformedJSON = MalformedJSON;
|
|
836
|
+
/**
|
|
837
|
+
* Parse incomplete JSON
|
|
838
|
+
* @param {string} jsonString Partial JSON to be parsed
|
|
839
|
+
* @param {number} allowPartial Specify what types are allowed to be partial, see {@link Allow} for details
|
|
840
|
+
* @returns The parsed JSON
|
|
841
|
+
* @throws {PartialJSON} If the JSON is incomplete (related to the `allow` parameter)
|
|
842
|
+
* @throws {MalformedJSON} If the JSON is malformed
|
|
843
|
+
*/
|
|
844
|
+
function parseJSON(jsonString, allowPartial = options_1.Allow.ALL) {
|
|
845
|
+
if (typeof jsonString !== "string") throw new TypeError(`expecting str, got ${typeof jsonString}`);
|
|
846
|
+
if (!jsonString.trim()) throw new Error(`${jsonString} is empty`);
|
|
847
|
+
return _parseJSON(jsonString.trim(), allowPartial);
|
|
848
|
+
}
|
|
849
|
+
exports.parseJSON = parseJSON;
|
|
850
|
+
var _parseJSON = (jsonString, allow) => {
|
|
851
|
+
const length = jsonString.length;
|
|
852
|
+
let index = 0;
|
|
853
|
+
const markPartialJSON = (msg) => {
|
|
854
|
+
throw new PartialJSON(`${msg} at position ${index}`);
|
|
855
|
+
};
|
|
856
|
+
const throwMalformedError = (msg) => {
|
|
857
|
+
throw new MalformedJSON(`${msg} at position ${index}`);
|
|
858
|
+
};
|
|
859
|
+
const parseAny = () => {
|
|
860
|
+
skipBlank();
|
|
861
|
+
if (index >= length) markPartialJSON("Unexpected end of input");
|
|
862
|
+
if (jsonString[index] === "\"") return parseStr();
|
|
863
|
+
if (jsonString[index] === "{") return parseObj();
|
|
864
|
+
if (jsonString[index] === "[") return parseArr();
|
|
865
|
+
if (jsonString.substring(index, index + 4) === "null" || options_1.Allow.NULL & allow && length - index < 4 && "null".startsWith(jsonString.substring(index))) {
|
|
866
|
+
index += 4;
|
|
867
|
+
return null;
|
|
868
|
+
}
|
|
869
|
+
if (jsonString.substring(index, index + 4) === "true" || options_1.Allow.BOOL & allow && length - index < 4 && "true".startsWith(jsonString.substring(index))) {
|
|
870
|
+
index += 4;
|
|
871
|
+
return true;
|
|
872
|
+
}
|
|
873
|
+
if (jsonString.substring(index, index + 5) === "false" || options_1.Allow.BOOL & allow && length - index < 5 && "false".startsWith(jsonString.substring(index))) {
|
|
874
|
+
index += 5;
|
|
875
|
+
return false;
|
|
876
|
+
}
|
|
877
|
+
if (jsonString.substring(index, index + 8) === "Infinity" || options_1.Allow.INFINITY & allow && length - index < 8 && "Infinity".startsWith(jsonString.substring(index))) {
|
|
878
|
+
index += 8;
|
|
879
|
+
return Infinity;
|
|
880
|
+
}
|
|
881
|
+
if (jsonString.substring(index, index + 9) === "-Infinity" || options_1.Allow._INFINITY & allow && 1 < length - index && length - index < 9 && "-Infinity".startsWith(jsonString.substring(index))) {
|
|
882
|
+
index += 9;
|
|
883
|
+
return -Infinity;
|
|
884
|
+
}
|
|
885
|
+
if (jsonString.substring(index, index + 3) === "NaN" || options_1.Allow.NAN & allow && length - index < 3 && "NaN".startsWith(jsonString.substring(index))) {
|
|
886
|
+
index += 3;
|
|
887
|
+
return NaN;
|
|
888
|
+
}
|
|
889
|
+
return parseNum();
|
|
890
|
+
};
|
|
891
|
+
const parseStr = () => {
|
|
892
|
+
const start = index;
|
|
893
|
+
let escape = false;
|
|
894
|
+
index++;
|
|
895
|
+
while (index < length && (jsonString[index] !== "\"" || escape && jsonString[index - 1] === "\\")) {
|
|
896
|
+
escape = jsonString[index] === "\\" ? !escape : false;
|
|
897
|
+
index++;
|
|
898
|
+
}
|
|
899
|
+
if (jsonString.charAt(index) == "\"") try {
|
|
900
|
+
return JSON.parse(jsonString.substring(start, ++index - Number(escape)));
|
|
901
|
+
} catch (e) {
|
|
902
|
+
throwMalformedError(String(e));
|
|
903
|
+
}
|
|
904
|
+
else if (options_1.Allow.STR & allow) try {
|
|
905
|
+
return JSON.parse(jsonString.substring(start, index - Number(escape)) + "\"");
|
|
906
|
+
} catch (e) {
|
|
907
|
+
return JSON.parse(jsonString.substring(start, jsonString.lastIndexOf("\\")) + "\"");
|
|
908
|
+
}
|
|
909
|
+
markPartialJSON("Unterminated string literal");
|
|
910
|
+
};
|
|
911
|
+
const parseObj = () => {
|
|
912
|
+
index++;
|
|
913
|
+
skipBlank();
|
|
914
|
+
const obj = {};
|
|
915
|
+
try {
|
|
916
|
+
while (jsonString[index] !== "}") {
|
|
917
|
+
skipBlank();
|
|
918
|
+
if (index >= length && options_1.Allow.OBJ & allow) return obj;
|
|
919
|
+
const key = parseStr();
|
|
920
|
+
skipBlank();
|
|
921
|
+
index++;
|
|
922
|
+
try {
|
|
923
|
+
obj[key] = parseAny();
|
|
924
|
+
} catch (e) {
|
|
925
|
+
if (options_1.Allow.OBJ & allow) return obj;
|
|
926
|
+
else throw e;
|
|
927
|
+
}
|
|
928
|
+
skipBlank();
|
|
929
|
+
if (jsonString[index] === ",") index++;
|
|
930
|
+
}
|
|
931
|
+
} catch (e) {
|
|
932
|
+
if (options_1.Allow.OBJ & allow) return obj;
|
|
933
|
+
else markPartialJSON("Expected '}' at end of object");
|
|
934
|
+
}
|
|
935
|
+
index++;
|
|
936
|
+
return obj;
|
|
937
|
+
};
|
|
938
|
+
const parseArr = () => {
|
|
939
|
+
index++;
|
|
940
|
+
const arr = [];
|
|
941
|
+
try {
|
|
942
|
+
while (jsonString[index] !== "]") {
|
|
943
|
+
arr.push(parseAny());
|
|
944
|
+
skipBlank();
|
|
945
|
+
if (jsonString[index] === ",") index++;
|
|
946
|
+
}
|
|
947
|
+
} catch (e) {
|
|
948
|
+
if (options_1.Allow.ARR & allow) return arr;
|
|
949
|
+
markPartialJSON("Expected ']' at end of array");
|
|
950
|
+
}
|
|
951
|
+
index++;
|
|
952
|
+
return arr;
|
|
953
|
+
};
|
|
954
|
+
const parseNum = () => {
|
|
955
|
+
if (index === 0) {
|
|
956
|
+
if (jsonString === "-") throwMalformedError("Not sure what '-' is");
|
|
957
|
+
try {
|
|
958
|
+
return JSON.parse(jsonString);
|
|
959
|
+
} catch (e) {
|
|
960
|
+
if (options_1.Allow.NUM & allow) try {
|
|
961
|
+
return JSON.parse(jsonString.substring(0, jsonString.lastIndexOf("e")));
|
|
962
|
+
} catch (e) {}
|
|
963
|
+
throwMalformedError(String(e));
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
const start = index;
|
|
967
|
+
if (jsonString[index] === "-") index++;
|
|
968
|
+
while (jsonString[index] && ",]}".indexOf(jsonString[index]) === -1) index++;
|
|
969
|
+
if (index == length && !(options_1.Allow.NUM & allow)) markPartialJSON("Unterminated number literal");
|
|
970
|
+
try {
|
|
971
|
+
return JSON.parse(jsonString.substring(start, index));
|
|
972
|
+
} catch (e) {
|
|
973
|
+
if (jsonString.substring(start, index) === "-") markPartialJSON("Not sure what '-' is");
|
|
974
|
+
try {
|
|
975
|
+
return JSON.parse(jsonString.substring(start, jsonString.lastIndexOf("e")));
|
|
976
|
+
} catch (e) {
|
|
977
|
+
throwMalformedError(String(e));
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
const skipBlank = () => {
|
|
982
|
+
while (index < length && " \n\r ".includes(jsonString[index])) index++;
|
|
983
|
+
};
|
|
984
|
+
return parseAny();
|
|
985
|
+
};
|
|
986
|
+
exports.parse = parseJSON;
|
|
987
|
+
})))();
|
|
988
|
+
var VALID_JSON_ESCAPES = /* @__PURE__ */ new Set([
|
|
989
|
+
"\"",
|
|
990
|
+
"\\",
|
|
991
|
+
"/",
|
|
992
|
+
"b",
|
|
993
|
+
"f",
|
|
994
|
+
"n",
|
|
995
|
+
"r",
|
|
996
|
+
"t",
|
|
997
|
+
"u"
|
|
998
|
+
]);
|
|
999
|
+
function isControlCharacter(char) {
|
|
1000
|
+
const codePoint = char.codePointAt(0);
|
|
1001
|
+
return codePoint !== void 0 && codePoint >= 0 && codePoint <= 31;
|
|
1002
|
+
}
|
|
1003
|
+
function escapeControlCharacter(char) {
|
|
1004
|
+
switch (char) {
|
|
1005
|
+
case "\b": return "\\b";
|
|
1006
|
+
case "\f": return "\\f";
|
|
1007
|
+
case "\n": return "\\n";
|
|
1008
|
+
case "\r": return "\\r";
|
|
1009
|
+
case " ": return "\\t";
|
|
1010
|
+
default: return `\\u${char.codePointAt(0)?.toString(16).padStart(4, "0") ?? "0000"}`;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
/**
|
|
1014
|
+
* Repairs malformed JSON string literals by:
|
|
1015
|
+
* - escaping raw control characters inside strings
|
|
1016
|
+
* - doubling backslashes before invalid escape characters
|
|
1017
|
+
*/
|
|
1018
|
+
function repairJson(json) {
|
|
1019
|
+
let repaired = "";
|
|
1020
|
+
let inString = false;
|
|
1021
|
+
for (let index = 0; index < json.length; index++) {
|
|
1022
|
+
const char = json[index];
|
|
1023
|
+
if (!inString) {
|
|
1024
|
+
repaired += char;
|
|
1025
|
+
if (char === "\"") inString = true;
|
|
1026
|
+
continue;
|
|
1027
|
+
}
|
|
1028
|
+
if (char === "\"") {
|
|
1029
|
+
repaired += char;
|
|
1030
|
+
inString = false;
|
|
1031
|
+
continue;
|
|
1032
|
+
}
|
|
1033
|
+
if (char === "\\") {
|
|
1034
|
+
const nextChar = json[index + 1];
|
|
1035
|
+
if (nextChar === void 0) {
|
|
1036
|
+
repaired += "\\\\";
|
|
1037
|
+
continue;
|
|
1038
|
+
}
|
|
1039
|
+
if (nextChar === "u") {
|
|
1040
|
+
const unicodeDigits = json.slice(index + 2, index + 6);
|
|
1041
|
+
if (/^[0-9a-fA-F]{4}$/.test(unicodeDigits)) {
|
|
1042
|
+
repaired += `\\u${unicodeDigits}`;
|
|
1043
|
+
index += 5;
|
|
1044
|
+
continue;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
if (VALID_JSON_ESCAPES.has(nextChar)) {
|
|
1048
|
+
repaired += `\\${nextChar}`;
|
|
1049
|
+
index += 1;
|
|
1050
|
+
continue;
|
|
1051
|
+
}
|
|
1052
|
+
repaired += "\\\\";
|
|
1053
|
+
continue;
|
|
1054
|
+
}
|
|
1055
|
+
repaired += isControlCharacter(char) ? escapeControlCharacter(char) : char;
|
|
1056
|
+
}
|
|
1057
|
+
return repaired;
|
|
1058
|
+
}
|
|
1059
|
+
function parseJsonWithRepair(json) {
|
|
1060
|
+
try {
|
|
1061
|
+
return JSON.parse(json);
|
|
1062
|
+
} catch (error) {
|
|
1063
|
+
const repairedJson = repairJson(json);
|
|
1064
|
+
if (repairedJson !== json) return JSON.parse(repairedJson);
|
|
1065
|
+
throw error;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Attempts to parse potentially incomplete JSON during streaming.
|
|
1070
|
+
* Always returns a valid object, even if the JSON is incomplete.
|
|
1071
|
+
*
|
|
1072
|
+
* @param partialJson The partial JSON string from streaming
|
|
1073
|
+
* @returns Parsed object or empty object if parsing fails
|
|
1074
|
+
*/
|
|
1075
|
+
function parseStreamingJson(partialJson) {
|
|
1076
|
+
if (!partialJson || partialJson.trim() === "") return {};
|
|
1077
|
+
try {
|
|
1078
|
+
return parseJsonWithRepair(partialJson);
|
|
1079
|
+
} catch {
|
|
1080
|
+
try {
|
|
1081
|
+
return (0, import_dist.parse)(partialJson) ?? {};
|
|
1082
|
+
} catch {
|
|
1083
|
+
try {
|
|
1084
|
+
return (0, import_dist.parse)(repairJson(partialJson)) ?? {};
|
|
1085
|
+
} catch {
|
|
1086
|
+
return {};
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
//#endregion
|
|
1092
|
+
export { createModels as a, AssistantMessageEventStream as c, clampThinkingLevel as i, createAssistantMessageEventStream as l, parseStreamingJson as n, createProvider as o, calculateCost as r, lazyApi as s, parseJsonWithRepair as t };
|
|
1093
|
+
|
|
1094
|
+
//# sourceMappingURL=json-parse-DCA_fvRV.js.map
|