@nathapp/nax-ai 0.1.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/LICENSE +21 -0
- package/README.md +69 -0
- package/dist/auth/oauth-policy.d.ts +42 -0
- package/dist/auth/oauth-policy.d.ts.map +1 -0
- package/dist/auth/oauth-policy.js +61 -0
- package/dist/auth/oauth-policy.js.map +1 -0
- package/dist/auth/pi-auth.d.ts +12 -0
- package/dist/auth/pi-auth.d.ts.map +1 -0
- package/dist/auth/pi-auth.js +84 -0
- package/dist/auth/pi-auth.js.map +1 -0
- package/dist/auth/resolver.d.ts +30 -0
- package/dist/auth/resolver.d.ts.map +1 -0
- package/dist/auth/resolver.js +10 -0
- package/dist/auth/resolver.js.map +1 -0
- package/dist/client.d.ts +33 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +68 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/protocols/collect.d.ts +15 -0
- package/dist/protocols/collect.d.ts.map +1 -0
- package/dist/protocols/collect.js +65 -0
- package/dist/protocols/collect.js.map +1 -0
- package/dist/protocols/errors.d.ts +30 -0
- package/dist/protocols/errors.d.ts.map +1 -0
- package/dist/protocols/errors.js +59 -0
- package/dist/protocols/errors.js.map +1 -0
- package/dist/protocols/pi-client.d.ts +36 -0
- package/dist/protocols/pi-client.d.ts.map +1 -0
- package/dist/protocols/pi-client.js +348 -0
- package/dist/protocols/pi-client.js.map +1 -0
- package/dist/protocols/pi-protocols.d.ts +21 -0
- package/dist/protocols/pi-protocols.d.ts.map +1 -0
- package/dist/protocols/pi-protocols.js +29 -0
- package/dist/protocols/pi-protocols.js.map +1 -0
- package/dist/protocols/registry.d.ts +36 -0
- package/dist/protocols/registry.d.ts.map +1 -0
- package/dist/protocols/registry.js +85 -0
- package/dist/protocols/registry.js.map +1 -0
- package/dist/protocols/retry.d.ts +37 -0
- package/dist/protocols/retry.d.ts.map +1 -0
- package/dist/protocols/retry.js +96 -0
- package/dist/protocols/retry.js.map +1 -0
- package/dist/protocols/thinking.d.ts +11 -0
- package/dist/protocols/thinking.d.ts.map +1 -0
- package/dist/protocols/thinking.js +35 -0
- package/dist/protocols/thinking.js.map +1 -0
- package/dist/protocols/tool-args.d.ts +27 -0
- package/dist/protocols/tool-args.d.ts.map +1 -0
- package/dist/protocols/tool-args.js +38 -0
- package/dist/protocols/tool-args.js.map +1 -0
- package/dist/protocols/types.d.ts +142 -0
- package/dist/protocols/types.d.ts.map +1 -0
- package/dist/protocols/types.js +33 -0
- package/dist/protocols/types.js.map +1 -0
- package/dist/providers/catalog.d.ts +37 -0
- package/dist/providers/catalog.d.ts.map +1 -0
- package/dist/providers/catalog.js +72 -0
- package/dist/providers/catalog.js.map +1 -0
- package/dist/providers/pi-catalog.d.ts +14 -0
- package/dist/providers/pi-catalog.d.ts.map +1 -0
- package/dist/providers/pi-catalog.js +91 -0
- package/dist/providers/pi-catalog.js.map +1 -0
- package/dist/providers/types.d.ts +79 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +10 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/types.d.ts +94 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/dist/usage.d.ts +39 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +40 -0
- package/dist/usage.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol backend registration and selection.
|
|
3
|
+
*
|
|
4
|
+
* A protocol may have more than one backend — `pi` today, `native` when a wire
|
|
5
|
+
* format is hand-written later. Both can be registered at once so a native
|
|
6
|
+
* implementation can be run against the pi-backed one on real traffic before
|
|
7
|
+
* becoming the default. That comparison is the reason selection happens at
|
|
8
|
+
* runtime rather than by swapping a module at build time.
|
|
9
|
+
*/
|
|
10
|
+
export class UnknownProtocolError extends Error {
|
|
11
|
+
protocolName;
|
|
12
|
+
constructor(protocolName) {
|
|
13
|
+
super(`Unknown protocol "${protocolName}".`);
|
|
14
|
+
this.protocolName = protocolName;
|
|
15
|
+
this.name = "UnknownProtocolError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class UnregisteredBackendError extends Error {
|
|
19
|
+
protocolName;
|
|
20
|
+
backendId;
|
|
21
|
+
constructor(protocolName, backendId, available) {
|
|
22
|
+
super(`Backend "${backendId}" is not registered for protocol "${protocolName}". ` +
|
|
23
|
+
`Available: ${available.length > 0 ? available.join(", ") : "none"}. ` +
|
|
24
|
+
`This is not falling back — a silent fallback would misreport which implementation ran.`);
|
|
25
|
+
this.protocolName = protocolName;
|
|
26
|
+
this.backendId = backendId;
|
|
27
|
+
this.name = "UnregisteredBackendError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function createRegistry(entries, selection = {}) {
|
|
31
|
+
const resolved = new Map();
|
|
32
|
+
const backendsFor = (protocolName) => {
|
|
33
|
+
const backends = entries[protocolName];
|
|
34
|
+
if (backends === undefined)
|
|
35
|
+
throw new UnknownProtocolError(protocolName);
|
|
36
|
+
return backends;
|
|
37
|
+
};
|
|
38
|
+
const idsFor = (backends) => Object.keys(backends).filter((id) => backends[id] !== undefined);
|
|
39
|
+
const selectedFor = (protocolName) => selection.byProtocol?.[protocolName] ?? selection.default ?? "pi";
|
|
40
|
+
return {
|
|
41
|
+
available() {
|
|
42
|
+
const map = new Map();
|
|
43
|
+
for (const [name, backends] of Object.entries(entries)) {
|
|
44
|
+
map.set(name, idsFor(backends));
|
|
45
|
+
}
|
|
46
|
+
return map;
|
|
47
|
+
},
|
|
48
|
+
async resolve(protocolName) {
|
|
49
|
+
const cached = resolved.get(protocolName);
|
|
50
|
+
if (cached !== undefined)
|
|
51
|
+
return cached;
|
|
52
|
+
const backends = backendsFor(protocolName);
|
|
53
|
+
const backendId = selectedFor(protocolName);
|
|
54
|
+
const factory = backends[backendId];
|
|
55
|
+
if (factory === undefined) {
|
|
56
|
+
throw new UnregisteredBackendError(protocolName, backendId, idsFor(backends));
|
|
57
|
+
}
|
|
58
|
+
const promise = factory();
|
|
59
|
+
resolved.set(protocolName, promise);
|
|
60
|
+
return promise;
|
|
61
|
+
},
|
|
62
|
+
validate() {
|
|
63
|
+
// Per-protocol overrides first: they take precedence over the default,
|
|
64
|
+
// and names a protocol outside `entries` must surface as unknown before
|
|
65
|
+
// any default-derived check runs. Throwing exits immediately, so the
|
|
66
|
+
// same defect is never reported twice.
|
|
67
|
+
for (const [protocolName, backendId] of Object.entries(selection.byProtocol ?? {})) {
|
|
68
|
+
const backends = backendsFor(protocolName);
|
|
69
|
+
if (backends[backendId] === undefined) {
|
|
70
|
+
throw new UnregisteredBackendError(protocolName, backendId, idsFor(backends));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// The default applies to every protocol not named in byProtocol. A
|
|
74
|
+
// `{ default: "native" }` selection must fail at startup, not on the
|
|
75
|
+
// first resolve().
|
|
76
|
+
for (const [protocolName, backends] of Object.entries(entries)) {
|
|
77
|
+
const backendId = selectedFor(protocolName);
|
|
78
|
+
if (backends[backendId] === undefined) {
|
|
79
|
+
throw new UnregisteredBackendError(protocolName, backendId, idsFor(backends));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/protocols/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded transport-fault retry, ahead of the first event.
|
|
3
|
+
*
|
|
4
|
+
* Lives in its own module rather than inline in client.ts so it is
|
|
5
|
+
* unit-testable with an injected clock, and so it survives a future
|
|
6
|
+
* migration that deletes the pi-ai backend entirely: this file imports
|
|
7
|
+
* nothing pi-ai-shaped, only the wire-protocol vocabulary in ./types.ts.
|
|
8
|
+
*
|
|
9
|
+
* Spec: docs/superpowers/specs/2026-08-31-nax-ai-protocol-architecture-design.md §10.1.
|
|
10
|
+
* nax-ai retries transport faults only, and only before the first event of an
|
|
11
|
+
* attempt is emitted. Rate limits and overload capacity are consumer policy
|
|
12
|
+
* (concurrency, cost budget, failover) and must never be retried internally.
|
|
13
|
+
* 4xx and auth failures are terminal — retrying cannot help either.
|
|
14
|
+
*/
|
|
15
|
+
import type { ProtocolEvent } from "./types.ts";
|
|
16
|
+
export interface RetryOptions {
|
|
17
|
+
/** Retries beyond the first attempt. 0 makes exactly one attempt. */
|
|
18
|
+
readonly retries: number;
|
|
19
|
+
/** Injected so tests never actually wait; client.ts passes the real clock. */
|
|
20
|
+
readonly sleep: (ms: number) => Promise<void>;
|
|
21
|
+
readonly signal?: AbortSignal;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Wraps a protocol stream factory with bounded transport-fault retry.
|
|
25
|
+
*
|
|
26
|
+
* `makeStream` is called once per attempt so each retry is a fresh request.
|
|
27
|
+
* The moment any event is yielded — including "usage" — everything from then
|
|
28
|
+
* on passes straight through with no further retry for this call. "usage"
|
|
29
|
+
* counts deliberately: pi-client.ts yields a usage event before an error
|
|
30
|
+
* event when a failed request still consumed tokens ("A failed request that
|
|
31
|
+
* consumed tokens still bills for them"). If usage did not gate the retry, a
|
|
32
|
+
* retry would emit a second usage event, and collectStream's "last usage
|
|
33
|
+
* wins" rule would silently discard the failed attempt's billed tokens. So
|
|
34
|
+
* retry only ever covers attempts that produced literally nothing.
|
|
35
|
+
*/
|
|
36
|
+
export declare function retryTransportFaults(makeStream: () => AsyncIterable<ProtocolEvent>, { retries, sleep, signal }: RetryOptions): AsyncIterable<ProtocolEvent>;
|
|
37
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/protocols/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AA2CD;;;;;;;;;;;;GAYG;AACH,wBAAuB,oBAAoB,CACzC,UAAU,EAAE,MAAM,aAAa,CAAC,aAAa,CAAC,EAC9C,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,YAAY,GACvC,aAAa,CAAC,aAAa,CAAC,CAoC9B"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded transport-fault retry, ahead of the first event.
|
|
3
|
+
*
|
|
4
|
+
* Lives in its own module rather than inline in client.ts so it is
|
|
5
|
+
* unit-testable with an injected clock, and so it survives a future
|
|
6
|
+
* migration that deletes the pi-ai backend entirely: this file imports
|
|
7
|
+
* nothing pi-ai-shaped, only the wire-protocol vocabulary in ./types.ts.
|
|
8
|
+
*
|
|
9
|
+
* Spec: docs/superpowers/specs/2026-08-31-nax-ai-protocol-architecture-design.md §10.1.
|
|
10
|
+
* nax-ai retries transport faults only, and only before the first event of an
|
|
11
|
+
* attempt is emitted. Rate limits and overload capacity are consumer policy
|
|
12
|
+
* (concurrency, cost budget, failover) and must never be retried internally.
|
|
13
|
+
* 4xx and auth failures are terminal — retrying cannot help either.
|
|
14
|
+
*/
|
|
15
|
+
/** 250ms then 500ms. No jitter: §10.1 hands concurrency policy to the
|
|
16
|
+
* consumer, so de-synchronising a herd is their call, not ours — and a fixed
|
|
17
|
+
* schedule keeps tests deterministic. */
|
|
18
|
+
const INITIAL_BACKOFF_MS = 250;
|
|
19
|
+
function backoffMs(retryIndex) {
|
|
20
|
+
return INITIAL_BACKOFF_MS * 2 ** retryIndex;
|
|
21
|
+
}
|
|
22
|
+
function isRetryableErrorEvent(event) {
|
|
23
|
+
// 503/529 classify as "overloaded", not "transport" (see errors.ts and
|
|
24
|
+
// its test) — deliberately excluded here, along with rate-limit, auth and
|
|
25
|
+
// bad-request. Only a fault with no policy content is ours to retry.
|
|
26
|
+
return event.type === "error" && event.error.kind === "transport";
|
|
27
|
+
}
|
|
28
|
+
function abortError(signal) {
|
|
29
|
+
return signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
30
|
+
}
|
|
31
|
+
/** A sleep that resolves early, and rejects, when `signal` fires — so a
|
|
32
|
+
* pending backoff cannot outlive the caller's own cancellation and go on to
|
|
33
|
+
* start a request nobody wants. */
|
|
34
|
+
function abortableSleep(ms, sleep, signal) {
|
|
35
|
+
if (signal === undefined)
|
|
36
|
+
return sleep(ms);
|
|
37
|
+
if (signal.aborted)
|
|
38
|
+
return Promise.reject(abortError(signal));
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
const onAbort = () => reject(abortError(signal));
|
|
41
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
42
|
+
sleep(ms).then(() => {
|
|
43
|
+
signal.removeEventListener("abort", onAbort);
|
|
44
|
+
resolve();
|
|
45
|
+
}, reject);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Wraps a protocol stream factory with bounded transport-fault retry.
|
|
50
|
+
*
|
|
51
|
+
* `makeStream` is called once per attempt so each retry is a fresh request.
|
|
52
|
+
* The moment any event is yielded — including "usage" — everything from then
|
|
53
|
+
* on passes straight through with no further retry for this call. "usage"
|
|
54
|
+
* counts deliberately: pi-client.ts yields a usage event before an error
|
|
55
|
+
* event when a failed request still consumed tokens ("A failed request that
|
|
56
|
+
* consumed tokens still bills for them"). If usage did not gate the retry, a
|
|
57
|
+
* retry would emit a second usage event, and collectStream's "last usage
|
|
58
|
+
* wins" rule would silently discard the failed attempt's billed tokens. So
|
|
59
|
+
* retry only ever covers attempts that produced literally nothing.
|
|
60
|
+
*/
|
|
61
|
+
export async function* retryTransportFaults(makeStream, { retries, sleep, signal }) {
|
|
62
|
+
let retryIndex = 0;
|
|
63
|
+
for (;;) {
|
|
64
|
+
let emitted = false;
|
|
65
|
+
let fault;
|
|
66
|
+
try {
|
|
67
|
+
for await (const event of makeStream()) {
|
|
68
|
+
if (!emitted && isRetryableErrorEvent(event)) {
|
|
69
|
+
fault = event;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
emitted = true;
|
|
73
|
+
yield event;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (cause) {
|
|
77
|
+
// A throw is retryable whenever it precedes any emitted event and
|
|
78
|
+
// attempts remain — unlike an error event, a throw carries no `kind`
|
|
79
|
+
// to gate on, so any pre-first-event throw is presumed transport-shaped.
|
|
80
|
+
if (emitted || retryIndex >= retries)
|
|
81
|
+
throw cause;
|
|
82
|
+
await abortableSleep(backoffMs(retryIndex), sleep, signal);
|
|
83
|
+
retryIndex += 1;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (fault === undefined)
|
|
87
|
+
return; // this attempt completed cleanly
|
|
88
|
+
if (retryIndex >= retries) {
|
|
89
|
+
yield fault;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
await abortableSleep(backoffMs(retryIndex), sleep, signal);
|
|
93
|
+
retryIndex += 1;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/protocols/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH;;yCAEyC;AACzC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAE/B,SAAS,SAAS,CAAC,UAAkB;IACnC,OAAO,kBAAkB,GAAG,CAAC,IAAI,UAAU,CAAC;AAC9C,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAoB;IACjD,uEAAuE;IACvE,0EAA0E;IAC1E,qEAAqE;IACrE,OAAO,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC;AACpE,CAAC;AAED,SAAS,UAAU,CAAC,MAAmB;IACrC,OAAO,MAAM,CAAC,MAAM,IAAI,IAAI,YAAY,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AACpE,CAAC;AAED;;mCAEmC;AACnC,SAAS,cAAc,CACrB,EAAU,EACV,KAAoC,EACpC,MAA+B;IAE/B,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAE9D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;YAClB,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7C,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,MAAM,CAAC,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,oBAAoB,CACzC,UAA8C,EAC9C,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAgB;IAExC,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,SAAS,CAAC;QACR,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,KAAgC,CAAC;QAErC,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,UAAU,EAAE,EAAE,CAAC;gBACvC,IAAI,CAAC,OAAO,IAAI,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC7C,KAAK,GAAG,KAAK,CAAC;oBACd,MAAM;gBACR,CAAC;gBACD,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kEAAkE;YAClE,qEAAqE;YACrE,yEAAyE;YACzE,IAAI,OAAO,IAAI,UAAU,IAAI,OAAO;gBAAE,MAAM,KAAK,CAAC;YAClD,MAAM,cAAc,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;YAC3D,UAAU,IAAI,CAAC,CAAC;YAChB,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,CAAC,iCAAiC;QAElE,IAAI,UAAU,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,KAAK,CAAC;YACZ,OAAO;QACT,CAAC;QAED,MAAM,cAAc,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC3D,UAAU,IAAI,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clamping a requested thinking level onto what a model actually supports.
|
|
3
|
+
*
|
|
4
|
+
* Clamping rather than throwing is deliberate: models expose different
|
|
5
|
+
* granularities, and a profile that says "high" should not fail outright
|
|
6
|
+
* because one model only offers off/low/medium. The caller's intent — think
|
|
7
|
+
* harder than default — is still expressible.
|
|
8
|
+
*/
|
|
9
|
+
import { type ThinkingLevel } from "./types.ts";
|
|
10
|
+
export declare function clampThinkingLevel(requested: ThinkingLevel, supported: readonly ThinkingLevel[]): ThinkingLevel;
|
|
11
|
+
//# sourceMappingURL=thinking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thinking.d.ts","sourceRoot":"","sources":["../../src/protocols/thinking.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAIjE,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,aAAa,EAAE,GAAG,aAAa,CAyB/G"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clamping a requested thinking level onto what a model actually supports.
|
|
3
|
+
*
|
|
4
|
+
* Clamping rather than throwing is deliberate: models expose different
|
|
5
|
+
* granularities, and a profile that says "high" should not fail outright
|
|
6
|
+
* because one model only offers off/low/medium. The caller's intent — think
|
|
7
|
+
* harder than default — is still expressible.
|
|
8
|
+
*/
|
|
9
|
+
import { THINKING_LEVELS } from "./types.js";
|
|
10
|
+
const rank = (level) => THINKING_LEVELS.indexOf(level);
|
|
11
|
+
export function clampThinkingLevel(requested, supported) {
|
|
12
|
+
if (supported.length === 0)
|
|
13
|
+
return "off";
|
|
14
|
+
if (supported.includes(requested))
|
|
15
|
+
return requested;
|
|
16
|
+
// Sorted ascending so that "first seen wins on a tie" means "lower level
|
|
17
|
+
// wins" — callers are not required to pass an ordered list.
|
|
18
|
+
const ordered = [...supported].sort((a, b) => rank(a) - rank(b));
|
|
19
|
+
const target = rank(requested);
|
|
20
|
+
// Safe: `ordered` is non-empty, guarded above. noUncheckedIndexedAccess
|
|
21
|
+
// still widens the type, hence the assertion.
|
|
22
|
+
let best = ordered[0];
|
|
23
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
24
|
+
for (const level of ordered) {
|
|
25
|
+
const distance = Math.abs(rank(level) - target);
|
|
26
|
+
// Strict `<` keeps the first-seen (lower) candidate on a tie: spending
|
|
27
|
+
// fewer thinking tokens than asked is the safer surprise.
|
|
28
|
+
if (distance < bestDistance) {
|
|
29
|
+
best = level;
|
|
30
|
+
bestDistance = distance;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return best;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=thinking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thinking.js","sourceRoot":"","sources":["../../src/protocols/thinking.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,eAAe,EAAsB,MAAM,YAAY,CAAC;AAEjE,MAAM,IAAI,GAAG,CAAC,KAAoB,EAAU,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAE9E,MAAM,UAAU,kBAAkB,CAAC,SAAwB,EAAE,SAAmC;IAC9F,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAEpD,yEAAyE;IACzE,4DAA4D;IAC5D,MAAM,OAAO,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;IAE/B,wEAAwE;IACxE,8CAA8C;IAC9C,IAAI,IAAI,GAAG,OAAO,CAAC,CAAC,CAAkB,CAAC;IACvC,IAAI,YAAY,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAE5C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC;QAChD,uEAAuE;QACvE,0DAA0D;QAC1D,IAAI,QAAQ,GAAG,YAAY,EAAE,CAAC;YAC5B,IAAI,GAAG,KAAK,CAAC;YACb,YAAY,GAAG,QAAQ,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streamed tool-call argument accumulation.
|
|
3
|
+
*
|
|
4
|
+
* A pure helper rather than a method on a backend: every protocol receives
|
|
5
|
+
* arguments as JSON fragments and must accumulate before parsing, so a
|
|
6
|
+
* hand-written backend needs this same logic and should not re-derive it.
|
|
7
|
+
*/
|
|
8
|
+
interface PendingToolArgs {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly raw: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ToolArgAccumulator {
|
|
13
|
+
/** Appends a fragment and returns everything accumulated for `id` so far. */
|
|
14
|
+
append(id: string, name: string, fragment: string): string;
|
|
15
|
+
/** Removes and returns the accumulation, or undefined if `id` is unknown. */
|
|
16
|
+
take(id: string): PendingToolArgs | undefined;
|
|
17
|
+
}
|
|
18
|
+
export declare function createToolArgAccumulator(): ToolArgAccumulator;
|
|
19
|
+
/**
|
|
20
|
+
* Parses an accumulated argument string.
|
|
21
|
+
*
|
|
22
|
+
* An empty accumulation means the provider sent a tool call with no arguments,
|
|
23
|
+
* which is an empty object rather than an error.
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseToolArgs(raw: string): unknown;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=tool-args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-args.d.ts","sourceRoot":"","sources":["../../src/protocols/tool-args.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,UAAU,eAAe;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3D,6EAA6E;IAC7E,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;CAC/C;AAED,wBAAgB,wBAAwB,IAAI,kBAAkB,CAsB7D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAElD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streamed tool-call argument accumulation.
|
|
3
|
+
*
|
|
4
|
+
* A pure helper rather than a method on a backend: every protocol receives
|
|
5
|
+
* arguments as JSON fragments and must accumulate before parsing, so a
|
|
6
|
+
* hand-written backend needs this same logic and should not re-derive it.
|
|
7
|
+
*/
|
|
8
|
+
export function createToolArgAccumulator() {
|
|
9
|
+
const pending = new Map();
|
|
10
|
+
return {
|
|
11
|
+
append(id, name, fragment) {
|
|
12
|
+
const current = pending.get(id);
|
|
13
|
+
// The name arrives with the first fragment and is authoritative; later
|
|
14
|
+
// fragments may not carry it.
|
|
15
|
+
const next = {
|
|
16
|
+
name: current?.name ?? name,
|
|
17
|
+
raw: (current?.raw ?? "") + fragment,
|
|
18
|
+
};
|
|
19
|
+
pending.set(id, next);
|
|
20
|
+
return next.raw;
|
|
21
|
+
},
|
|
22
|
+
take(id) {
|
|
23
|
+
const current = pending.get(id);
|
|
24
|
+
pending.delete(id);
|
|
25
|
+
return current;
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parses an accumulated argument string.
|
|
31
|
+
*
|
|
32
|
+
* An empty accumulation means the provider sent a tool call with no arguments,
|
|
33
|
+
* which is an empty object rather than an error.
|
|
34
|
+
*/
|
|
35
|
+
export function parseToolArgs(raw) {
|
|
36
|
+
return raw === "" ? {} : JSON.parse(raw);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=tool-args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-args.js","sourceRoot":"","sources":["../../src/protocols/tool-args.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,MAAM,UAAU,wBAAwB;IACtC,MAAM,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEnD,OAAO;QACL,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ;YACvB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChC,uEAAuE;YACvE,8BAA8B;YAC9B,MAAM,IAAI,GAAoB;gBAC5B,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,IAAI;gBAC3B,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,QAAQ;aACrC,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACtB,OAAO,IAAI,CAAC,GAAG,CAAC;QAClB,CAAC;QAED,IAAI,CAAC,EAAE;YACL,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACnB,OAAO,OAAO,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire-protocol vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* Every concept here appears in more than one provider's wire format, or is a
|
|
5
|
+
* deliberate normalisation. No field is named after one provider's API: the
|
|
6
|
+
* point of this file is that a backend for any provider can be written against
|
|
7
|
+
* it without the interface having already picked a side.
|
|
8
|
+
*/
|
|
9
|
+
import type { StopReason, TokenUsage } from "../types.ts";
|
|
10
|
+
/** JSON Schema draft 2020-12 object. Structural — nax-ai does not validate it. */
|
|
11
|
+
export type JsonSchema = Readonly<Record<string, unknown>>;
|
|
12
|
+
/**
|
|
13
|
+
* Ascending order is load-bearing: clamping an unsupported level picks the
|
|
14
|
+
* nearest supported one by index, so reordering this array changes behaviour.
|
|
15
|
+
*/
|
|
16
|
+
export declare const THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
17
|
+
export type ThinkingLevel = (typeof THINKING_LEVELS)[number];
|
|
18
|
+
export declare const CACHE_RETENTIONS: readonly ["none", "short", "long"];
|
|
19
|
+
export type CacheRetention = (typeof CACHE_RETENTIONS)[number];
|
|
20
|
+
export declare const PROTOCOL_EVENT_TYPES: readonly ["text-delta", "thinking-delta", "thinking", "tool-call-partial", "tool-call", "usage", "error", "done"];
|
|
21
|
+
export type ProtocolEventType = (typeof PROTOCOL_EVENT_TYPES)[number];
|
|
22
|
+
export declare const PROTOCOL_ERROR_KINDS: readonly ["rate-limit", "auth", "overloaded", "bad-request", "transport", "unknown"];
|
|
23
|
+
export type ProtocolErrorKind = (typeof PROTOCOL_ERROR_KINDS)[number];
|
|
24
|
+
export interface ProtocolError {
|
|
25
|
+
readonly kind: ProtocolErrorKind;
|
|
26
|
+
readonly message: string;
|
|
27
|
+
readonly status?: number;
|
|
28
|
+
/** Seconds, when the provider signals one. The consumer owns the retry loop. */
|
|
29
|
+
readonly retryAfter?: number;
|
|
30
|
+
readonly cause?: unknown;
|
|
31
|
+
}
|
|
32
|
+
export interface ToolDefinition {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly description: string;
|
|
35
|
+
readonly inputSchema: JsonSchema;
|
|
36
|
+
}
|
|
37
|
+
export interface ToolCall {
|
|
38
|
+
readonly id: string;
|
|
39
|
+
readonly name: string;
|
|
40
|
+
/** Parsed. A protocol accumulates streamed JSON fragments and parses before emitting. */
|
|
41
|
+
readonly input: unknown;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A complete extended-thinking block, durable enough to replay on the next
|
|
45
|
+
* turn. Anthropic requires the exact thinking block (text plus signature) that
|
|
46
|
+
* preceded a tool call to be sent back verbatim on the following request, or
|
|
47
|
+
* the call cannot be verified server-side.
|
|
48
|
+
*/
|
|
49
|
+
export interface ThinkingBlock {
|
|
50
|
+
readonly text: string;
|
|
51
|
+
/**
|
|
52
|
+
* Opaque, like `StoredCredential`'s `key` (see src/types.ts): some
|
|
53
|
+
* providers put a cryptographic signature here, a redacted block puts its
|
|
54
|
+
* entire encrypted payload here instead. Never inspect, compare or log it.
|
|
55
|
+
* Absent means the provider did not send one — never synthesise "" for
|
|
56
|
+
* that, since an empty string is itself a value a provider could send.
|
|
57
|
+
*/
|
|
58
|
+
readonly signature?: string;
|
|
59
|
+
readonly redacted?: boolean;
|
|
60
|
+
}
|
|
61
|
+
export type ConversationMessage = {
|
|
62
|
+
readonly role: "user";
|
|
63
|
+
readonly content: string;
|
|
64
|
+
} | {
|
|
65
|
+
readonly role: "assistant";
|
|
66
|
+
readonly content: string;
|
|
67
|
+
readonly toolCalls?: readonly ToolCall[];
|
|
68
|
+
readonly thinking?: readonly ThinkingBlock[];
|
|
69
|
+
} | {
|
|
70
|
+
readonly role: "tool-result";
|
|
71
|
+
readonly toolCallId: string;
|
|
72
|
+
readonly content: string;
|
|
73
|
+
readonly isError?: boolean;
|
|
74
|
+
};
|
|
75
|
+
export interface ProtocolRequest {
|
|
76
|
+
readonly model: string;
|
|
77
|
+
/**
|
|
78
|
+
* The model's owning provider, supplied by the client so a protocol can
|
|
79
|
+
* scope model resolution when ids are ambiguous across providers.
|
|
80
|
+
*/
|
|
81
|
+
readonly provider?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Kept out of `messages` deliberately: Anthropic takes a top-level `system`
|
|
84
|
+
* parameter while OpenAI takes a system message in the array. Each backend
|
|
85
|
+
* places it correctly, so callers never encode a provider's shape.
|
|
86
|
+
*/
|
|
87
|
+
readonly system?: string;
|
|
88
|
+
readonly messages: readonly ConversationMessage[];
|
|
89
|
+
readonly tools?: readonly ToolDefinition[];
|
|
90
|
+
readonly toolChoice?: "auto" | "none";
|
|
91
|
+
readonly maxTokens?: number;
|
|
92
|
+
readonly temperature?: number;
|
|
93
|
+
readonly thinking?: ThinkingLevel;
|
|
94
|
+
readonly cacheRetention?: CacheRetention;
|
|
95
|
+
readonly signal?: AbortSignal;
|
|
96
|
+
}
|
|
97
|
+
export type ProtocolEvent = {
|
|
98
|
+
readonly type: "text-delta";
|
|
99
|
+
readonly text: string;
|
|
100
|
+
} | {
|
|
101
|
+
readonly type: "thinking-delta";
|
|
102
|
+
readonly text: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Mirrors the "tool-call-partial" -> "tool-call" pair: "thinking-delta"
|
|
106
|
+
* stays display-only progress, this is the durable complete block a
|
|
107
|
+
* consumer can carry into the next request's `ConversationMessage`.
|
|
108
|
+
*/
|
|
109
|
+
| {
|
|
110
|
+
readonly type: "thinking";
|
|
111
|
+
readonly block: ThinkingBlock;
|
|
112
|
+
} | {
|
|
113
|
+
readonly type: "tool-call-partial";
|
|
114
|
+
readonly id: string;
|
|
115
|
+
readonly name: string;
|
|
116
|
+
/** Raw accumulated JSON fragment — for progress display only. */
|
|
117
|
+
readonly rawInput: string;
|
|
118
|
+
} | {
|
|
119
|
+
readonly type: "tool-call";
|
|
120
|
+
readonly call: ToolCall;
|
|
121
|
+
} | {
|
|
122
|
+
readonly type: "usage";
|
|
123
|
+
readonly usage: TokenUsage;
|
|
124
|
+
} | {
|
|
125
|
+
readonly type: "error";
|
|
126
|
+
readonly error: ProtocolError;
|
|
127
|
+
} | {
|
|
128
|
+
readonly type: "done";
|
|
129
|
+
readonly stopReason: StopReason;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* A wire protocol.
|
|
133
|
+
*
|
|
134
|
+
* `complete` is deliberately absent. It is derived once, at the client layer,
|
|
135
|
+
* by collecting a stream — so a backend has no way to implement it as a second
|
|
136
|
+
* request path that drifts from this one.
|
|
137
|
+
*/
|
|
138
|
+
export interface Protocol {
|
|
139
|
+
readonly name: string;
|
|
140
|
+
stream(req: ProtocolRequest): AsyncIterable<ProtocolEvent>;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/protocols/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire-protocol vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* Every concept here appears in more than one provider's wire format, or is a
|
|
5
|
+
* deliberate normalisation. No field is named after one provider's API: the
|
|
6
|
+
* point of this file is that a backend for any provider can be written against
|
|
7
|
+
* it without the interface having already picked a side.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Ascending order is load-bearing: clamping an unsupported level picks the
|
|
11
|
+
* nearest supported one by index, so reordering this array changes behaviour.
|
|
12
|
+
*/
|
|
13
|
+
export const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
14
|
+
export const CACHE_RETENTIONS = ["none", "short", "long"];
|
|
15
|
+
export const PROTOCOL_EVENT_TYPES = [
|
|
16
|
+
"text-delta",
|
|
17
|
+
"thinking-delta",
|
|
18
|
+
"thinking",
|
|
19
|
+
"tool-call-partial",
|
|
20
|
+
"tool-call",
|
|
21
|
+
"usage",
|
|
22
|
+
"error",
|
|
23
|
+
"done",
|
|
24
|
+
];
|
|
25
|
+
export const PROTOCOL_ERROR_KINDS = [
|
|
26
|
+
"rate-limit",
|
|
27
|
+
"auth",
|
|
28
|
+
"overloaded",
|
|
29
|
+
"bad-request",
|
|
30
|
+
"transport",
|
|
31
|
+
"unknown",
|
|
32
|
+
];
|
|
33
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/protocols/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAU,CAAC;AAGpG,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAU,CAAC;AAGnE,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,YAAY;IACZ,gBAAgB;IAChB,UAAU;IACV,mBAAmB;IACnB,WAAW;IACX,OAAO;IACP,OAAO;IACP,MAAM;CACE,CAAC;AAGX,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,YAAY;IACZ,MAAM;IACN,YAAY;IACZ,aAAa;IACb,WAAW;IACX,SAAS;CACD,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalises a raw provider catalog into nax-ai types.
|
|
3
|
+
*
|
|
4
|
+
* STAYS pi-ai-BACKED. Hand-rolling the model catalog is explicitly out of
|
|
5
|
+
* scope: its pricing and model data are maintained upstream, and taking that
|
|
6
|
+
* maintenance back is the burden the dependency was chosen to avoid. Unlike
|
|
7
|
+
* `protocols/`, this layer is not a migration surface.
|
|
8
|
+
*
|
|
9
|
+
* This is also where the OAuth allowlist meets a real code path: a provider
|
|
10
|
+
* declaring a prohibited flow fails to resolve here.
|
|
11
|
+
*/
|
|
12
|
+
import type { ThinkingLevel } from "../protocols/types.ts";
|
|
13
|
+
import type { Pricing, ProviderAuth, ProviderOverride, ResolvedModel, ResolvedProvider } from "./types.ts";
|
|
14
|
+
export interface RawModel {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
/** Falls back to the provider's `defaultProtocol` when absent. */
|
|
17
|
+
readonly protocol?: string;
|
|
18
|
+
readonly pricing: Pricing;
|
|
19
|
+
readonly contextWindow: number;
|
|
20
|
+
readonly supportsTools: boolean;
|
|
21
|
+
readonly thinkingLevels: readonly ThinkingLevel[];
|
|
22
|
+
}
|
|
23
|
+
export interface RawProvider {
|
|
24
|
+
readonly id: string;
|
|
25
|
+
readonly baseUrl: string;
|
|
26
|
+
readonly auth: ProviderAuth;
|
|
27
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
28
|
+
readonly defaultProtocol: string;
|
|
29
|
+
readonly models: readonly RawModel[];
|
|
30
|
+
}
|
|
31
|
+
export interface Catalog {
|
|
32
|
+
provider(id: string): ResolvedProvider | undefined;
|
|
33
|
+
model(provider: string, model: string): ResolvedModel | undefined;
|
|
34
|
+
listModels(provider?: string): readonly ResolvedModel[];
|
|
35
|
+
}
|
|
36
|
+
export declare function normaliseCatalog(raw: readonly RawProvider[], overrides?: readonly ProviderOverride[]): Catalog;
|
|
37
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/providers/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE3G,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,SAAS,aAAa,EAAE,CAAC;CACnD;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAC;IACnD,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAC;IAClE,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,aAAa,EAAE,CAAC;CACzD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,WAAW,EAAE,EAAE,SAAS,GAAE,SAAS,gBAAgB,EAAO,GAAG,OAAO,CAgElH"}
|