@providerkit/core 0.22.0 → 0.24.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 +29 -7
- package/dist/auth/flows.d.ts.map +1 -1
- package/dist/auth/flows.js +5 -5
- package/dist/auth/flows.js.map +1 -1
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +1 -0
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/oauth.d.ts +12 -0
- package/dist/auth/oauth.d.ts.map +1 -1
- package/dist/auth/oauth.js +19 -1
- package/dist/auth/oauth.js.map +1 -1
- package/dist/auth/token-source.d.ts +9 -3
- package/dist/auth/token-source.d.ts.map +1 -1
- package/dist/auth/token-source.js +24 -9
- package/dist/auth/token-source.js.map +1 -1
- package/dist/auth/with-token.d.ts +32 -0
- package/dist/auth/with-token.d.ts.map +1 -0
- package/dist/auth/with-token.js +88 -0
- package/dist/auth/with-token.js.map +1 -0
- package/dist/context.d.ts +39 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +119 -0
- package/dist/context.js.map +1 -1
- package/dist/errors.d.ts +12 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +44 -5
- package/dist/errors.js.map +1 -1
- package/dist/fallback.d.ts +45 -1
- package/dist/fallback.d.ts.map +1 -1
- package/dist/fallback.js +138 -75
- package/dist/fallback.js.map +1 -1
- package/dist/gate.d.ts +29 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +96 -0
- package/dist/gate.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/key-pool.d.ts +21 -4
- package/dist/key-pool.d.ts.map +1 -1
- package/dist/key-pool.js +43 -12
- package/dist/key-pool.js.map +1 -1
- package/dist/presets.d.ts +7 -2
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +12 -2
- package/dist/presets.js.map +1 -1
- package/dist/providers/anthropic.d.ts +7 -0
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +83 -26
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/factory.d.ts +26 -0
- package/dist/providers/factory.d.ts.map +1 -1
- package/dist/providers/factory.js +41 -9
- package/dist/providers/factory.js.map +1 -1
- package/dist/providers/gemini.d.ts +6 -0
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +102 -27
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/openai.d.ts +7 -0
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +66 -15
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/responses.d.ts +11 -0
- package/dist/providers/responses.d.ts.map +1 -1
- package/dist/providers/responses.js +101 -53
- package/dist/providers/responses.js.map +1 -1
- package/dist/rate-limit.d.ts +10 -0
- package/dist/rate-limit.d.ts.map +1 -1
- package/dist/rate-limit.js +7 -1
- package/dist/rate-limit.js.map +1 -1
- package/dist/registry.d.ts +105 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +291 -0
- package/dist/registry.js.map +1 -0
- package/dist/retry.d.ts +11 -0
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +25 -12
- package/dist/retry.js.map +1 -1
- package/dist/tool-args.d.ts +22 -0
- package/dist/tool-args.d.ts.map +1 -1
- package/dist/tool-args.js +28 -0
- package/dist/tool-args.js.map +1 -1
- package/dist/tools.d.ts +8 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +2 -2
- package/dist/tools.js.map +1 -1
- package/dist/transport.d.ts +34 -4
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +77 -16
- package/dist/transport.js.map +1 -1
- package/dist/turn.d.ts +55 -0
- package/dist/turn.d.ts.map +1 -0
- package/dist/turn.js +125 -0
- package/dist/turn.js.map +1 -0
- package/dist/types.d.ts +21 -22
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -53
- package/dist/types.js.map +1 -1
- package/dist/watchdog.d.ts +2 -0
- package/dist/watchdog.d.ts.map +1 -1
- package/dist/watchdog.js +25 -6
- package/dist/watchdog.js.map +1 -1
- package/package.json +1 -1
- package/src/auth/flows.ts +5 -4
- package/src/auth/index.ts +1 -0
- package/src/auth/oauth.ts +23 -1
- package/src/auth/token-source.ts +30 -11
- package/src/auth/with-token.ts +100 -0
- package/src/context.ts +137 -2
- package/src/errors.ts +46 -6
- package/src/fallback.ts +173 -75
- package/src/gate.ts +152 -0
- package/src/index.ts +3 -0
- package/src/key-pool.ts +45 -13
- package/src/presets.ts +12 -2
- package/src/providers/anthropic.ts +93 -25
- package/src/providers/factory.ts +66 -21
- package/src/providers/gemini.ts +102 -28
- package/src/providers/openai.ts +71 -14
- package/src/providers/responses.ts +116 -51
- package/src/rate-limit.ts +31 -3
- package/src/registry.ts +420 -0
- package/src/retry.ts +41 -10
- package/src/tool-args.ts +44 -0
- package/src/tools.ts +10 -2
- package/src/transport.ts +97 -17
- package/src/turn.ts +166 -0
- package/src/types.ts +21 -62
- package/src/watchdog.ts +25 -6
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { type ErrorKind } from "./errors.ts";
|
|
2
|
+
import { type FallbackOptions } from "./fallback.ts";
|
|
3
|
+
import { type KeyPoolOptions, type KeyTier } from "./key-pool.ts";
|
|
4
|
+
import { type ProviderPresetId } from "./presets.ts";
|
|
5
|
+
import { type PresetAdapterConfig } from "./providers/factory.ts";
|
|
6
|
+
import type { RateLimitWindow } from "./rate-limit.ts";
|
|
7
|
+
import type { Effort, Provider } from "./types.ts";
|
|
8
|
+
import { type WatchdogOptions } from "./watchdog.ts";
|
|
9
|
+
import type { TokenSource } from "./auth/token-source.ts";
|
|
10
|
+
/** How a connection signs its calls: exactly one of the three. */
|
|
11
|
+
export type ConnectionCredential = {
|
|
12
|
+
apiKey: string;
|
|
13
|
+
keys?: never;
|
|
14
|
+
token?: never;
|
|
15
|
+
}
|
|
16
|
+
/** Several keys for one account, rotated by one `KeyPool` per connection. */
|
|
17
|
+
| {
|
|
18
|
+
keys: KeyPoolOptions;
|
|
19
|
+
apiKey?: never;
|
|
20
|
+
token?: never;
|
|
21
|
+
}
|
|
22
|
+
/** A signed-in user's token (`@providerkit/core/auth`), renewed on a 401. */
|
|
23
|
+
| {
|
|
24
|
+
token: TokenSource;
|
|
25
|
+
apiKey?: never;
|
|
26
|
+
keys?: never;
|
|
27
|
+
};
|
|
28
|
+
export type ConnectionConfig = Omit<PresetAdapterConfig, "apiKey" | "instanceSessionId"> & ConnectionCredential & {
|
|
29
|
+
preset: ProviderPresetId;
|
|
30
|
+
/** The models a bare ref (`"go"`) runs, in order. Absent: `model`, then the
|
|
31
|
+
* preset's `rotation`, then its `defaultModel`. */
|
|
32
|
+
models?: readonly string[];
|
|
33
|
+
/** At most this many calls at once on this connection, in every chain and
|
|
34
|
+
* view that uses it. The rest wait in line. Absent: no limit. */
|
|
35
|
+
maxConcurrent?: number;
|
|
36
|
+
/** Replaces the registry's `watchdog` for this connection; `false` turns
|
|
37
|
+
* it off. */
|
|
38
|
+
watchdog?: WatchdogOptions | false;
|
|
39
|
+
};
|
|
40
|
+
type PoolCooldownInfo = Parameters<NonNullable<FallbackOptions<Provider>["onCooldown"]>>[0];
|
|
41
|
+
/** What a chain's pool reports when it benches a candidate, plus the
|
|
42
|
+
* candidate's ref (`"go/glm-5.3"`). The candidate's own `id` is its preset
|
|
43
|
+
* id, which two connections on one preset share. */
|
|
44
|
+
export type RegistryCooldownInfo = PoolCooldownInfo & {
|
|
45
|
+
ref: string;
|
|
46
|
+
};
|
|
47
|
+
export interface RegistryOptions {
|
|
48
|
+
connections: Record<string, ConnectionConfig>;
|
|
49
|
+
/** Named lists of refs, tried in order: `"conn/model"`, or a bare `"conn"`
|
|
50
|
+
* for its models. A chain can't name another chain. */
|
|
51
|
+
chains?: Record<string, readonly string[]>;
|
|
52
|
+
/** Every candidate's watchdog. On by default with the package's clocks;
|
|
53
|
+
* `false` turns it off. A connection's own `watchdog` replaces it. */
|
|
54
|
+
watchdog?: WatchdogOptions | false;
|
|
55
|
+
/** One set for every chain, because every chain shares one cooldown store:
|
|
56
|
+
* a bench set by one is honoured by the others. */
|
|
57
|
+
fallback?: Omit<FallbackOptions<Provider>, "cooldowns" | "onCooldown"> & {
|
|
58
|
+
onCooldown?: (info: RegistryCooldownInfo) => void;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export interface ViewOptions {
|
|
62
|
+
/** Every call's effort, unless the call names its own. */
|
|
63
|
+
effort?: Effort;
|
|
64
|
+
/** Every call's output ceiling, unless the call names its own. */
|
|
65
|
+
maxTokens?: number;
|
|
66
|
+
}
|
|
67
|
+
export interface CandidateStatus {
|
|
68
|
+
ref: string;
|
|
69
|
+
/** When its bench ends; 0 when it has none. A time already past means its
|
|
70
|
+
* next call is the probe that lifts the bench. */
|
|
71
|
+
retryAtMs: number;
|
|
72
|
+
probing: boolean;
|
|
73
|
+
kind?: ErrorKind;
|
|
74
|
+
window?: RateLimitWindow;
|
|
75
|
+
}
|
|
76
|
+
export interface ConnectionStatus {
|
|
77
|
+
gate?: {
|
|
78
|
+
max: number;
|
|
79
|
+
held: number;
|
|
80
|
+
waiting: number;
|
|
81
|
+
};
|
|
82
|
+
keys?: Array<{
|
|
83
|
+
tier: KeyTier;
|
|
84
|
+
evictedUntil: number;
|
|
85
|
+
}>;
|
|
86
|
+
/** The candidates built so far: one is built the first time a ref needs it. */
|
|
87
|
+
candidates: CandidateStatus[];
|
|
88
|
+
}
|
|
89
|
+
export interface Registry {
|
|
90
|
+
/**
|
|
91
|
+
* A provider for a chain name, a `"conn/model"` ref or a bare `"conn"`.
|
|
92
|
+
* Keep it as long as you like: it looks its chain up on every call, so
|
|
93
|
+
* `update` reaches it. Throws on a name it doesn't know.
|
|
94
|
+
*/
|
|
95
|
+
get(ref: string, opts?: ViewOptions): Provider;
|
|
96
|
+
/** Add a connection, or replace one. An equal config changes nothing, so
|
|
97
|
+
* calling this on every request is cheap. */
|
|
98
|
+
update(name: string, config: ConnectionConfig): void;
|
|
99
|
+
/** Delete a connection. A chain that names it fails on its next call. */
|
|
100
|
+
remove(name: string): void;
|
|
101
|
+
status(): Record<string, ConnectionStatus>;
|
|
102
|
+
}
|
|
103
|
+
export declare function createRegistry(options: RegistryOptions): Registry;
|
|
104
|
+
export {};
|
|
105
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
// Providers and credentials, set up once per app.
|
|
2
|
+
//
|
|
3
|
+
// Every app on this package wrote the same block: build each provider from
|
|
4
|
+
// env, wrap it in a watchdog, chain a few into a fallback pool, keep that pool
|
|
5
|
+
// alive so its cooldowns survive, and cache it somewhere. The OpenCode Go
|
|
6
|
+
// chain alone was copied seven times. Where an app put the watchdog or the
|
|
7
|
+
// error envelope together by hand, it got it wrong (AGENTS.md, "A bump is an
|
|
8
|
+
// audit too"). A registry names each connection once, and `get` hands back
|
|
9
|
+
// the composition already assembled.
|
|
10
|
+
//
|
|
11
|
+
// The layers, outside in: the view (per-call effort and `maxTokens`), the
|
|
12
|
+
// fallback pool when there is more than one candidate, then per candidate the
|
|
13
|
+
// gate, the watchdog and the adapter.
|
|
14
|
+
//
|
|
15
|
+
// ponytail: one registry per process. Per-tenant keys would need one registry
|
|
16
|
+
// per tenant, and no app needs that yet.
|
|
17
|
+
import { ProviderError } from "./errors.js";
|
|
18
|
+
import { withFallbackProviders } from "./fallback.js";
|
|
19
|
+
import { createGate, withGate } from "./gate.js";
|
|
20
|
+
import { KeyPool, withKeyPool } from "./key-pool.js";
|
|
21
|
+
import { PROVIDER_PRESETS } from "./presets.js";
|
|
22
|
+
import { presetAdapter } from "./providers/factory.js";
|
|
23
|
+
import { withWatchdog } from "./watchdog.js";
|
|
24
|
+
// A value import from the `auth/` subpath, and a cheap one: with-token.ts
|
|
25
|
+
// imports only errors.ts at runtime and the sign-in flows as types, so the
|
|
26
|
+
// main entry gains these few lines and none of oauth, device or flows.
|
|
27
|
+
import { withToken } from "./auth/with-token.js";
|
|
28
|
+
export function createRegistry(options) {
|
|
29
|
+
const connections = new Map();
|
|
30
|
+
const chainRefs = new Map(Object.entries(options.chains ?? {}));
|
|
31
|
+
/** Built chains by ref, with the connections each one uses. */
|
|
32
|
+
const built = new Map();
|
|
33
|
+
// One store for every chain, so a candidate benched in one is benched in
|
|
34
|
+
// all. Weak, so a candidate dropped by `update` takes its bench with it.
|
|
35
|
+
const cooldowns = new WeakMap();
|
|
36
|
+
const refOf = new WeakMap();
|
|
37
|
+
const { onCooldown, ...fallback } = options.fallback ?? {};
|
|
38
|
+
const poolOptions = {
|
|
39
|
+
...fallback,
|
|
40
|
+
cooldowns,
|
|
41
|
+
...(onCooldown
|
|
42
|
+
? {
|
|
43
|
+
onCooldown: (info) => onCooldown({ ...info, ref: refOf.get(info.candidate) ?? info.candidate.id }),
|
|
44
|
+
}
|
|
45
|
+
: {}),
|
|
46
|
+
};
|
|
47
|
+
for (const [name, refs] of chainRefs) {
|
|
48
|
+
if (!name || name.includes("/")) {
|
|
49
|
+
throw new Error(`[providerkit] Chain name "${name}" can't be empty or contain "/".`);
|
|
50
|
+
}
|
|
51
|
+
if (refs.length === 0)
|
|
52
|
+
throw new Error(`[providerkit] Chain "${name}" lists no refs.`);
|
|
53
|
+
}
|
|
54
|
+
// `open` refuses a connection named like a chain.
|
|
55
|
+
for (const [name, config] of Object.entries(options.connections)) {
|
|
56
|
+
connections.set(name, open(name, config));
|
|
57
|
+
}
|
|
58
|
+
// Checked once every connection exists, so a chain may name any of them.
|
|
59
|
+
for (const name of chainRefs.keys())
|
|
60
|
+
members(name);
|
|
61
|
+
function open(name, config, current) {
|
|
62
|
+
if (!name || name.includes("/")) {
|
|
63
|
+
throw new Error(`[providerkit] Connection name "${name}" can't be empty or contain "/".`);
|
|
64
|
+
}
|
|
65
|
+
if (chainRefs.has(name)) {
|
|
66
|
+
throw new Error(`[providerkit] "${name}" names both a chain and a connection. Rename one of them.`);
|
|
67
|
+
}
|
|
68
|
+
if (!(config.preset in PROVIDER_PRESETS)) {
|
|
69
|
+
throw new Error(`[providerkit] Connection "${name}" names an unknown preset "${config.preset}".`);
|
|
70
|
+
}
|
|
71
|
+
const credentials = [config.apiKey, config.keys, config.token].filter((c) => c !== undefined);
|
|
72
|
+
if (credentials.length !== 1) {
|
|
73
|
+
throw new Error(`[providerkit] Connection "${name}" needs exactly one of apiKey, keys or token. ` +
|
|
74
|
+
`It has ${credentials.length}.`);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
config,
|
|
78
|
+
gate: gateFor(config, current),
|
|
79
|
+
keyPool: config.keys ? new KeyPool(name, config.keys) : undefined,
|
|
80
|
+
candidates: new Map(),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** The (connection, model) pairs a ref names, in order, duplicates dropped. */
|
|
84
|
+
function members(ref) {
|
|
85
|
+
const inChain = chainRefs.get(ref);
|
|
86
|
+
const out = new Map();
|
|
87
|
+
for (const member of inChain ?? [ref]) {
|
|
88
|
+
const slash = member.indexOf("/");
|
|
89
|
+
const name = slash < 0 ? member : member.slice(0, slash);
|
|
90
|
+
if (inChain && chainRefs.has(member)) {
|
|
91
|
+
throw new Error(`[providerkit] Chain "${ref}" names chain "${member}". List its refs instead.`);
|
|
92
|
+
}
|
|
93
|
+
const connection = connections.get(name);
|
|
94
|
+
if (!connection) {
|
|
95
|
+
throw new Error(inChain
|
|
96
|
+
? `[providerkit] Chain "${ref}" names connection "${name}", which doesn't exist.`
|
|
97
|
+
: `[providerkit] "${ref}" is not a chain or a connection. ` +
|
|
98
|
+
`Known: ${[...chainRefs.keys(), ...connections.keys()].join(", ")}.`);
|
|
99
|
+
}
|
|
100
|
+
const models = slash < 0 ? modelsOf(name, connection.config) : [member.slice(slash + 1)];
|
|
101
|
+
for (const model of models) {
|
|
102
|
+
if (!model)
|
|
103
|
+
throw new Error(`[providerkit] "${member}" has an empty model after "/".`);
|
|
104
|
+
const key = `${name}/${model}`;
|
|
105
|
+
if (!out.has(key))
|
|
106
|
+
out.set(key, { name, model });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return [...out.values()];
|
|
110
|
+
}
|
|
111
|
+
/** Get the provider for a ref, building it on first use. */
|
|
112
|
+
function resolve(ref) {
|
|
113
|
+
const cached = built.get(ref);
|
|
114
|
+
if (cached)
|
|
115
|
+
return cached.provider;
|
|
116
|
+
const list = members(ref);
|
|
117
|
+
const candidates = list.map(({ name, model }) => candidate(name, model));
|
|
118
|
+
// A single candidate gets no pool. A pool of one benches the only option:
|
|
119
|
+
// a 503 a retry would absorb in a second becomes 30 s of instant
|
|
120
|
+
// NoAvailableProviderError, and the real kind hides behind `rate`. KeyPool
|
|
121
|
+
// refuses to bench its last key for the same reason.
|
|
122
|
+
const provider = candidates.length === 1 ? candidates[0] : withFallbackProviders(candidates, poolOptions);
|
|
123
|
+
built.set(ref, { provider, uses: new Set(list.map(({ name }) => name)) });
|
|
124
|
+
return provider;
|
|
125
|
+
}
|
|
126
|
+
function candidate(name, model) {
|
|
127
|
+
const connection = connections.get(name);
|
|
128
|
+
const cached = connection.candidates.get(model);
|
|
129
|
+
if (cached)
|
|
130
|
+
return cached;
|
|
131
|
+
const { config, keyPool } = connection;
|
|
132
|
+
const { preset, apiKey: _apiKey, keys: _keys, token: _token, models: _models, maxConcurrent: _maxConcurrent, watchdog: _watchdog, headers, ...rest } = config;
|
|
133
|
+
// One session id per candidate, kept by every adapter a key pool or a
|
|
134
|
+
// token builds for it. A new id per attempt made a sticky gateway treat
|
|
135
|
+
// every call as a new session and miss its prompt cache.
|
|
136
|
+
const base = { ...rest, model, instanceSessionId: crypto.randomUUID() };
|
|
137
|
+
let provider;
|
|
138
|
+
if (config.token) {
|
|
139
|
+
// The credential's host and headers win: Copilot gives each plan its
|
|
140
|
+
// own host, and the Codex backend refuses a call without its account id.
|
|
141
|
+
provider = withToken(config.token, (auth) => presetAdapter(preset, { ...base, ...auth, headers: { ...headers, ...auth.headers } }));
|
|
142
|
+
}
|
|
143
|
+
else if (config.keys) {
|
|
144
|
+
// `open` builds the pool whenever `keys` is set.
|
|
145
|
+
provider = withKeyPool(keyPool, (key) => presetAdapter(preset, { ...base, headers, apiKey: key }));
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
provider = presetAdapter(preset, { ...base, headers, apiKey: config.apiKey });
|
|
149
|
+
}
|
|
150
|
+
// On unless turned off, where `createPresetProvider` adds one only when
|
|
151
|
+
// asked. Handing apps the whole composition is the point of a registry:
|
|
152
|
+
// two apps that wired the watchdog themselves left keep-alives uncounted,
|
|
153
|
+
// so the idle clock would cut a long tool call at 60 s (AGENTS.md, "A bump
|
|
154
|
+
// is an audit too").
|
|
155
|
+
const watchdog = config.watchdog === undefined ? options.watchdog : config.watchdog;
|
|
156
|
+
if (watchdog !== false)
|
|
157
|
+
provider = withWatchdog(provider, watchdog);
|
|
158
|
+
// Outside the watchdog, so a call waiting for a slot spends no deadline.
|
|
159
|
+
if (connection.gate)
|
|
160
|
+
provider = withGate(provider, connection.gate);
|
|
161
|
+
connection.candidates.set(model, provider);
|
|
162
|
+
refOf.set(provider, `${name}/${model}`);
|
|
163
|
+
return provider;
|
|
164
|
+
}
|
|
165
|
+
/** Drop every built chain that uses this connection. */
|
|
166
|
+
function forget(name) {
|
|
167
|
+
for (const [ref, entry] of built)
|
|
168
|
+
if (entry.uses.has(name))
|
|
169
|
+
built.delete(ref);
|
|
170
|
+
}
|
|
171
|
+
function view(ref, viewOpts) {
|
|
172
|
+
return {
|
|
173
|
+
get id() {
|
|
174
|
+
return resolve(ref).id;
|
|
175
|
+
},
|
|
176
|
+
get model() {
|
|
177
|
+
return resolve(ref).model;
|
|
178
|
+
},
|
|
179
|
+
createStream(messages, tools, opts = {}) {
|
|
180
|
+
async function* viewed() {
|
|
181
|
+
// A pool applies a per-call model to its primary only, and a single
|
|
182
|
+
// candidate would post it to a connection picked for another model.
|
|
183
|
+
if (opts.model) {
|
|
184
|
+
throw new ProviderError(ref, "invalid", `${ref}: a registry provider can't take a per-call model. ` +
|
|
185
|
+
`Ask the registry for it instead: get("conn/${opts.model}").`);
|
|
186
|
+
}
|
|
187
|
+
// Looked up per call, so `update` reaches a provider taken at boot.
|
|
188
|
+
const provider = resolve(ref);
|
|
189
|
+
for await (const chunk of provider.createStream(messages, tools, {
|
|
190
|
+
...opts,
|
|
191
|
+
effort: opts.effort ?? viewOpts.effort,
|
|
192
|
+
maxTokens: opts.maxTokens ?? viewOpts.maxTokens,
|
|
193
|
+
})) {
|
|
194
|
+
// A pool names the endpoint that answered; a single candidate is
|
|
195
|
+
// the endpoint, so its chunks get the same field.
|
|
196
|
+
yield chunk.source
|
|
197
|
+
? chunk
|
|
198
|
+
: { ...chunk, source: { provider: provider.id, model: provider.model } };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return viewed();
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
get(ref, opts = {}) {
|
|
207
|
+
members(ref);
|
|
208
|
+
return view(ref, opts);
|
|
209
|
+
},
|
|
210
|
+
update(name, config) {
|
|
211
|
+
const current = connections.get(name);
|
|
212
|
+
if (current && sameValue(current.config, config))
|
|
213
|
+
return;
|
|
214
|
+
connections.set(name, open(name, config, current));
|
|
215
|
+
forget(name);
|
|
216
|
+
},
|
|
217
|
+
remove(name) {
|
|
218
|
+
connections.delete(name);
|
|
219
|
+
forget(name);
|
|
220
|
+
},
|
|
221
|
+
status() {
|
|
222
|
+
const out = {};
|
|
223
|
+
for (const [name, { gate, keyPool, candidates }] of connections) {
|
|
224
|
+
out[name] = {
|
|
225
|
+
...(gate ? { gate: { max: gate.max, held: gate.held, waiting: gate.waiting } } : {}),
|
|
226
|
+
...(keyPool ? { keys: keyPool.status() } : {}),
|
|
227
|
+
candidates: [...candidates].map(([model, provider]) => {
|
|
228
|
+
const { probe, ...bench } = cooldowns.get(provider) ?? { retryAtMs: 0 };
|
|
229
|
+
return { ref: `${name}/${model}`, ...bench, probing: probe !== undefined };
|
|
230
|
+
}),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
return out;
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function gateFor(config, current) {
|
|
238
|
+
if (config.maxConcurrent === undefined)
|
|
239
|
+
return undefined;
|
|
240
|
+
// Calls in flight hold slots on the current gate. A fresh one with the same
|
|
241
|
+
// limit would let `max` more through beside them.
|
|
242
|
+
if (current?.gate && current.config.maxConcurrent === config.maxConcurrent)
|
|
243
|
+
return current.gate;
|
|
244
|
+
return createGate(config.maxConcurrent);
|
|
245
|
+
}
|
|
246
|
+
/** A bare connection's models: `models`, then `model`, then the preset's
|
|
247
|
+
* rotation, then its default. The order `createPresetProvider` uses. */
|
|
248
|
+
function modelsOf(name, config) {
|
|
249
|
+
const preset = PROVIDER_PRESETS[config.preset];
|
|
250
|
+
if (config.models?.length)
|
|
251
|
+
return config.models;
|
|
252
|
+
if (config.model)
|
|
253
|
+
return [config.model];
|
|
254
|
+
if (preset.rotation?.length)
|
|
255
|
+
return preset.rotation;
|
|
256
|
+
if (preset.defaultModel)
|
|
257
|
+
return [preset.defaultModel];
|
|
258
|
+
throw new Error(`[providerkit] Connection "${name}" names no model, and preset "${config.preset}" has no ` +
|
|
259
|
+
"default. Set model or models.");
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Equality for configs: plain objects and arrays by their contents, functions
|
|
263
|
+
* and every other object by identity. A key set to `undefined` equals a key
|
|
264
|
+
* left out. So an app that re-reads its config on every request rebuilds
|
|
265
|
+
* nothing, as long as it hands back the same `TokenSource`, `fetchImpl` and
|
|
266
|
+
* `onEvict` each time: a new one is a change, even when it does the same.
|
|
267
|
+
*/
|
|
268
|
+
function sameValue(a, b) {
|
|
269
|
+
if (Object.is(a, b))
|
|
270
|
+
return true;
|
|
271
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
272
|
+
return (Array.isArray(a) &&
|
|
273
|
+
Array.isArray(b) &&
|
|
274
|
+
a.length === b.length &&
|
|
275
|
+
a.every((value, i) => sameValue(value, b[i])));
|
|
276
|
+
}
|
|
277
|
+
if (!isPlainObject(a) || !isPlainObject(b))
|
|
278
|
+
return false;
|
|
279
|
+
for (const key of new Set([...Object.keys(a), ...Object.keys(b)])) {
|
|
280
|
+
if (!sameValue(a[key], b[key]))
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
function isPlainObject(value) {
|
|
286
|
+
if (typeof value !== "object" || value === null)
|
|
287
|
+
return false;
|
|
288
|
+
const proto = Object.getPrototypeOf(value);
|
|
289
|
+
return proto === Object.prototype || proto === null;
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
package/dist/retry.d.ts
CHANGED
|
@@ -5,6 +5,17 @@ export interface RetryOptions {
|
|
|
5
5
|
/** Maximum acceptable wait. A longer server deadline ends retry so an outer
|
|
6
6
|
* fallback can switch provider; it is never shortened to retry too early. */
|
|
7
7
|
maxDelayMs?: number;
|
|
8
|
+
/**
|
|
9
|
+
* How long recovery may go on, counted from the FIRST failure. A retry
|
|
10
|
+
* starts only if it would start before then, its wait included. An attempt
|
|
11
|
+
* already running is never cut. Default 60s; `Infinity` turns it off.
|
|
12
|
+
*
|
|
13
|
+
* Without it the worst case is every attempt in full plus every wait: three
|
|
14
|
+
* stalled streams at the watchdog's 300s each is a quarter of an hour before
|
|
15
|
+
* the caller hears anything. The clock starts at the first failure, not at
|
|
16
|
+
* the call, so a long healthy run that then fails still gets its recovery.
|
|
17
|
+
*/
|
|
18
|
+
budgetMs?: number;
|
|
8
19
|
/** Aborts the wait as well as the work, so Stop lands promptly. */
|
|
9
20
|
signal?: AbortSignal;
|
|
10
21
|
/** Decide retryability. Default: transient kinds only. */
|
package/dist/retry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;kFAC8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/E,uDAAuD;IACvD,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D;
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;kFAC8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/E,uDAAuD;IACvD,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D;AAOD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,IAAI,SAAwB,EAC5B,GAAG,SAAuB,GACzB,MAAM,CAGR;AAED;0EAC0E;AAC1E,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAarE;AA0CD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EACnC,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,CAAC,CAAC,CAoBZ;AAED;;;;;;;;GAQG;AACH,wBAAuB,eAAe,CAAC,CAAC,EACtC,OAAO,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,EACnE,IAAI,GAAE,YAAiB,GACtB,cAAc,CAAC,CAAC,CAAC,CAsCnB;AAED,MAAM,WAAW,kBAAkB;IACjC,uEAAuE;IACvE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IAC1C,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE;QACrB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;KACf,KAAK,IAAI,CAAC;IACX,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACjF;AAQD,gFAAgF;AAChF,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EACtC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,CAAC,CAAC,CAiBZ;AAED;;;;;;;;GAQG;AACH,wBAAuB,sBAAsB,CAAC,CAAC,EAC7C,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,EAC5C,IAAI,EAAE,kBAAkB,GACvB,cAAc,CAAC,CAAC,CAAC,CAsBnB"}
|
package/dist/retry.js
CHANGED
|
@@ -17,6 +17,7 @@ import { classify, isBackupEligible, isRetryable, parseRetryAfterMs, ProviderErr
|
|
|
17
17
|
const DEFAULT_MAX_ATTEMPTS = 3;
|
|
18
18
|
const DEFAULT_BASE_DELAY_MS = 1_000;
|
|
19
19
|
const DEFAULT_MAX_DELAY_MS = 30_000;
|
|
20
|
+
const DEFAULT_BUDGET_MS = 60_000;
|
|
20
21
|
/**
|
|
21
22
|
* Full-jitter exponential backoff: a random delay in
|
|
22
23
|
* `[0, min(cap, base · 2^(attempt-1))]`.
|
|
@@ -60,6 +61,24 @@ function delayFor(err, attempt, opts) {
|
|
|
60
61
|
return backoffMs(attempt, opts.baseDelayMs ?? DEFAULT_BASE_DELAY_MS, cap);
|
|
61
62
|
}
|
|
62
63
|
const defaultShouldRetry = (err, _attempt) => isRetryable(err);
|
|
64
|
+
/** The moment the recovery budget runs out, fixed at the first failure. */
|
|
65
|
+
const budgetEnd = (opts) => Date.now() + (opts.budgetMs ?? DEFAULT_BUDGET_MS);
|
|
66
|
+
/**
|
|
67
|
+
* Wait out the delay before the next attempt, or rethrow `err` unchanged when
|
|
68
|
+
* there is none: the server's deadline is past `maxDelayMs`, or the next
|
|
69
|
+
* attempt would start past the budget.
|
|
70
|
+
*/
|
|
71
|
+
async function waitToRetry(err, attempt, opts, budgetEndsAt) {
|
|
72
|
+
const delayMs = delayFor(err, attempt, opts);
|
|
73
|
+
if (delayMs === null || Date.now() + delayMs >= budgetEndsAt)
|
|
74
|
+
throw err;
|
|
75
|
+
opts.onRetry?.({ error: err, attempt, delayMs });
|
|
76
|
+
await (opts.sleep ?? sleep)(delayMs, opts.signal);
|
|
77
|
+
// A timer can wake long after it was due (a suspended worker, a throttled
|
|
78
|
+
// tab). The budget is about when the attempt starts, not when it was meant to.
|
|
79
|
+
if (Date.now() >= budgetEndsAt)
|
|
80
|
+
throw err;
|
|
81
|
+
}
|
|
63
82
|
/**
|
|
64
83
|
* Run `fn`, retrying transient failures with backoff. For one-shot calls such
|
|
65
84
|
* as a title, a summary or a compaction pass.
|
|
@@ -67,7 +86,7 @@ const defaultShouldRetry = (err, _attempt) => isRetryable(err);
|
|
|
67
86
|
export async function withRetry(fn, opts = {}) {
|
|
68
87
|
const maxAttempts = opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
69
88
|
const shouldRetry = opts.shouldRetry ?? defaultShouldRetry;
|
|
70
|
-
|
|
89
|
+
let budgetEndsAt;
|
|
71
90
|
let lastError;
|
|
72
91
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
73
92
|
if (opts.signal?.aborted)
|
|
@@ -82,11 +101,8 @@ export async function withRetry(fn, opts = {}) {
|
|
|
82
101
|
throw err;
|
|
83
102
|
if (attempt >= maxAttempts || !shouldRetry(err, attempt))
|
|
84
103
|
throw err;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
throw err;
|
|
88
|
-
opts.onRetry?.({ error: err, attempt, delayMs });
|
|
89
|
-
await nap(delayMs, opts.signal);
|
|
104
|
+
budgetEndsAt ??= budgetEnd(opts);
|
|
105
|
+
await waitToRetry(err, attempt, opts, budgetEndsAt);
|
|
90
106
|
}
|
|
91
107
|
}
|
|
92
108
|
throw lastError;
|
|
@@ -103,7 +119,7 @@ export async function withRetry(fn, opts = {}) {
|
|
|
103
119
|
export async function* withStreamRetry(factory, opts = {}) {
|
|
104
120
|
const maxAttempts = opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
105
121
|
const shouldRetry = opts.shouldRetry ?? defaultShouldRetry;
|
|
106
|
-
|
|
122
|
+
let budgetEndsAt;
|
|
107
123
|
let lastError;
|
|
108
124
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
109
125
|
if (opts.signal?.aborted)
|
|
@@ -129,11 +145,8 @@ export async function* withStreamRetry(factory, opts = {}) {
|
|
|
129
145
|
// Rule 2: past the first chunk there is no going back.
|
|
130
146
|
if (emitted || attempt >= maxAttempts || !shouldRetry(err, attempt))
|
|
131
147
|
throw err;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
throw err;
|
|
135
|
-
opts.onRetry?.({ error: err, attempt, delayMs });
|
|
136
|
-
await nap(delayMs, opts.signal);
|
|
148
|
+
budgetEndsAt ??= budgetEnd(opts);
|
|
149
|
+
await waitToRetry(err, attempt, opts, budgetEndsAt);
|
|
137
150
|
}
|
|
138
151
|
finally {
|
|
139
152
|
opts.signal?.removeEventListener("abort", onOuterAbort);
|
package/dist/retry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,yEAAyE;AACzE,EAAE;AACF,yEAAyE;AACzE,6EAA6E;AAC7E,gFAAgF;AAChF,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,4EAA4E;AAC5E,2EAA2E;AAC3E,EAAE;AACF,0EAA0E;AAC1E,wEAAwE;AACxE,OAAO,EACL,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,aAAa,GACd,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"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"}
|
package/dist/tool-args.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ToolCallDelta } from "./types.ts";
|
|
1
2
|
/**
|
|
2
3
|
* Attempt to recover the last valid JSON object from concatenated or prepended JSON
|
|
3
4
|
* (e.g. `{}{"query":"hello"}` or `{"a":1}{"b":2}`).
|
|
@@ -9,6 +10,27 @@ export declare function findLastValidJsonObject(raw: string): Record<string, unk
|
|
|
9
10
|
* 2. Clamps oversized IDs (> 64 chars) to avoid ChatGPT Responses 400 errors.
|
|
10
11
|
*/
|
|
11
12
|
export declare function normalizeToolId(id: string | undefined | null, prefix?: string): string;
|
|
13
|
+
/** A tool call's identity as a stream stated it: the last id and name it gave. */
|
|
14
|
+
export interface ToolCallIdentity {
|
|
15
|
+
index: number;
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Make a turn's tool calls runnable before its finish goes out, or fail the turn.
|
|
21
|
+
*
|
|
22
|
+
* A call with no name can't run: nothing says which tool to dispatch. It used to
|
|
23
|
+
* pass through (the Messages reader wrote `""` for both fields), and the loop
|
|
24
|
+
* failed one step later with nothing to say why. It throws `overload` now, a
|
|
25
|
+
* broken turn the same request usually does not repeat; cc-proxy answers it
|
|
26
|
+
* with a 502.
|
|
27
|
+
*
|
|
28
|
+
* A call with no id still can run. It gets one from `normalizeToolId`, written
|
|
29
|
+
* back into `calls` and returned as the deltas to send, so the result has an id
|
|
30
|
+
* to quote. An id the vendor did send is never rewritten: the four wires must
|
|
31
|
+
* agree on it (invariant 10), and repeated ids are history repair's job.
|
|
32
|
+
*/
|
|
33
|
+
export declare function settleToolCalls(provider: string, calls: Iterable<ToolCallIdentity>): ToolCallDelta[];
|
|
12
34
|
/**
|
|
13
35
|
* Parse a tool call's raw argument string into an object, salvaging what a
|
|
14
36
|
* truncated stream left behind, resolving concatenated JSON, and healing
|
package/dist/tool-args.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-args.d.ts","sourceRoot":"","sources":["../src/tool-args.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tool-args.d.ts","sourceRoot":"","sources":["../src/tool-args.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA0EhD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAiBnF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,MAAM,SAAa,GAAG,MAAM,CAc1F;AAED,kFAAkF;AAClF,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAChC,aAAa,EAAE,CAgBjB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYlE;AAED;sEACsE;AACtE,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQnD"}
|
package/dist/tool-args.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
// `\uXXXX`, which JSON.parse decodes correctly. Some escape it twice and
|
|
13
13
|
// emit `\\u00e7`, so even a clean parse leaves six literal characters
|
|
14
14
|
// standing and a Portuguese answer reaches the user as `atenção`.
|
|
15
|
+
import { ProviderError } from "./errors.js";
|
|
15
16
|
function isRecord(value) {
|
|
16
17
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17
18
|
}
|
|
@@ -122,6 +123,33 @@ export function normalizeToolId(id, prefix = "call_pk_") {
|
|
|
122
123
|
}
|
|
123
124
|
return clean;
|
|
124
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Make a turn's tool calls runnable before its finish goes out, or fail the turn.
|
|
128
|
+
*
|
|
129
|
+
* A call with no name can't run: nothing says which tool to dispatch. It used to
|
|
130
|
+
* pass through (the Messages reader wrote `""` for both fields), and the loop
|
|
131
|
+
* failed one step later with nothing to say why. It throws `overload` now, a
|
|
132
|
+
* broken turn the same request usually does not repeat; cc-proxy answers it
|
|
133
|
+
* with a 502.
|
|
134
|
+
*
|
|
135
|
+
* A call with no id still can run. It gets one from `normalizeToolId`, written
|
|
136
|
+
* back into `calls` and returned as the deltas to send, so the result has an id
|
|
137
|
+
* to quote. An id the vendor did send is never rewritten: the four wires must
|
|
138
|
+
* agree on it (invariant 10), and repeated ids are history repair's job.
|
|
139
|
+
*/
|
|
140
|
+
export function settleToolCalls(provider, calls) {
|
|
141
|
+
const minted = [];
|
|
142
|
+
for (const call of calls) {
|
|
143
|
+
if (!call.name.trim()) {
|
|
144
|
+
throw new ProviderError(provider, "overload", `${provider}: tool call ${call.index} came with no name, so no tool can run it`);
|
|
145
|
+
}
|
|
146
|
+
if (!call.id.trim()) {
|
|
147
|
+
call.id = normalizeToolId(call.id);
|
|
148
|
+
minted.push({ index: call.index, id: call.id });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return minted;
|
|
152
|
+
}
|
|
125
153
|
/**
|
|
126
154
|
* Parse a tool call's raw argument string into an object, salvaging what a
|
|
127
155
|
* truncated stream left behind, resolving concatenated JSON, and healing
|