@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.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +69 -0
  3. package/dist/auth/oauth-policy.d.ts +42 -0
  4. package/dist/auth/oauth-policy.d.ts.map +1 -0
  5. package/dist/auth/oauth-policy.js +61 -0
  6. package/dist/auth/oauth-policy.js.map +1 -0
  7. package/dist/auth/pi-auth.d.ts +12 -0
  8. package/dist/auth/pi-auth.d.ts.map +1 -0
  9. package/dist/auth/pi-auth.js +84 -0
  10. package/dist/auth/pi-auth.js.map +1 -0
  11. package/dist/auth/resolver.d.ts +30 -0
  12. package/dist/auth/resolver.d.ts.map +1 -0
  13. package/dist/auth/resolver.js +10 -0
  14. package/dist/auth/resolver.js.map +1 -0
  15. package/dist/client.d.ts +33 -0
  16. package/dist/client.d.ts.map +1 -0
  17. package/dist/client.js +68 -0
  18. package/dist/client.js.map +1 -0
  19. package/dist/index.d.ts +27 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +23 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/protocols/collect.d.ts +15 -0
  24. package/dist/protocols/collect.d.ts.map +1 -0
  25. package/dist/protocols/collect.js +65 -0
  26. package/dist/protocols/collect.js.map +1 -0
  27. package/dist/protocols/errors.d.ts +30 -0
  28. package/dist/protocols/errors.d.ts.map +1 -0
  29. package/dist/protocols/errors.js +59 -0
  30. package/dist/protocols/errors.js.map +1 -0
  31. package/dist/protocols/pi-client.d.ts +36 -0
  32. package/dist/protocols/pi-client.d.ts.map +1 -0
  33. package/dist/protocols/pi-client.js +348 -0
  34. package/dist/protocols/pi-client.js.map +1 -0
  35. package/dist/protocols/pi-protocols.d.ts +21 -0
  36. package/dist/protocols/pi-protocols.d.ts.map +1 -0
  37. package/dist/protocols/pi-protocols.js +29 -0
  38. package/dist/protocols/pi-protocols.js.map +1 -0
  39. package/dist/protocols/registry.d.ts +36 -0
  40. package/dist/protocols/registry.d.ts.map +1 -0
  41. package/dist/protocols/registry.js +85 -0
  42. package/dist/protocols/registry.js.map +1 -0
  43. package/dist/protocols/retry.d.ts +37 -0
  44. package/dist/protocols/retry.d.ts.map +1 -0
  45. package/dist/protocols/retry.js +96 -0
  46. package/dist/protocols/retry.js.map +1 -0
  47. package/dist/protocols/thinking.d.ts +11 -0
  48. package/dist/protocols/thinking.d.ts.map +1 -0
  49. package/dist/protocols/thinking.js +35 -0
  50. package/dist/protocols/thinking.js.map +1 -0
  51. package/dist/protocols/tool-args.d.ts +27 -0
  52. package/dist/protocols/tool-args.d.ts.map +1 -0
  53. package/dist/protocols/tool-args.js +38 -0
  54. package/dist/protocols/tool-args.js.map +1 -0
  55. package/dist/protocols/types.d.ts +142 -0
  56. package/dist/protocols/types.d.ts.map +1 -0
  57. package/dist/protocols/types.js +33 -0
  58. package/dist/protocols/types.js.map +1 -0
  59. package/dist/providers/catalog.d.ts +37 -0
  60. package/dist/providers/catalog.d.ts.map +1 -0
  61. package/dist/providers/catalog.js +72 -0
  62. package/dist/providers/catalog.js.map +1 -0
  63. package/dist/providers/pi-catalog.d.ts +14 -0
  64. package/dist/providers/pi-catalog.d.ts.map +1 -0
  65. package/dist/providers/pi-catalog.js +91 -0
  66. package/dist/providers/pi-catalog.js.map +1 -0
  67. package/dist/providers/types.d.ts +79 -0
  68. package/dist/providers/types.d.ts.map +1 -0
  69. package/dist/providers/types.js +10 -0
  70. package/dist/providers/types.js.map +1 -0
  71. package/dist/types.d.ts +94 -0
  72. package/dist/types.d.ts.map +1 -0
  73. package/dist/types.js +10 -0
  74. package/dist/types.js.map +1 -0
  75. package/dist/usage.d.ts +39 -0
  76. package/dist/usage.d.ts.map +1 -0
  77. package/dist/usage.js +40 -0
  78. package/dist/usage.js.map +1 -0
  79. 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"}