@demicodes/provider 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/dist/credentials-pool.d.mts +66 -0
- package/dist/credentials-pool.mjs +262 -0
- package/dist/index.d.mts +14 -4
- package/dist/index.mjs +146 -2
- package/dist/testing.d.mts +1 -2
- package/dist/types-B6AclLz0.d.mts +424 -0
- package/package.json +8 -3
- package/dist/types-CGXGUfNJ.d.mts +0 -198
package/README.md
CHANGED
|
@@ -11,9 +11,21 @@ writing providers.
|
|
|
11
11
|
`withProviderId`.
|
|
12
12
|
- **HTTP helpers** — `redactSecretText`, `httpErrorCode`, `normalizeErrorCode`,
|
|
13
13
|
`providerErrorFromUnknown`, `authStatusFromKey`, `httpRequestFailedEvent`.
|
|
14
|
+
- **Quota** — optional `Provider.quota` (`ProviderQuota` / `ProviderQuotaSnapshot`),
|
|
15
|
+
`createProviderQuota`, `ensureQuota`. See
|
|
16
|
+
[docs/provider-quota.md](../../docs/provider-quota.md).
|
|
17
|
+
- **Credentials** — optional `Provider.credentials` for multi-account pool + global
|
|
18
|
+
`setActive` (subscription CLIs). See
|
|
19
|
+
[docs/provider-global-credentials.md](../../docs/provider-global-credentials.md).
|
|
14
20
|
|
|
15
21
|
```ts
|
|
16
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
defineProvider,
|
|
24
|
+
createProviderQuota,
|
|
25
|
+
ensureQuota,
|
|
26
|
+
type ProviderCredentials,
|
|
27
|
+
type ProviderQuota,
|
|
28
|
+
} from '@demicodes/provider'
|
|
17
29
|
```
|
|
18
30
|
|
|
19
31
|
See [Add a Provider](../../docs/guides/add-a-provider.md). Part of
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { d as ProviderCredentialInfo } from "./types-B6AclLz0.mjs";
|
|
2
|
+
//#region src/credentials-pool.d.ts
|
|
3
|
+
interface CredentialEntryMeta {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
detail?: string | null;
|
|
7
|
+
updatedAt: string;
|
|
8
|
+
source?: string | null;
|
|
9
|
+
/** Stable account key for upsert on re-import (email, accountId, entryKey, …). */
|
|
10
|
+
identityKey?: string | null;
|
|
11
|
+
}
|
|
12
|
+
interface FileCredentialPoolOptions {
|
|
13
|
+
/** Demi state root ($DEMI_HOME / ~/.demi). */
|
|
14
|
+
stateDir?: string;
|
|
15
|
+
/** Subdir under credentials/ (e.g. codex, grok-build, claude-code). */
|
|
16
|
+
providerKey: string;
|
|
17
|
+
/** Secret filename inside each entry (auth.json, oauth.json). */
|
|
18
|
+
secretFileName: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Demi local state root (`$DEMI_HOME` / `~/.demi`). Canonical copy — host-local
|
|
22
|
+
* re-exports this for its bridge layout.
|
|
23
|
+
*/
|
|
24
|
+
declare function resolveDemiHome(explicit?: string): string;
|
|
25
|
+
declare function credentialIdFromIdentity(identityKey: string | null | undefined, fallbackLabel: string): string;
|
|
26
|
+
declare function newCredentialId(): string;
|
|
27
|
+
declare class FileCredentialPool {
|
|
28
|
+
readonly root: string;
|
|
29
|
+
readonly secretFileName: string;
|
|
30
|
+
constructor(options: FileCredentialPoolOptions);
|
|
31
|
+
entriesDir(): string;
|
|
32
|
+
entryDir(id: string): string;
|
|
33
|
+
metaPath(id: string): string;
|
|
34
|
+
secretPath(id: string): string;
|
|
35
|
+
activePath(): string;
|
|
36
|
+
list(): Promise<ProviderCredentialInfo[]>;
|
|
37
|
+
listMeta(): Promise<CredentialEntryMeta[]>;
|
|
38
|
+
readMeta(id: string): Promise<CredentialEntryMeta | null>;
|
|
39
|
+
getActiveId(): Promise<string | null>;
|
|
40
|
+
setActiveId(id: string): Promise<void>;
|
|
41
|
+
clearActive(): Promise<void>;
|
|
42
|
+
writeEntry(meta: CredentialEntryMeta, secretText: string): Promise<CredentialEntryMeta>;
|
|
43
|
+
readSecretText(id: string): Promise<string>;
|
|
44
|
+
remove(id: string): Promise<void>;
|
|
45
|
+
private tmpPath;
|
|
46
|
+
/**
|
|
47
|
+
* Serializes pool mutations across processes with a create-exclusive lock
|
|
48
|
+
* file; stale locks (mtime older than 30s) are removed.
|
|
49
|
+
*/
|
|
50
|
+
private withWriteLock;
|
|
51
|
+
findByIdentityKey(identityKey: string): Promise<CredentialEntryMeta | null>;
|
|
52
|
+
/** If active missing but entries exist, pick first and repair active pointer. */
|
|
53
|
+
ensureActivePointer(): Promise<string | null>;
|
|
54
|
+
}
|
|
55
|
+
declare class CredentialPoolError extends Error {
|
|
56
|
+
readonly code: 'credential_not_found' | 'credential_invalid';
|
|
57
|
+
constructor(code: 'credential_not_found' | 'credential_invalid', message: string);
|
|
58
|
+
}
|
|
59
|
+
declare function runVendorLoginCommand(command: string, args: string[], options?: {
|
|
60
|
+
signal?: AbortSignal;
|
|
61
|
+
}): Promise<{
|
|
62
|
+
status: 'completed' | 'cancelled' | 'failed' | 'unavailable';
|
|
63
|
+
message?: string;
|
|
64
|
+
}>;
|
|
65
|
+
//#endregion
|
|
66
|
+
export { CredentialEntryMeta, CredentialPoolError, FileCredentialPool, FileCredentialPoolOptions, credentialIdFromIdentity, newCredentialId, resolveDemiHome, runVendorLoginCommand };
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { errorCode, isRecord, nonEmptyString } from "@demicodes/utils";
|
|
2
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
+
import { chmod, mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { join, resolve } from "node:path";
|
|
6
|
+
//#region src/credentials-pool.ts
|
|
7
|
+
/**
|
|
8
|
+
* Demi multi-credential pool on disk:
|
|
9
|
+
* <stateDir>/credentials/<providerKey>/{active,entries/<id>/{meta.json,secret}}
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Demi local state root (`$DEMI_HOME` / `~/.demi`). Canonical copy — host-local
|
|
13
|
+
* re-exports this for its bridge layout.
|
|
14
|
+
*/
|
|
15
|
+
function resolveDemiHome(explicit) {
|
|
16
|
+
if (explicit && explicit.trim()) return resolve(explicit.trim());
|
|
17
|
+
const fromEnv = process.env.DEMI_HOME;
|
|
18
|
+
if (fromEnv && fromEnv.trim()) return resolve(fromEnv.trim());
|
|
19
|
+
return join(homedir(), ".demi");
|
|
20
|
+
}
|
|
21
|
+
function credentialIdFromIdentity(identityKey, fallbackLabel) {
|
|
22
|
+
const basis = nonEmptyString(identityKey) ?? fallbackLabel;
|
|
23
|
+
return `cred-${createHash("sha256").update(basis).digest("hex").slice(0, 16)}`;
|
|
24
|
+
}
|
|
25
|
+
function newCredentialId() {
|
|
26
|
+
return `cred-${randomUUID().replace(/-/g, "").slice(0, 16)}`;
|
|
27
|
+
}
|
|
28
|
+
var FileCredentialPool = class {
|
|
29
|
+
root;
|
|
30
|
+
secretFileName;
|
|
31
|
+
constructor(options) {
|
|
32
|
+
const stateDir = resolveDemiHome(options.stateDir);
|
|
33
|
+
this.root = join(stateDir, "credentials", options.providerKey);
|
|
34
|
+
this.secretFileName = options.secretFileName;
|
|
35
|
+
}
|
|
36
|
+
entriesDir() {
|
|
37
|
+
return join(this.root, "entries");
|
|
38
|
+
}
|
|
39
|
+
entryDir(id) {
|
|
40
|
+
return join(this.entriesDir(), id);
|
|
41
|
+
}
|
|
42
|
+
metaPath(id) {
|
|
43
|
+
return join(this.entryDir(id), "meta.json");
|
|
44
|
+
}
|
|
45
|
+
secretPath(id) {
|
|
46
|
+
return join(this.entryDir(id), this.secretFileName);
|
|
47
|
+
}
|
|
48
|
+
activePath() {
|
|
49
|
+
return join(this.root, "active");
|
|
50
|
+
}
|
|
51
|
+
async list() {
|
|
52
|
+
return (await this.listMeta()).map((m) => ({
|
|
53
|
+
id: m.id,
|
|
54
|
+
label: m.label,
|
|
55
|
+
detail: m.detail ?? null,
|
|
56
|
+
updatedAt: m.updatedAt
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
async listMeta() {
|
|
60
|
+
let names;
|
|
61
|
+
try {
|
|
62
|
+
names = await readdir(this.entriesDir());
|
|
63
|
+
} catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
const out = [];
|
|
67
|
+
for (const name of names) {
|
|
68
|
+
const meta = await this.readMeta(name);
|
|
69
|
+
if (meta) out.push(meta);
|
|
70
|
+
}
|
|
71
|
+
out.sort((a, b) => a.id.localeCompare(b.id));
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
async readMeta(id) {
|
|
75
|
+
try {
|
|
76
|
+
const raw = JSON.parse(await readFile(this.metaPath(id), "utf8"));
|
|
77
|
+
if (!isRecord(raw)) return null;
|
|
78
|
+
const entryId = nonEmptyString(raw.id) ?? id;
|
|
79
|
+
const label = nonEmptyString(raw.label);
|
|
80
|
+
if (!label) return null;
|
|
81
|
+
return {
|
|
82
|
+
id: entryId,
|
|
83
|
+
label,
|
|
84
|
+
detail: nonEmptyString(raw.detail) ?? null,
|
|
85
|
+
updatedAt: nonEmptyString(raw.updatedAt) ?? (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
86
|
+
source: nonEmptyString(raw.source) ?? null,
|
|
87
|
+
identityKey: nonEmptyString(raw.identityKey) ?? null
|
|
88
|
+
};
|
|
89
|
+
} catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async getActiveId() {
|
|
94
|
+
try {
|
|
95
|
+
const id = (await readFile(this.activePath(), "utf8")).trim();
|
|
96
|
+
if (!id) return null;
|
|
97
|
+
return await this.readMeta(id) ? id : null;
|
|
98
|
+
} catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async setActiveId(id) {
|
|
103
|
+
if (!await this.readMeta(id)) throw new CredentialPoolError("credential_not_found", `Credential "${id}" not found`);
|
|
104
|
+
try {
|
|
105
|
+
await readFile(this.secretPath(id), "utf8");
|
|
106
|
+
} catch {
|
|
107
|
+
throw new CredentialPoolError("credential_not_found", `Credential "${id}" has no secret material`);
|
|
108
|
+
}
|
|
109
|
+
await this.withWriteLock(async () => {
|
|
110
|
+
const tmp = this.tmpPath(this.activePath());
|
|
111
|
+
await writeFile(tmp, `${id}\n`, { mode: 384 });
|
|
112
|
+
await rename(tmp, this.activePath());
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async clearActive() {
|
|
116
|
+
await rm(this.activePath(), { force: true }).catch(() => void 0);
|
|
117
|
+
}
|
|
118
|
+
async writeEntry(meta, secretText) {
|
|
119
|
+
return this.withWriteLock(async () => {
|
|
120
|
+
await mkdir(this.entryDir(meta.id), {
|
|
121
|
+
recursive: true,
|
|
122
|
+
mode: 448
|
|
123
|
+
});
|
|
124
|
+
const secretTmp = this.tmpPath(this.secretPath(meta.id));
|
|
125
|
+
const metaTmp = this.tmpPath(this.metaPath(meta.id));
|
|
126
|
+
await writeFile(secretTmp, secretText, { mode: 384 });
|
|
127
|
+
await chmod(secretTmp, 384).catch(() => void 0);
|
|
128
|
+
await rename(secretTmp, this.secretPath(meta.id));
|
|
129
|
+
await writeFile(metaTmp, `${JSON.stringify(meta, null, 2)}\n`, { mode: 384 });
|
|
130
|
+
await rename(metaTmp, this.metaPath(meta.id));
|
|
131
|
+
return meta;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
async readSecretText(id) {
|
|
135
|
+
return readFile(this.secretPath(id), "utf8");
|
|
136
|
+
}
|
|
137
|
+
async remove(id) {
|
|
138
|
+
await this.withWriteLock(async () => {
|
|
139
|
+
const active = await this.getActiveId();
|
|
140
|
+
await rm(this.entryDir(id), {
|
|
141
|
+
recursive: true,
|
|
142
|
+
force: true
|
|
143
|
+
});
|
|
144
|
+
if (active === id) await this.clearActive();
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
tmpPath(target) {
|
|
148
|
+
return `${target}.${process.pid}.${randomUUID().slice(0, 8)}.tmp`;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Serializes pool mutations across processes with a create-exclusive lock
|
|
152
|
+
* file; stale locks (mtime older than 30s) are removed.
|
|
153
|
+
*/
|
|
154
|
+
async withWriteLock(fn) {
|
|
155
|
+
await mkdir(this.root, {
|
|
156
|
+
recursive: true,
|
|
157
|
+
mode: 448
|
|
158
|
+
});
|
|
159
|
+
const lockPath = join(this.root, ".lock");
|
|
160
|
+
const started = Date.now();
|
|
161
|
+
while (true) try {
|
|
162
|
+
await writeFile(lockPath, `${process.pid}\n`, {
|
|
163
|
+
flag: "wx",
|
|
164
|
+
mode: 384
|
|
165
|
+
});
|
|
166
|
+
break;
|
|
167
|
+
} catch (error) {
|
|
168
|
+
if (errorCode(error) !== "EEXIST") throw error;
|
|
169
|
+
const info = await stat(lockPath).catch(() => null);
|
|
170
|
+
if (info && Date.now() - info.mtimeMs > 3e4) {
|
|
171
|
+
await rm(lockPath, { force: true }).catch(() => void 0);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (Date.now() - started > 5e3) throw new CredentialPoolError("credential_invalid", `Timed out waiting for credential pool lock ${lockPath}`);
|
|
175
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
return await fn();
|
|
179
|
+
} finally {
|
|
180
|
+
await rm(lockPath, { force: true }).catch(() => void 0);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async findByIdentityKey(identityKey) {
|
|
184
|
+
return (await this.listMeta()).find((m) => m.identityKey === identityKey) ?? null;
|
|
185
|
+
}
|
|
186
|
+
/** If active missing but entries exist, pick first and repair active pointer. */
|
|
187
|
+
async ensureActivePointer() {
|
|
188
|
+
const active = await this.getActiveId();
|
|
189
|
+
if (active) return active;
|
|
190
|
+
const all = await this.listMeta();
|
|
191
|
+
if (all.length === 0) return null;
|
|
192
|
+
await this.setActiveId(all[0].id);
|
|
193
|
+
return all[0].id;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
var CredentialPoolError = class extends Error {
|
|
197
|
+
code;
|
|
198
|
+
constructor(code, message) {
|
|
199
|
+
super(message);
|
|
200
|
+
this.code = code;
|
|
201
|
+
this.name = "CredentialPoolError";
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
async function runVendorLoginCommand(command, args, options = {}) {
|
|
205
|
+
const { spawn } = await import("node:child_process");
|
|
206
|
+
return new Promise((resolvePromise) => {
|
|
207
|
+
let child;
|
|
208
|
+
try {
|
|
209
|
+
child = spawn(command, args, {
|
|
210
|
+
stdio: "inherit",
|
|
211
|
+
env: process.env,
|
|
212
|
+
shell: false
|
|
213
|
+
});
|
|
214
|
+
} catch (error) {
|
|
215
|
+
resolvePromise({
|
|
216
|
+
status: "unavailable",
|
|
217
|
+
message: error instanceof Error ? error.message : String(error)
|
|
218
|
+
});
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const onAbort = () => {
|
|
222
|
+
child.kill("SIGTERM");
|
|
223
|
+
};
|
|
224
|
+
if (options.signal) {
|
|
225
|
+
if (options.signal.aborted) {
|
|
226
|
+
child.kill("SIGTERM");
|
|
227
|
+
resolvePromise({ status: "cancelled" });
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
231
|
+
}
|
|
232
|
+
child.on("error", (error) => {
|
|
233
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
234
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
235
|
+
if (errorCode(error) === "ENOENT") {
|
|
236
|
+
resolvePromise({
|
|
237
|
+
status: "unavailable",
|
|
238
|
+
message: `Command not found: ${command}`
|
|
239
|
+
});
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
resolvePromise({
|
|
243
|
+
status: "failed",
|
|
244
|
+
message: msg
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
child.on("exit", (code, signal) => {
|
|
248
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
249
|
+
if (options.signal?.aborted || signal === "SIGTERM" || signal === "SIGINT") {
|
|
250
|
+
resolvePromise({ status: "cancelled" });
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if (code === 0) resolvePromise({ status: "completed" });
|
|
254
|
+
else resolvePromise({
|
|
255
|
+
status: "failed",
|
|
256
|
+
message: `${command} exited with code ${code ?? "null"}`
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
//#endregion
|
|
262
|
+
export { CredentialPoolError, FileCredentialPool, credentialIdFromIdentity, newCredentialId, resolveDemiHome, runVendorLoginCommand };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
import { FileExtension, ModelSelection, ThinkingCapability, ThinkingConfig } from "@demicodes/core";
|
|
3
|
-
|
|
1
|
+
import { A as ProviderQuotaCapability, B as ProviderQuotaWindow, C as ProviderRuntimeState, D as CreateProviderQuotaOptions, E as ToolDefinition, F as ProviderQuotaProbeResult, G as severityFromUsedPercent, H as clampUsedPercent, I as ProviderQuotaSeverity, K as unixSecondsToIso, L as ProviderQuotaSnapshot, M as ProviderQuotaPlan, N as ProviderQuotaProbeCost, O as EnsureQuotaOptions, P as ProviderQuotaProbeOptions, R as ProviderQuotaSource, S as ProviderRuntimeFactory, T as ProviderServiceTier, U as createProviderQuota, V as ProviderQuotaWindowUnit, W as ensureQuota, _ as ProviderFactoryDefinition, a as ModelPolicy, b as ProviderModelList, c as ProviderAuthState, d as ProviderCredentialInfo, f as ProviderCredentialLoginOptions, g as ProviderEvent, h as ProviderCredentialsCapability, i as InferenceSteer, j as ProviderQuotaObserveInput, k as ProviderQuota, l as ProviderCredentialActive, m as ProviderCredentials, n as InferenceItem, o as Provider, p as ProviderCredentialLoginResult, q as usedPercentFromRatio, r as InferenceRequest, s as ProviderAuth, t as AgentProvider, u as ProviderCredentialAddInput, v as ProviderModel, w as ProviderSelection, x as ProviderRun, y as ProviderModelCost, z as ProviderQuotaUnsupportedError } from "./types-B6AclLz0.mjs";
|
|
2
|
+
import { FileExtension, ModelSelection, ThinkingCapability, ThinkingConfig, ToolResultContentBlock } from "@demicodes/core";
|
|
3
|
+
//#region src/content.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Flattens a tool result to plain text for wire formats without native media
|
|
6
|
+
* blocks; non-text blocks become `[<type>:<mediaType>]` placeholders.
|
|
7
|
+
*/
|
|
8
|
+
declare function toolResultContentToText(output: ToolResultContentBlock[]): string;
|
|
9
|
+
//#endregion
|
|
4
10
|
//#region src/provider.d.ts
|
|
5
11
|
declare function defineProvider(definition: ProviderFactoryDefinition): Provider;
|
|
6
12
|
declare function providerRuntime(provider: Provider, selection: ProviderSelection): Promise<AgentProvider> | AgentProvider;
|
|
@@ -41,6 +47,8 @@ type HeadersResolver = () => Record<string, string> | Promise<Record<string, str
|
|
|
41
47
|
declare function clampPromptCacheKey(value: string): string;
|
|
42
48
|
/** Replaces every occurrence of `secret` in `value` with a redaction marker. */
|
|
43
49
|
declare function redactSecretText(value: string, secret: string | null | undefined): string;
|
|
50
|
+
/** Masks bearer tokens and named credential fields in free-form auth error text. */
|
|
51
|
+
declare function redactCredentialText(text: string, extraFieldPatterns?: readonly string[]): string;
|
|
44
52
|
/** Maps an HTTP status (and response text) to a coarse provider error code. */
|
|
45
53
|
declare function httpErrorCode(status: number, message: string): string | null;
|
|
46
54
|
/** Classifies a provider error code/message into a coarse category, falling back to `code`. */
|
|
@@ -51,7 +59,9 @@ declare function providerErrorFromUnknown(error: unknown, secret: string | null
|
|
|
51
59
|
declare function authStatusFromKey(resolveKey: SecretResolver, resolveHeaders: HeadersResolver | undefined, authHeader: string, providerLabel: string): Promise<ProviderAuthState>;
|
|
52
60
|
/** Parses a Retry-After header (delta-seconds or HTTP-date) into milliseconds. */
|
|
53
61
|
declare function retryAfterMsFromHeader(value: string | null): number | undefined;
|
|
62
|
+
/** Reads a header as a finite number, or null when absent/blank/non-numeric. */
|
|
63
|
+
declare function numberHeader(headers: Headers, name: string): number | null;
|
|
54
64
|
/** Builds a redacted provider `error` event from a failed HTTP response. */
|
|
55
65
|
declare function httpRequestFailedEvent(response: Response, secret: string | null | undefined, providerLabel: string): Promise<ProviderEvent>;
|
|
56
66
|
//#endregion
|
|
57
|
-
export { AgentProvider, DEFAULT_ATTACHMENT_EXTENSIONS, InferenceItem, InferenceRequest, InferenceSteer, ModelPolicy, type ModelSelectionFromCatalogOptions, Provider, ProviderAuth, ProviderAuthState, ProviderEvent, ProviderFactoryDefinition, ProviderModel, ProviderModelCost, ProviderModelList, ProviderRun, ProviderRuntimeFactory, ProviderRuntimeState, ProviderSelection, ProviderServiceTier, ToolDefinition, applyModelPolicy, authStatusFromKey, clampPromptCacheKey, defineProvider, httpErrorCode, httpRequestFailedEvent, modelSelectionFromCatalog, normalizeErrorCode, providerErrorFromUnknown, providerRuntime, redactSecretText, retryAfterMsFromHeader, thinkingCapabilitiesFromProviderModel, withProviderId };
|
|
67
|
+
export { AgentProvider, type CreateProviderQuotaOptions, DEFAULT_ATTACHMENT_EXTENSIONS, type EnsureQuotaOptions, InferenceItem, InferenceRequest, InferenceSteer, ModelPolicy, type ModelSelectionFromCatalogOptions, Provider, ProviderAuth, ProviderAuthState, ProviderCredentialActive, ProviderCredentialAddInput, ProviderCredentialInfo, ProviderCredentialLoginOptions, ProviderCredentialLoginResult, ProviderCredentials, ProviderCredentialsCapability, ProviderEvent, ProviderFactoryDefinition, ProviderModel, ProviderModelCost, ProviderModelList, type ProviderQuota, type ProviderQuotaCapability, type ProviderQuotaObserveInput, type ProviderQuotaPlan, type ProviderQuotaProbeCost, type ProviderQuotaProbeOptions, type ProviderQuotaProbeResult, type ProviderQuotaSeverity, type ProviderQuotaSnapshot, type ProviderQuotaSource, ProviderQuotaUnsupportedError, type ProviderQuotaWindow, type ProviderQuotaWindowUnit, ProviderRun, ProviderRuntimeFactory, ProviderRuntimeState, ProviderSelection, ProviderServiceTier, ToolDefinition, applyModelPolicy, authStatusFromKey, clampPromptCacheKey, clampUsedPercent, createProviderQuota, defineProvider, ensureQuota, httpErrorCode, httpRequestFailedEvent, modelSelectionFromCatalog, normalizeErrorCode, numberHeader, providerErrorFromUnknown, providerRuntime, redactCredentialText, redactSecretText, retryAfterMsFromHeader, severityFromUsedPercent, thinkingCapabilitiesFromProviderModel, toolResultContentToText, unixSecondsToIso, usedPercentFromRatio, withProviderId };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
import { VIDEO_FILE_EXTENSIONS } from "@demicodes/core";
|
|
1
2
|
import { shortHash } from "@demicodes/utils";
|
|
3
|
+
//#region src/content.ts
|
|
4
|
+
/**
|
|
5
|
+
* Flattens a tool result to plain text for wire formats without native media
|
|
6
|
+
* blocks; non-text blocks become `[<type>:<mediaType>]` placeholders.
|
|
7
|
+
*/
|
|
8
|
+
function toolResultContentToText(output) {
|
|
9
|
+
return output.map((block) => block.type === "text" ? block.text : `[${block.type}:${block.source.mediaType}]`).join("\n");
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
2
12
|
//#region src/provider.ts
|
|
3
13
|
const runtimeFactorySymbol = Symbol("demi.provider.runtimeFactory");
|
|
4
14
|
function defineProvider(definition) {
|
|
@@ -89,7 +99,7 @@ function modelSelectionFromCatalog(providerId, model, options = {}) {
|
|
|
89
99
|
contextWindow: model?.contextWindow ?? 0,
|
|
90
100
|
inputLimit: null,
|
|
91
101
|
thinking: thinkingCapabilitiesFromProviderModel(model),
|
|
92
|
-
acceptedExtensions: model?.supportsAttachments ? [
|
|
102
|
+
acceptedExtensions: [...model?.supportsAttachments ? accepted : [], ...model?.supportsVideo ? VIDEO_FILE_EXTENSIONS : []]
|
|
93
103
|
},
|
|
94
104
|
thinking: options.thinking ?? null,
|
|
95
105
|
serviceTierId: options.serviceTierId ?? null
|
|
@@ -108,6 +118,16 @@ function clampPromptCacheKey(value) {
|
|
|
108
118
|
function redactSecretText(value, secret) {
|
|
109
119
|
return secret ? value.split(secret).join("[redacted]") : value;
|
|
110
120
|
}
|
|
121
|
+
/** Masks bearer tokens and named credential fields in free-form auth error text. */
|
|
122
|
+
function redactCredentialText(text, extraFieldPatterns = []) {
|
|
123
|
+
const fields = [
|
|
124
|
+
"access_token",
|
|
125
|
+
"refresh_token",
|
|
126
|
+
"id_token",
|
|
127
|
+
...extraFieldPatterns
|
|
128
|
+
];
|
|
129
|
+
return text.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/g, "Bearer [REDACTED]").replace(new RegExp(`(${fields.join("|")})["'=:\\s]+[A-Za-z0-9._~+/=-]+`, "gi"), "$1=[REDACTED]");
|
|
130
|
+
}
|
|
111
131
|
/** Maps an HTTP status (and response text) to a coarse provider error code. */
|
|
112
132
|
function httpErrorCode(status, message) {
|
|
113
133
|
if (status === 401 || status === 403) return "auth_expired";
|
|
@@ -150,6 +170,13 @@ function retryAfterMsFromHeader(value) {
|
|
|
150
170
|
const dateMs = Date.parse(value);
|
|
151
171
|
if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
|
|
152
172
|
}
|
|
173
|
+
/** Reads a header as a finite number, or null when absent/blank/non-numeric. */
|
|
174
|
+
function numberHeader(headers, name) {
|
|
175
|
+
const raw = headers.get(name);
|
|
176
|
+
if (raw == null || raw === "") return null;
|
|
177
|
+
const n = Number(raw);
|
|
178
|
+
return Number.isFinite(n) ? n : null;
|
|
179
|
+
}
|
|
153
180
|
/** Builds a redacted provider `error` event from a failed HTTP response. */
|
|
154
181
|
async function httpRequestFailedEvent(response, secret, providerLabel) {
|
|
155
182
|
const text = await response.text().catch(() => "");
|
|
@@ -164,4 +191,121 @@ async function httpRequestFailedEvent(response, secret, providerLabel) {
|
|
|
164
191
|
return event;
|
|
165
192
|
}
|
|
166
193
|
//#endregion
|
|
167
|
-
|
|
194
|
+
//#region src/quota.ts
|
|
195
|
+
var ProviderQuotaUnsupportedError = class extends Error {
|
|
196
|
+
providerId;
|
|
197
|
+
constructor(providerId, message) {
|
|
198
|
+
super(message ?? `Provider "${providerId}" does not support quota probe`);
|
|
199
|
+
this.providerId = providerId;
|
|
200
|
+
this.name = "ProviderQuotaUnsupportedError";
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* Return a fresh-enough snapshot: cache when valid, else probe when allowed.
|
|
205
|
+
* When only observation is supported and nothing is cached yet, returns null.
|
|
206
|
+
*/
|
|
207
|
+
async function ensureQuota(quota, options = {}) {
|
|
208
|
+
const cap = quota.capability();
|
|
209
|
+
if (cap.mode === "none") return null;
|
|
210
|
+
const latest = quota.latest();
|
|
211
|
+
const maxStale = options.maxStaleMs ?? cap.staleAfterMs ?? 6e4;
|
|
212
|
+
if ((latest !== null && Number.isFinite(Date.parse(latest.observedAt)) ? Date.now() - Date.parse(latest.observedAt) < maxStale : false) && latest && options.prefer !== "probe") return {
|
|
213
|
+
...latest,
|
|
214
|
+
source: "cache"
|
|
215
|
+
};
|
|
216
|
+
if (cap.canProbe) return quota.probe({
|
|
217
|
+
signal: options.signal,
|
|
218
|
+
force: options.prefer === "probe"
|
|
219
|
+
});
|
|
220
|
+
return latest;
|
|
221
|
+
}
|
|
222
|
+
/** In-memory latest snapshot + capability wiring for concrete providers. */
|
|
223
|
+
function createProviderQuota(options) {
|
|
224
|
+
let latest = null;
|
|
225
|
+
const canObserve = options.canObserve ?? Boolean(options.observe);
|
|
226
|
+
const capability = () => {
|
|
227
|
+
if (!options.canProbe && !canObserve) return { mode: "none" };
|
|
228
|
+
return {
|
|
229
|
+
mode: "supported",
|
|
230
|
+
canProbe: options.canProbe,
|
|
231
|
+
canObserve,
|
|
232
|
+
probeCost: options.probeCost,
|
|
233
|
+
staleAfterMs: options.staleAfterMs
|
|
234
|
+
};
|
|
235
|
+
};
|
|
236
|
+
const materialize = (partial, source) => {
|
|
237
|
+
const previous = source === "observation" ? latest : null;
|
|
238
|
+
const snapshot = {
|
|
239
|
+
providerId: options.providerId,
|
|
240
|
+
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
241
|
+
source,
|
|
242
|
+
plan: partial.plan === void 0 ? previous?.plan ?? null : partial.plan,
|
|
243
|
+
accountLabel: partial.accountLabel === void 0 ? previous?.accountLabel ?? null : partial.accountLabel,
|
|
244
|
+
windows: previous ? mergeQuotaWindows(previous.windows, partial.windows) : partial.windows,
|
|
245
|
+
raw: partial.raw
|
|
246
|
+
};
|
|
247
|
+
latest = snapshot;
|
|
248
|
+
return snapshot;
|
|
249
|
+
};
|
|
250
|
+
const quota = {
|
|
251
|
+
capability,
|
|
252
|
+
latest: () => latest,
|
|
253
|
+
clearLatest: () => {
|
|
254
|
+
latest = null;
|
|
255
|
+
},
|
|
256
|
+
async probe(probeOptions = {}) {
|
|
257
|
+
if (!options.canProbe) throw new ProviderQuotaUnsupportedError(options.providerId);
|
|
258
|
+
const partial = await options.probe(probeOptions);
|
|
259
|
+
return materialize(partial, "probe");
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
if (options.observe) {
|
|
263
|
+
const observe = options.observe;
|
|
264
|
+
quota.observeResponse = (input) => {
|
|
265
|
+
const partial = observe(input);
|
|
266
|
+
if (!partial) return null;
|
|
267
|
+
return materialize(partial, "observation");
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
return quota;
|
|
271
|
+
}
|
|
272
|
+
function mergeQuotaWindows(previous, observed) {
|
|
273
|
+
const observedById = new Map(observed.map((window) => [window.id, window]));
|
|
274
|
+
const merged = previous.map((window) => observedById.get(window.id) ?? window);
|
|
275
|
+
const previousIds = new Set(previous.map((window) => window.id));
|
|
276
|
+
for (const window of observed) if (!previousIds.has(window.id)) merged.push(window);
|
|
277
|
+
return merged;
|
|
278
|
+
}
|
|
279
|
+
/** Clamp percent into 0–100 or null. */
|
|
280
|
+
function clampUsedPercent(value) {
|
|
281
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return null;
|
|
282
|
+
if (value < 0) return 0;
|
|
283
|
+
if (value > 100) return 100;
|
|
284
|
+
return value;
|
|
285
|
+
}
|
|
286
|
+
/** used/limit → percent, or null when limit is missing/zero. */
|
|
287
|
+
function usedPercentFromRatio(used, limit) {
|
|
288
|
+
if (used == null || limit == null || !Number.isFinite(used) || !Number.isFinite(limit) || limit <= 0) return null;
|
|
289
|
+
return clampUsedPercent(used / limit * 100);
|
|
290
|
+
}
|
|
291
|
+
function unixSecondsToIso(value) {
|
|
292
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
293
|
+
const ms = value > 0xe8d4a51000 ? value : value * 1e3;
|
|
294
|
+
return new Date(ms).toISOString();
|
|
295
|
+
}
|
|
296
|
+
if (typeof value === "string" && value.trim()) {
|
|
297
|
+
const asNum = Number(value);
|
|
298
|
+
if (Number.isFinite(asNum) && /^\d+(\.\d+)?$/.test(value.trim())) return unixSecondsToIso(asNum);
|
|
299
|
+
const parsed = Date.parse(value);
|
|
300
|
+
if (Number.isFinite(parsed)) return new Date(parsed).toISOString();
|
|
301
|
+
}
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
function severityFromUsedPercent(usedPercent) {
|
|
305
|
+
if (usedPercent == null) return null;
|
|
306
|
+
if (usedPercent >= 95) return "critical";
|
|
307
|
+
if (usedPercent >= 80) return "warning";
|
|
308
|
+
return "normal";
|
|
309
|
+
}
|
|
310
|
+
//#endregion
|
|
311
|
+
export { DEFAULT_ATTACHMENT_EXTENSIONS, ProviderQuotaUnsupportedError, applyModelPolicy, authStatusFromKey, clampPromptCacheKey, clampUsedPercent, createProviderQuota, defineProvider, ensureQuota, httpErrorCode, httpRequestFailedEvent, modelSelectionFromCatalog, normalizeErrorCode, numberHeader, providerErrorFromUnknown, providerRuntime, redactCredentialText, redactSecretText, retryAfterMsFromHeader, severityFromUsedPercent, thinkingCapabilitiesFromProviderModel, toolResultContentToText, unixSecondsToIso, usedPercentFromRatio, withProviderId };
|
package/dist/testing.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { g as ProviderEvent, i as InferenceSteer, r as InferenceRequest, t as AgentProvider, x as ProviderRun } from "./types-B6AclLz0.mjs";
|
|
3
2
|
//#region src/testing.d.ts
|
|
4
3
|
/**
|
|
5
4
|
* Scripted provider for testing. Each "turn" is a list of events to yield.
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import { ModelSelection, ThinkingConfig, ThinkingEffort, TokenUsage, ToolResultContentBlock, UserContentBlock } from "@demicodes/core";
|
|
2
|
+
//#region src/quota.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Unified subscription / rate-limit quota surface for concrete providers.
|
|
5
|
+
*
|
|
6
|
+
* - One snapshot shape for all vendors (windows + optional plan).
|
|
7
|
+
* - Two fill paths: active {@link ProviderQuota.probe} and passive
|
|
8
|
+
* {@link ProviderQuota.observeResponse} (headers / envelopes).
|
|
9
|
+
* - Products read {@link ProviderQuota.latest} or call {@link ensureQuota}.
|
|
10
|
+
*/
|
|
11
|
+
type ProviderQuotaWindowUnit = 'percent' | 'credits' | 'usd_minor' | 'requests' | 'tokens' | 'unknown';
|
|
12
|
+
type ProviderQuotaSeverity = 'normal' | 'warning' | 'critical';
|
|
13
|
+
interface ProviderQuotaWindow {
|
|
14
|
+
/** Stable id: five_hour, seven_day, primary, monthly, rpm, … */
|
|
15
|
+
id: string;
|
|
16
|
+
label?: string;
|
|
17
|
+
/** 0–100 when known. */
|
|
18
|
+
usedPercent: number | null;
|
|
19
|
+
used?: number | null;
|
|
20
|
+
limit?: number | null;
|
|
21
|
+
unit?: ProviderQuotaWindowUnit;
|
|
22
|
+
/** ISO-8601 reset time when known. */
|
|
23
|
+
resetsAt: string | null;
|
|
24
|
+
severity?: ProviderQuotaSeverity | null;
|
|
25
|
+
scope?: {
|
|
26
|
+
kind: string;
|
|
27
|
+
label?: string;
|
|
28
|
+
} | null;
|
|
29
|
+
}
|
|
30
|
+
interface ProviderQuotaPlan {
|
|
31
|
+
id: string | null;
|
|
32
|
+
label?: string | null;
|
|
33
|
+
raw?: string | null;
|
|
34
|
+
}
|
|
35
|
+
type ProviderQuotaSource = 'probe' | 'observation' | 'cache';
|
|
36
|
+
interface ProviderQuotaSnapshot {
|
|
37
|
+
providerId: string;
|
|
38
|
+
observedAt: string;
|
|
39
|
+
source: ProviderQuotaSource;
|
|
40
|
+
plan?: ProviderQuotaPlan | null;
|
|
41
|
+
accountLabel?: string | null;
|
|
42
|
+
windows: ProviderQuotaWindow[];
|
|
43
|
+
/** Vendor payload for debugging; not for generic UI logic. */
|
|
44
|
+
raw?: unknown;
|
|
45
|
+
}
|
|
46
|
+
type ProviderQuotaProbeCost = 'free' | 'minimal_request';
|
|
47
|
+
type ProviderQuotaCapability = {
|
|
48
|
+
mode: 'none';
|
|
49
|
+
} | {
|
|
50
|
+
mode: 'supported';
|
|
51
|
+
canProbe: boolean;
|
|
52
|
+
canObserve: boolean;
|
|
53
|
+
/** free = dedicated usage API; minimal_request = burns a tiny inference */
|
|
54
|
+
probeCost?: ProviderQuotaProbeCost;
|
|
55
|
+
staleAfterMs?: number;
|
|
56
|
+
};
|
|
57
|
+
interface ProviderQuotaProbeOptions {
|
|
58
|
+
signal?: AbortSignal;
|
|
59
|
+
/** Bypass in-memory cache freshness for probe implementations that short-circuit. */
|
|
60
|
+
force?: boolean;
|
|
61
|
+
}
|
|
62
|
+
interface ProviderQuotaObserveInput {
|
|
63
|
+
/** HTTP response headers when the vendor exposes quota there. */
|
|
64
|
+
headers?: Headers;
|
|
65
|
+
status?: number;
|
|
66
|
+
/**
|
|
67
|
+
* Vendor-specific envelope (e.g. Claude stream-json message with `rate_limits`).
|
|
68
|
+
* Used when there is no raw HTTP Response (CLI transport).
|
|
69
|
+
*/
|
|
70
|
+
body?: unknown;
|
|
71
|
+
}
|
|
72
|
+
interface ProviderQuota {
|
|
73
|
+
capability(): ProviderQuotaCapability;
|
|
74
|
+
probe(options?: ProviderQuotaProbeOptions): Promise<ProviderQuotaSnapshot>;
|
|
75
|
+
latest(): ProviderQuotaSnapshot | null;
|
|
76
|
+
/**
|
|
77
|
+
* Drop the in-memory latest snapshot (e.g. after credentials.setActive so the
|
|
78
|
+
* next ensureQuota/probe does not show the previous account).
|
|
79
|
+
*/
|
|
80
|
+
clearLatest?(): void;
|
|
81
|
+
/**
|
|
82
|
+
* Optional passive update from a vendor HTTP response (headers, etc.).
|
|
83
|
+
* Returns the new snapshot when observation succeeded; otherwise null.
|
|
84
|
+
*/
|
|
85
|
+
observeResponse?(input: ProviderQuotaObserveInput): ProviderQuotaSnapshot | null;
|
|
86
|
+
}
|
|
87
|
+
declare class ProviderQuotaUnsupportedError extends Error {
|
|
88
|
+
readonly providerId: string;
|
|
89
|
+
constructor(providerId: string, message?: string);
|
|
90
|
+
}
|
|
91
|
+
interface EnsureQuotaOptions {
|
|
92
|
+
/** Prefer a network probe even when cache is fresh. */
|
|
93
|
+
prefer?: 'probe' | 'cache';
|
|
94
|
+
/** Override capability.staleAfterMs when deciding cache freshness. */
|
|
95
|
+
maxStaleMs?: number;
|
|
96
|
+
signal?: AbortSignal;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Return a fresh-enough snapshot: cache when valid, else probe when allowed.
|
|
100
|
+
* When only observation is supported and nothing is cached yet, returns null.
|
|
101
|
+
*/
|
|
102
|
+
declare function ensureQuota(quota: ProviderQuota, options?: EnsureQuotaOptions): Promise<ProviderQuotaSnapshot | null>;
|
|
103
|
+
interface CreateProviderQuotaOptions {
|
|
104
|
+
providerId: string;
|
|
105
|
+
canProbe: boolean;
|
|
106
|
+
canObserve?: boolean;
|
|
107
|
+
probeCost?: ProviderQuotaProbeCost;
|
|
108
|
+
staleAfterMs?: number;
|
|
109
|
+
/**
|
|
110
|
+
* Active fetch. Should return plan/windows/account/raw; controller fills
|
|
111
|
+
* providerId, observedAt, source.
|
|
112
|
+
*/
|
|
113
|
+
probe: (options: ProviderQuotaProbeOptions) => Promise<ProviderQuotaProbeResult>;
|
|
114
|
+
/**
|
|
115
|
+
* Optional passive header/body observation. Return null when headers do not
|
|
116
|
+
* carry quota windows.
|
|
117
|
+
*/
|
|
118
|
+
observe?: (input: ProviderQuotaObserveInput) => ProviderQuotaProbeResult | null;
|
|
119
|
+
}
|
|
120
|
+
interface ProviderQuotaProbeResult {
|
|
121
|
+
plan?: ProviderQuotaPlan | null;
|
|
122
|
+
accountLabel?: string | null;
|
|
123
|
+
windows: ProviderQuotaWindow[];
|
|
124
|
+
raw?: unknown;
|
|
125
|
+
}
|
|
126
|
+
/** In-memory latest snapshot + capability wiring for concrete providers. */
|
|
127
|
+
declare function createProviderQuota(options: CreateProviderQuotaOptions): ProviderQuota;
|
|
128
|
+
/** Clamp percent into 0–100 or null. */
|
|
129
|
+
declare function clampUsedPercent(value: unknown): number | null;
|
|
130
|
+
/** used/limit → percent, or null when limit is missing/zero. */
|
|
131
|
+
declare function usedPercentFromRatio(used: number | null | undefined, limit: number | null | undefined): number | null;
|
|
132
|
+
declare function unixSecondsToIso(value: unknown): string | null;
|
|
133
|
+
declare function severityFromUsedPercent(usedPercent: number | null): ProviderQuotaSeverity | null;
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/types.d.ts
|
|
136
|
+
interface ToolDefinition {
|
|
137
|
+
name: string;
|
|
138
|
+
description: string;
|
|
139
|
+
/** JSON Schema describing the tool input. */
|
|
140
|
+
inputSchema: Record<string, unknown>;
|
|
141
|
+
}
|
|
142
|
+
type InferenceItem = {
|
|
143
|
+
type: 'user_message';
|
|
144
|
+
content: UserContentBlock[];
|
|
145
|
+
} | {
|
|
146
|
+
type: 'user_steer';
|
|
147
|
+
turnId: string;
|
|
148
|
+
content: UserContentBlock[];
|
|
149
|
+
} | {
|
|
150
|
+
type: 'assistant_text';
|
|
151
|
+
modelId: string;
|
|
152
|
+
text: string;
|
|
153
|
+
} | {
|
|
154
|
+
type: 'assistant_thinking';
|
|
155
|
+
modelId: string;
|
|
156
|
+
text: string;
|
|
157
|
+
signature: string | null;
|
|
158
|
+
} | {
|
|
159
|
+
type: 'assistant_redacted_thinking';
|
|
160
|
+
modelId: string;
|
|
161
|
+
data: string;
|
|
162
|
+
} | {
|
|
163
|
+
type: 'tool_use';
|
|
164
|
+
modelId: string;
|
|
165
|
+
toolUseId: string;
|
|
166
|
+
toolName: string;
|
|
167
|
+
input: unknown;
|
|
168
|
+
} | {
|
|
169
|
+
type: 'tool_result';
|
|
170
|
+
toolUseId: string;
|
|
171
|
+
output: ToolResultContentBlock[];
|
|
172
|
+
isError: boolean;
|
|
173
|
+
};
|
|
174
|
+
interface InferenceRequest {
|
|
175
|
+
/** Stable id for the owning agent session. */
|
|
176
|
+
sessionId: string;
|
|
177
|
+
/** Stable id for the active user/maintenance turn; shared by provider continuations inside that turn. */
|
|
178
|
+
turnId: string;
|
|
179
|
+
/** Unique id for this concrete provider request. */
|
|
180
|
+
requestId: string;
|
|
181
|
+
modelId: string;
|
|
182
|
+
systemPrompt: string;
|
|
183
|
+
cwd: string;
|
|
184
|
+
items: InferenceItem[];
|
|
185
|
+
tools: ToolDefinition[];
|
|
186
|
+
thinking: ThinkingConfig | null;
|
|
187
|
+
serviceTierId?: string | null;
|
|
188
|
+
cancel: AbortSignal;
|
|
189
|
+
}
|
|
190
|
+
type ProviderEvent = {
|
|
191
|
+
type: 'thinking_start';
|
|
192
|
+
} | {
|
|
193
|
+
type: 'thinking_delta';
|
|
194
|
+
text: string;
|
|
195
|
+
} | {
|
|
196
|
+
type: 'thinking_signature';
|
|
197
|
+
signature: string;
|
|
198
|
+
} | {
|
|
199
|
+
type: 'redacted_thinking';
|
|
200
|
+
data: string;
|
|
201
|
+
} | {
|
|
202
|
+
type: 'text_delta';
|
|
203
|
+
text: string;
|
|
204
|
+
} | {
|
|
205
|
+
type: 'tool_call_requested';
|
|
206
|
+
toolUseId: string;
|
|
207
|
+
toolName: string;
|
|
208
|
+
input: unknown;
|
|
209
|
+
} | {
|
|
210
|
+
type: 'response';
|
|
211
|
+
usage: TokenUsage;
|
|
212
|
+
} | {
|
|
213
|
+
type: 'error';
|
|
214
|
+
message: string;
|
|
215
|
+
code: string | null;
|
|
216
|
+
/** Server-suggested retry delay (e.g. from a Retry-After header), if any. */
|
|
217
|
+
retryAfterMs?: number;
|
|
218
|
+
} | {
|
|
219
|
+
type: 'abort';
|
|
220
|
+
};
|
|
221
|
+
interface InferenceSteer {
|
|
222
|
+
id: string;
|
|
223
|
+
sessionId: string;
|
|
224
|
+
turnId: string;
|
|
225
|
+
content: UserContentBlock[];
|
|
226
|
+
}
|
|
227
|
+
interface ProviderRun extends AsyncIterable<ProviderEvent> {
|
|
228
|
+
steer?(input: InferenceSteer): Promise<void> | void;
|
|
229
|
+
}
|
|
230
|
+
interface AgentProvider {
|
|
231
|
+
run(request: InferenceRequest): ProviderRun;
|
|
232
|
+
/**
|
|
233
|
+
* Releases any resources the provider holds open across turns — e.g. a long-lived CLI
|
|
234
|
+
* subprocess kept alive for a whole session. Called once when the owning session closes.
|
|
235
|
+
*/
|
|
236
|
+
dispose?(): Promise<void> | void;
|
|
237
|
+
}
|
|
238
|
+
interface ProviderSelection {
|
|
239
|
+
providerId: string;
|
|
240
|
+
model: ModelSelection;
|
|
241
|
+
}
|
|
242
|
+
type ProviderAuthState = {
|
|
243
|
+
status: 'unknown';
|
|
244
|
+
message?: string;
|
|
245
|
+
} | {
|
|
246
|
+
status: 'authenticated';
|
|
247
|
+
accountLabel?: string;
|
|
248
|
+
} | {
|
|
249
|
+
status: 'unauthenticated';
|
|
250
|
+
message?: string;
|
|
251
|
+
} | {
|
|
252
|
+
status: 'error';
|
|
253
|
+
message: string;
|
|
254
|
+
};
|
|
255
|
+
interface ProviderAuth {
|
|
256
|
+
status(): Promise<ProviderAuthState> | ProviderAuthState;
|
|
257
|
+
}
|
|
258
|
+
/** Public metadata only — never tokens, cookies, or raw auth files. */
|
|
259
|
+
interface ProviderCredentialInfo {
|
|
260
|
+
/** Stable id within this provider (not globally unique across providers). */
|
|
261
|
+
id: string;
|
|
262
|
+
/** Human label: email, account id, or import tag. */
|
|
263
|
+
label: string;
|
|
264
|
+
/** Optional secondary display (plan name, issuer, …). */
|
|
265
|
+
detail?: string | null;
|
|
266
|
+
/** ISO-8601 when this entry was last imported or refreshed in the pool. */
|
|
267
|
+
updatedAt?: string | null;
|
|
268
|
+
}
|
|
269
|
+
interface ProviderCredentialActive {
|
|
270
|
+
credentialId: string | null;
|
|
271
|
+
/** Same shape as auth status, for the active credential. */
|
|
272
|
+
status: ProviderAuthState;
|
|
273
|
+
}
|
|
274
|
+
interface ProviderCredentialLoginOptions {
|
|
275
|
+
/** Abort the spawned login process. */
|
|
276
|
+
signal?: AbortSignal;
|
|
277
|
+
/** Prefer browser vs device/CLI when the vendor supports both; best-effort. */
|
|
278
|
+
preferBrowser?: boolean;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Login invoke result — status of the *vendor* process only, not a pool id.
|
|
282
|
+
* Demi does not complete OAuth; product should `importDefault` afterwards.
|
|
283
|
+
*/
|
|
284
|
+
type ProviderCredentialLoginResult = {
|
|
285
|
+
status: 'completed';
|
|
286
|
+
} | {
|
|
287
|
+
status: 'cancelled';
|
|
288
|
+
} | {
|
|
289
|
+
status: 'unavailable';
|
|
290
|
+
message: string;
|
|
291
|
+
} | {
|
|
292
|
+
status: 'failed';
|
|
293
|
+
message: string;
|
|
294
|
+
};
|
|
295
|
+
/**
|
|
296
|
+
* Provider-specific add payloads. Concrete packages document accepted variants.
|
|
297
|
+
* Do not put secrets on browser-visible control protocols.
|
|
298
|
+
*/
|
|
299
|
+
type ProviderCredentialAddInput = {
|
|
300
|
+
[key: string]: unknown;
|
|
301
|
+
};
|
|
302
|
+
type ProviderCredentialsCapability = {
|
|
303
|
+
mode: 'none';
|
|
304
|
+
} | {
|
|
305
|
+
mode: 'supported';
|
|
306
|
+
/** Can spawn / open vendor login (`beginLogin`). */
|
|
307
|
+
canBeginLogin?: boolean;
|
|
308
|
+
/** Can import from the vendor default location into the pool. */
|
|
309
|
+
canImportDefault?: boolean;
|
|
310
|
+
/** Can register externally supplied material (`add`). */
|
|
311
|
+
canAdd?: boolean;
|
|
312
|
+
/** Pool can hold more than one credential. */
|
|
313
|
+
multi?: boolean;
|
|
314
|
+
};
|
|
315
|
+
/**
|
|
316
|
+
* Multi-credential pool + process-global active switch.
|
|
317
|
+
* See `docs/provider-global-credentials.md`.
|
|
318
|
+
*/
|
|
319
|
+
interface ProviderCredentials {
|
|
320
|
+
capability(): ProviderCredentialsCapability;
|
|
321
|
+
list(): Promise<ProviderCredentialInfo[]> | ProviderCredentialInfo[];
|
|
322
|
+
getActive(): Promise<ProviderCredentialActive> | ProviderCredentialActive;
|
|
323
|
+
/**
|
|
324
|
+
* Make `credentialId` the process-global active credential for this provider.
|
|
325
|
+
* Subsequent auth / quota / inference use it.
|
|
326
|
+
*/
|
|
327
|
+
setActive(credentialId: string): Promise<ProviderCredentialActive> | ProviderCredentialActive;
|
|
328
|
+
/**
|
|
329
|
+
* Invoke the vendor’s own login flow. Does not complete OAuth inside demi
|
|
330
|
+
* and does not return a credential id.
|
|
331
|
+
*/
|
|
332
|
+
beginLogin?(options?: ProviderCredentialLoginOptions): Promise<ProviderCredentialLoginResult>;
|
|
333
|
+
/**
|
|
334
|
+
* Snapshot current vendor-default material into the demi pool.
|
|
335
|
+
* Assigns a stable `id` and returns public metadata (no secrets).
|
|
336
|
+
*/
|
|
337
|
+
importDefault?(): Promise<ProviderCredentialInfo>;
|
|
338
|
+
/** Register material supplied by the product. */
|
|
339
|
+
add?(input: ProviderCredentialAddInput): Promise<ProviderCredentialInfo>;
|
|
340
|
+
/** Remove a pool entry. */
|
|
341
|
+
remove?(credentialId: string): Promise<void>;
|
|
342
|
+
}
|
|
343
|
+
type ProviderRuntimeState = {
|
|
344
|
+
status: 'unknown';
|
|
345
|
+
message?: string;
|
|
346
|
+
} | {
|
|
347
|
+
status: 'ready';
|
|
348
|
+
message?: string;
|
|
349
|
+
} | {
|
|
350
|
+
status: 'unavailable';
|
|
351
|
+
message: string;
|
|
352
|
+
} | {
|
|
353
|
+
status: 'error';
|
|
354
|
+
message: string;
|
|
355
|
+
};
|
|
356
|
+
interface Provider {
|
|
357
|
+
id: string;
|
|
358
|
+
displayName: string;
|
|
359
|
+
auth?: ProviderAuth;
|
|
360
|
+
/** Optional subscription / rate-limit quota surface (`@demicodes/provider` quota helpers). */
|
|
361
|
+
quota?: ProviderQuota;
|
|
362
|
+
/** Optional multi-credential pool + global active switch. */
|
|
363
|
+
credentials?: ProviderCredentials;
|
|
364
|
+
state?(): Promise<ProviderRuntimeState> | ProviderRuntimeState;
|
|
365
|
+
listModels?(): Promise<ProviderModelList> | ProviderModelList;
|
|
366
|
+
}
|
|
367
|
+
interface ProviderRuntimeFactory {
|
|
368
|
+
createRuntime(selection: ProviderSelection): Promise<AgentProvider> | AgentProvider;
|
|
369
|
+
}
|
|
370
|
+
interface ProviderFactoryDefinition extends Provider {
|
|
371
|
+
createRuntime(selection: ProviderSelection): Promise<AgentProvider> | AgentProvider;
|
|
372
|
+
}
|
|
373
|
+
interface ProviderModelCost {
|
|
374
|
+
input: number | null;
|
|
375
|
+
output: number | null;
|
|
376
|
+
cacheRead: number | null;
|
|
377
|
+
cacheWrite: number | null;
|
|
378
|
+
}
|
|
379
|
+
interface ProviderServiceTier {
|
|
380
|
+
id: string;
|
|
381
|
+
label: string;
|
|
382
|
+
description?: string;
|
|
383
|
+
}
|
|
384
|
+
interface ProviderModel {
|
|
385
|
+
providerId: string;
|
|
386
|
+
id: string;
|
|
387
|
+
displayName: string;
|
|
388
|
+
description?: string;
|
|
389
|
+
contextWindow: number | null;
|
|
390
|
+
outputLimit: number | null;
|
|
391
|
+
supportsTools: boolean | null;
|
|
392
|
+
supportsAttachments: boolean | null;
|
|
393
|
+
/** Whether the model accepts native video input (not frame extraction). Most models
|
|
394
|
+
* (all current Anthropic/Claude Code models) do not — their API has no video block.
|
|
395
|
+
* Optional: unset/undefined means "no video", so existing catalogs need no change. */
|
|
396
|
+
supportsVideo?: boolean | null;
|
|
397
|
+
supportsReasoning: boolean | null;
|
|
398
|
+
supportedThinkingEfforts: ThinkingEffort[] | null;
|
|
399
|
+
defaultThinkingEffort: ThinkingEffort | null;
|
|
400
|
+
/** Whether thinking can be turned off entirely. Some transports (e.g. the Claude Code CLI, whose
|
|
401
|
+
* `--effort` flag only accepts low|medium|high|xhigh|max) can level thinking but never disable it,
|
|
402
|
+
* so the UI must not offer a "no reasoning" option. Defaults to true (optional) when unset. */
|
|
403
|
+
canDisableThinking?: boolean | null;
|
|
404
|
+
serviceTiers?: ProviderServiceTier[] | null;
|
|
405
|
+
defaultServiceTierId?: string | null;
|
|
406
|
+
cost?: ProviderModelCost;
|
|
407
|
+
sourceFetchedAt: string;
|
|
408
|
+
stale: boolean;
|
|
409
|
+
}
|
|
410
|
+
interface ProviderModelList {
|
|
411
|
+
providerId: string;
|
|
412
|
+
models: ProviderModel[];
|
|
413
|
+
defaultModelId: string | null;
|
|
414
|
+
warnings: string[];
|
|
415
|
+
sourceFetchedAt: string;
|
|
416
|
+
stale: boolean;
|
|
417
|
+
}
|
|
418
|
+
type ModelPolicy = {
|
|
419
|
+
include?: string[];
|
|
420
|
+
exclude?: string[];
|
|
421
|
+
default?: string;
|
|
422
|
+
};
|
|
423
|
+
//#endregion
|
|
424
|
+
export { ProviderQuotaCapability as A, ProviderQuotaWindow as B, ProviderRuntimeState as C, CreateProviderQuotaOptions as D, ToolDefinition as E, ProviderQuotaProbeResult as F, severityFromUsedPercent as G, clampUsedPercent as H, ProviderQuotaSeverity as I, unixSecondsToIso as K, ProviderQuotaSnapshot as L, ProviderQuotaPlan as M, ProviderQuotaProbeCost as N, EnsureQuotaOptions as O, ProviderQuotaProbeOptions as P, ProviderQuotaSource as R, ProviderRuntimeFactory as S, ProviderServiceTier as T, createProviderQuota as U, ProviderQuotaWindowUnit as V, ensureQuota as W, ProviderFactoryDefinition as _, ModelPolicy as a, ProviderModelList as b, ProviderAuthState as c, ProviderCredentialInfo as d, ProviderCredentialLoginOptions as f, ProviderEvent as g, ProviderCredentialsCapability as h, InferenceSteer as i, ProviderQuotaObserveInput as j, ProviderQuota as k, ProviderCredentialActive as l, ProviderCredentials as m, InferenceItem as n, Provider as o, ProviderCredentialLoginResult as p, usedPercentFromRatio as q, InferenceRequest as r, ProviderAuth as s, AgentProvider as t, ProviderCredentialAddInput as u, ProviderModel as v, ProviderSelection as w, ProviderRun as x, ProviderModelCost as y, ProviderQuotaUnsupportedError as z };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@demicodes/provider",
|
|
3
3
|
"description": "Provider contract and shared building blocks for Demi inference adapters.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
@@ -14,11 +14,16 @@
|
|
|
14
14
|
"development": "./src/testing.ts",
|
|
15
15
|
"types": "./dist/testing.d.mts",
|
|
16
16
|
"import": "./dist/testing.mjs"
|
|
17
|
+
},
|
|
18
|
+
"./credentials-pool": {
|
|
19
|
+
"development": "./src/credentials-pool.ts",
|
|
20
|
+
"types": "./dist/credentials-pool.d.mts",
|
|
21
|
+
"import": "./dist/credentials-pool.mjs"
|
|
17
22
|
}
|
|
18
23
|
},
|
|
19
24
|
"dependencies": {
|
|
20
|
-
"@demicodes/core": "
|
|
21
|
-
"@demicodes/utils": "
|
|
25
|
+
"@demicodes/core": "0.2.0",
|
|
26
|
+
"@demicodes/utils": "0.2.0"
|
|
22
27
|
},
|
|
23
28
|
"license": "Apache-2.0",
|
|
24
29
|
"main": "./dist/index.mjs",
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { ModelSelection, ThinkingConfig, ThinkingEffort, TokenUsage, ToolResultContentBlock, UserContentBlock } from "@demicodes/core";
|
|
2
|
-
|
|
3
|
-
//#region src/types.d.ts
|
|
4
|
-
interface ToolDefinition {
|
|
5
|
-
name: string;
|
|
6
|
-
description: string;
|
|
7
|
-
/** JSON Schema describing the tool input. */
|
|
8
|
-
inputSchema: Record<string, unknown>;
|
|
9
|
-
}
|
|
10
|
-
type InferenceItem = {
|
|
11
|
-
type: 'user_message';
|
|
12
|
-
content: UserContentBlock[];
|
|
13
|
-
} | {
|
|
14
|
-
type: 'user_steer';
|
|
15
|
-
turnId: string;
|
|
16
|
-
content: UserContentBlock[];
|
|
17
|
-
} | {
|
|
18
|
-
type: 'assistant_text';
|
|
19
|
-
modelId: string;
|
|
20
|
-
text: string;
|
|
21
|
-
} | {
|
|
22
|
-
type: 'assistant_thinking';
|
|
23
|
-
modelId: string;
|
|
24
|
-
text: string;
|
|
25
|
-
signature: string | null;
|
|
26
|
-
} | {
|
|
27
|
-
type: 'assistant_redacted_thinking';
|
|
28
|
-
modelId: string;
|
|
29
|
-
data: string;
|
|
30
|
-
} | {
|
|
31
|
-
type: 'tool_use';
|
|
32
|
-
modelId: string;
|
|
33
|
-
toolUseId: string;
|
|
34
|
-
toolName: string;
|
|
35
|
-
input: unknown;
|
|
36
|
-
} | {
|
|
37
|
-
type: 'tool_result';
|
|
38
|
-
toolUseId: string;
|
|
39
|
-
output: ToolResultContentBlock[];
|
|
40
|
-
isError: boolean;
|
|
41
|
-
};
|
|
42
|
-
interface InferenceRequest {
|
|
43
|
-
/** Stable id for the owning agent session. */
|
|
44
|
-
sessionId: string;
|
|
45
|
-
/** Stable id for the active user/maintenance turn; shared by provider continuations inside that turn. */
|
|
46
|
-
turnId: string;
|
|
47
|
-
/** Unique id for this concrete provider request. */
|
|
48
|
-
requestId: string;
|
|
49
|
-
modelId: string;
|
|
50
|
-
systemPrompt: string;
|
|
51
|
-
cwd: string;
|
|
52
|
-
items: InferenceItem[];
|
|
53
|
-
tools: ToolDefinition[];
|
|
54
|
-
thinking: ThinkingConfig | null;
|
|
55
|
-
serviceTierId?: string | null;
|
|
56
|
-
cancel: AbortSignal;
|
|
57
|
-
}
|
|
58
|
-
type ProviderEvent = {
|
|
59
|
-
type: 'thinking_start';
|
|
60
|
-
} | {
|
|
61
|
-
type: 'thinking_delta';
|
|
62
|
-
text: string;
|
|
63
|
-
} | {
|
|
64
|
-
type: 'thinking_signature';
|
|
65
|
-
signature: string;
|
|
66
|
-
} | {
|
|
67
|
-
type: 'redacted_thinking';
|
|
68
|
-
data: string;
|
|
69
|
-
} | {
|
|
70
|
-
type: 'text_delta';
|
|
71
|
-
text: string;
|
|
72
|
-
} | {
|
|
73
|
-
type: 'tool_call_requested';
|
|
74
|
-
toolUseId: string;
|
|
75
|
-
toolName: string;
|
|
76
|
-
input: unknown;
|
|
77
|
-
} | {
|
|
78
|
-
type: 'response';
|
|
79
|
-
usage: TokenUsage;
|
|
80
|
-
} | {
|
|
81
|
-
type: 'error';
|
|
82
|
-
message: string;
|
|
83
|
-
code: string | null; /** Server-suggested retry delay (e.g. from a Retry-After header), if any. */
|
|
84
|
-
retryAfterMs?: number;
|
|
85
|
-
} | {
|
|
86
|
-
type: 'abort';
|
|
87
|
-
};
|
|
88
|
-
interface InferenceSteer {
|
|
89
|
-
id: string;
|
|
90
|
-
sessionId: string;
|
|
91
|
-
turnId: string;
|
|
92
|
-
content: UserContentBlock[];
|
|
93
|
-
}
|
|
94
|
-
interface ProviderRun extends AsyncIterable<ProviderEvent> {
|
|
95
|
-
steer?(input: InferenceSteer): Promise<void> | void;
|
|
96
|
-
}
|
|
97
|
-
interface AgentProvider {
|
|
98
|
-
run(request: InferenceRequest): ProviderRun;
|
|
99
|
-
/**
|
|
100
|
-
* Releases any resources the provider holds open across turns — e.g. a long-lived CLI
|
|
101
|
-
* subprocess kept alive for a whole session. Called once when the owning session closes.
|
|
102
|
-
*/
|
|
103
|
-
dispose?(): Promise<void> | void;
|
|
104
|
-
}
|
|
105
|
-
interface ProviderSelection {
|
|
106
|
-
providerId: string;
|
|
107
|
-
model: ModelSelection;
|
|
108
|
-
}
|
|
109
|
-
type ProviderAuthState = {
|
|
110
|
-
status: 'unknown';
|
|
111
|
-
message?: string;
|
|
112
|
-
} | {
|
|
113
|
-
status: 'authenticated';
|
|
114
|
-
accountLabel?: string;
|
|
115
|
-
} | {
|
|
116
|
-
status: 'unauthenticated';
|
|
117
|
-
message?: string;
|
|
118
|
-
} | {
|
|
119
|
-
status: 'error';
|
|
120
|
-
message: string;
|
|
121
|
-
};
|
|
122
|
-
interface ProviderAuth {
|
|
123
|
-
status(): Promise<ProviderAuthState> | ProviderAuthState;
|
|
124
|
-
}
|
|
125
|
-
type ProviderRuntimeState = {
|
|
126
|
-
status: 'unknown';
|
|
127
|
-
message?: string;
|
|
128
|
-
} | {
|
|
129
|
-
status: 'ready';
|
|
130
|
-
message?: string;
|
|
131
|
-
} | {
|
|
132
|
-
status: 'unavailable';
|
|
133
|
-
message: string;
|
|
134
|
-
} | {
|
|
135
|
-
status: 'error';
|
|
136
|
-
message: string;
|
|
137
|
-
};
|
|
138
|
-
interface Provider {
|
|
139
|
-
id: string;
|
|
140
|
-
displayName: string;
|
|
141
|
-
auth?: ProviderAuth;
|
|
142
|
-
state?(): Promise<ProviderRuntimeState> | ProviderRuntimeState;
|
|
143
|
-
listModels?(): Promise<ProviderModelList> | ProviderModelList;
|
|
144
|
-
}
|
|
145
|
-
interface ProviderRuntimeFactory {
|
|
146
|
-
createRuntime(selection: ProviderSelection): Promise<AgentProvider> | AgentProvider;
|
|
147
|
-
}
|
|
148
|
-
interface ProviderFactoryDefinition extends Provider {
|
|
149
|
-
createRuntime(selection: ProviderSelection): Promise<AgentProvider> | AgentProvider;
|
|
150
|
-
}
|
|
151
|
-
interface ProviderModelCost {
|
|
152
|
-
input: number | null;
|
|
153
|
-
output: number | null;
|
|
154
|
-
cacheRead: number | null;
|
|
155
|
-
cacheWrite: number | null;
|
|
156
|
-
}
|
|
157
|
-
interface ProviderServiceTier {
|
|
158
|
-
id: string;
|
|
159
|
-
label: string;
|
|
160
|
-
description?: string;
|
|
161
|
-
}
|
|
162
|
-
interface ProviderModel {
|
|
163
|
-
providerId: string;
|
|
164
|
-
id: string;
|
|
165
|
-
displayName: string;
|
|
166
|
-
description?: string;
|
|
167
|
-
contextWindow: number | null;
|
|
168
|
-
outputLimit: number | null;
|
|
169
|
-
supportsTools: boolean | null;
|
|
170
|
-
supportsAttachments: boolean | null;
|
|
171
|
-
supportsReasoning: boolean | null;
|
|
172
|
-
supportedThinkingEfforts: ThinkingEffort[] | null;
|
|
173
|
-
defaultThinkingEffort: ThinkingEffort | null;
|
|
174
|
-
/** Whether thinking can be turned off entirely. Some transports (e.g. the Claude Code CLI, whose
|
|
175
|
-
* `--effort` flag only accepts low|medium|high|xhigh|max) can level thinking but never disable it,
|
|
176
|
-
* so the UI must not offer a "no reasoning" option. Defaults to true (optional) when unset. */
|
|
177
|
-
canDisableThinking?: boolean | null;
|
|
178
|
-
serviceTiers?: ProviderServiceTier[] | null;
|
|
179
|
-
defaultServiceTierId?: string | null;
|
|
180
|
-
cost?: ProviderModelCost;
|
|
181
|
-
sourceFetchedAt: string;
|
|
182
|
-
stale: boolean;
|
|
183
|
-
}
|
|
184
|
-
interface ProviderModelList {
|
|
185
|
-
providerId: string;
|
|
186
|
-
models: ProviderModel[];
|
|
187
|
-
defaultModelId: string | null;
|
|
188
|
-
warnings: string[];
|
|
189
|
-
sourceFetchedAt: string;
|
|
190
|
-
stale: boolean;
|
|
191
|
-
}
|
|
192
|
-
type ModelPolicy = {
|
|
193
|
-
include?: string[];
|
|
194
|
-
exclude?: string[];
|
|
195
|
-
default?: string;
|
|
196
|
-
};
|
|
197
|
-
//#endregion
|
|
198
|
-
export { ProviderSelection as _, ModelPolicy as a, ProviderAuthState as c, ProviderModel as d, ProviderModelCost as f, ProviderRuntimeState as g, ProviderRuntimeFactory as h, InferenceSteer as i, ProviderEvent as l, ProviderRun as m, InferenceItem as n, Provider as o, ProviderModelList as p, InferenceRequest as r, ProviderAuth as s, AgentProvider as t, ProviderFactoryDefinition as u, ProviderServiceTier as v, ToolDefinition as y };
|