@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,30 @@
1
+ /**
2
+ * HTTP-shaped error classification.
3
+ *
4
+ * Kept as pure functions, separate from any call path, for the same reason
5
+ * `usage.ts` is: a hand-written backend classifies the same statuses from a
6
+ * different source and should not carry a second copy of this table.
7
+ */
8
+ import type { ProtocolError, ProtocolErrorKind } from "./types.ts";
9
+ export declare function classifyHttpError(status: number | undefined): ProtocolErrorKind;
10
+ /**
11
+ * Reads `retry-after` as a delay in seconds.
12
+ *
13
+ * The header may also carry an HTTP-date. That form is deliberately not
14
+ * converted: the conversion depends on clock skew between us and the provider,
15
+ * and a wrong number here would be worse than an absent one, because the
16
+ * consumer owns the retry loop and would sleep on it.
17
+ */
18
+ export declare function parseRetryAfter(headers: Readonly<Record<string, string>> | undefined): number | undefined;
19
+ /**
20
+ * Normalises an arbitrary thrown value (connection reset, DNS failure, an
21
+ * immediate socket error) into a `ProtocolError`.
22
+ *
23
+ * Always classified as "transport": `classifyHttpError(undefined)` would
24
+ * return "unknown", but a throw with no HTTP response is exactly the class
25
+ * of fault §10.1 assigns to nax-ai's own bounded retry, not the consumer's
26
+ * rate-limit/overload policy. `cause` is preserved so the original value is
27
+ * never lost.
28
+ */
29
+ export declare function classifyThrown(cause: unknown): ProtocolError;
30
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/protocols/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEnE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB,CAQ/E;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CASzG;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,CAM5D"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * HTTP-shaped error classification.
3
+ *
4
+ * Kept as pure functions, separate from any call path, for the same reason
5
+ * `usage.ts` is: a hand-written backend classifies the same statuses from a
6
+ * different source and should not carry a second copy of this table.
7
+ */
8
+ export function classifyHttpError(status) {
9
+ if (status === undefined)
10
+ return "unknown";
11
+ if (status === 401 || status === 403)
12
+ return "auth";
13
+ if (status === 429)
14
+ return "rate-limit";
15
+ if (status === 529 || status === 503)
16
+ return "overloaded";
17
+ if (status >= 400 && status < 500)
18
+ return "bad-request";
19
+ if (status >= 500)
20
+ return "transport";
21
+ return "unknown";
22
+ }
23
+ /**
24
+ * Reads `retry-after` as a delay in seconds.
25
+ *
26
+ * The header may also carry an HTTP-date. That form is deliberately not
27
+ * converted: the conversion depends on clock skew between us and the provider,
28
+ * and a wrong number here would be worse than an absent one, because the
29
+ * consumer owns the retry loop and would sleep on it.
30
+ */
31
+ export function parseRetryAfter(headers) {
32
+ if (headers === undefined)
33
+ return undefined;
34
+ const entry = Object.entries(headers).find(([name]) => name.toLowerCase() === "retry-after");
35
+ if (entry === undefined)
36
+ return undefined;
37
+ const seconds = Number(entry[1]);
38
+ if (!Number.isFinite(seconds) || seconds < 0)
39
+ return undefined;
40
+ return seconds;
41
+ }
42
+ /**
43
+ * Normalises an arbitrary thrown value (connection reset, DNS failure, an
44
+ * immediate socket error) into a `ProtocolError`.
45
+ *
46
+ * Always classified as "transport": `classifyHttpError(undefined)` would
47
+ * return "unknown", but a throw with no HTTP response is exactly the class
48
+ * of fault §10.1 assigns to nax-ai's own bounded retry, not the consumer's
49
+ * rate-limit/overload policy. `cause` is preserved so the original value is
50
+ * never lost.
51
+ */
52
+ export function classifyThrown(cause) {
53
+ return {
54
+ kind: "transport",
55
+ message: cause instanceof Error ? cause.message : String(cause),
56
+ cause,
57
+ };
58
+ }
59
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/protocols/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,UAAU,iBAAiB,CAAC,MAA0B;IAC1D,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC3C,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,MAAM,CAAC;IACpD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,YAAY,CAAC;IACxC,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,YAAY,CAAC;IAC1D,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG;QAAE,OAAO,aAAa,CAAC;IACxD,IAAI,MAAM,IAAI,GAAG;QAAE,OAAO,WAAW,CAAC;IACtC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,OAAqD;IACnF,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE5C,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,aAAa,CAAC,CAAC;IAC7F,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE1C,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/D,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;QAC/D,KAAK;KACN,CAAC;AACJ,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The pi-ai-backed protocol.
3
+ *
4
+ * This file and the two other files on the ALLOWED list in
5
+ * scripts/check-pi-ai-imports.ts are the only places pi-ai may be imported.
6
+ * Nothing exported here may expose a pi-ai type in a shape a consumer sees.
7
+ *
8
+ * One implementation serves all four protocols. They differ only in where a
9
+ * system prompt sits in the wire request, and pi-ai's Context carries it in a
10
+ * dedicated field, so on this path the difference does not exist. The protocol
11
+ * name is still a parameter because a per-api quirk would branch on it.
12
+ */
13
+ import type { Api, AssistantMessageEvent, Context, Model, SimpleStreamOptions } from "@earendil-works/pi-ai";
14
+ import type { PiProtocolOptions } from "./pi-protocols.ts";
15
+ import type { Protocol, ProtocolRequest } from "./types.ts";
16
+ export interface PiResponse {
17
+ readonly status: number;
18
+ readonly headers: Readonly<Record<string, string>>;
19
+ }
20
+ export type PiStreamFn = (model: Model<Api>, context: Context, options: SimpleStreamOptions,
21
+ /**
22
+ * Called once, before the body is consumed. pi-ai's error event carries no
23
+ * status and no retry-after, so without this the classifier would return
24
+ * "unknown" for every failure and the consumer's retry policy — which M1
25
+ * section 10.1 deliberately assigns to the consumer — would be blind.
26
+ */
27
+ onResponse: (response: PiResponse) => void) => AsyncIterable<AssistantMessageEvent>;
28
+ export interface PiDeps {
29
+ readonly resolveModel: (modelId: string, provider?: string) => Promise<Model<Api>>;
30
+ readonly stream: PiStreamFn;
31
+ }
32
+ export declare function toPiContext(req: ProtocolRequest, model: Model<Api>): Context;
33
+ export declare function toPiOptions(req: ProtocolRequest): SimpleStreamOptions;
34
+ export declare function createPiProtocol(name: string, deps: PiDeps): Protocol;
35
+ export declare function createPiDeps(options?: PiProtocolOptions): PiDeps;
36
+ //# sourceMappingURL=pi-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-client.d.ts","sourceRoot":"","sources":["../../src/protocols/pi-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,GAAG,EACH,qBAAqB,EACrB,OAAO,EACP,KAAK,EAKL,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAM/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,KAAK,EAAuB,QAAQ,EAAiB,eAAe,EAAiB,MAAM,YAAY,CAAC;AAE/G,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACpD;AAED,MAAM,MAAM,UAAU,GAAG,CACvB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,mBAAmB;AAC5B;;;;;GAKG;AACH,UAAU,EAAE,CAAC,QAAQ,EAAE,UAAU,KAAK,IAAI,KACvC,aAAa,CAAC,qBAAqB,CAAC,CAAC;AAE1C,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACnF,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC7B;AA6GD,wBAAgB,WAAW,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,CAM5E;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,eAAe,GAAG,mBAAmB,CAWrE;AAkDD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CA+HrE;AAYD,wBAAgB,YAAY,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,CA6CpE"}
@@ -0,0 +1,348 @@
1
+ /**
2
+ * The pi-ai-backed protocol.
3
+ *
4
+ * This file and the two other files on the ALLOWED list in
5
+ * scripts/check-pi-ai-imports.ts are the only places pi-ai may be imported.
6
+ * Nothing exported here may expose a pi-ai type in a shape a consumer sees.
7
+ *
8
+ * One implementation serves all four protocols. They differ only in where a
9
+ * system prompt sits in the wire request, and pi-ai's Context carries it in a
10
+ * dedicated field, so on this path the difference does not exist. The protocol
11
+ * name is still a parameter because a per-api quirk would branch on it.
12
+ */
13
+ import { builtinModels } from "@earendil-works/pi-ai/providers/all";
14
+ import { createPiAuthResolver, toPiCredentialStore } from "../auth/pi-auth.js";
15
+ import { toTokenUsage, totalTokens } from "../usage.js";
16
+ import { classifyHttpError, classifyThrown, parseRetryAfter } from "./errors.js";
17
+ import { createToolArgAccumulator, parseToolArgs } from "./tool-args.js";
18
+ /**
19
+ * pi-ai's Message requires a timestamp, but no wire module under its api/
20
+ * directory reads one. A constant keeps translation deterministic; Date.now()
21
+ * would make tests flap over a field that is never sent.
22
+ */
23
+ const NO_TIMESTAMP = 0;
24
+ /** Placeholder accounting for a replayed assistant turn. Never sent upstream. */
25
+ const NO_USAGE = {
26
+ input: 0,
27
+ output: 0,
28
+ cacheRead: 0,
29
+ cacheWrite: 0,
30
+ totalTokens: 0,
31
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
32
+ };
33
+ function toPiTool(tool) {
34
+ return {
35
+ name: tool.name,
36
+ description: tool.description,
37
+ // pi-ai types this as a TypeBox TSchema, which is a JSON Schema object at
38
+ // runtime. nax-ai does not validate schemas; it forwards what it was given.
39
+ parameters: tool.inputSchema,
40
+ };
41
+ }
42
+ /**
43
+ * pi's ThinkingContent, from our ThinkingBlock. `thinkingSignature` is left
44
+ * unset rather than "" when absent, because pi's own request-side handling
45
+ * (dist/api/anthropic-messages.js:923-957) treats "no signature" and "empty
46
+ * signature" differently — a synthesised "" would pick the wrong branch.
47
+ */
48
+ function toPiThinking(block) {
49
+ return {
50
+ type: "thinking",
51
+ thinking: block.text,
52
+ ...(block.signature !== undefined ? { thinkingSignature: block.signature } : {}),
53
+ ...(block.redacted !== undefined ? { redacted: block.redacted } : {}),
54
+ };
55
+ }
56
+ function toPiMessages(messages, model) {
57
+ const toolNames = new Map();
58
+ const out = [];
59
+ for (const message of messages) {
60
+ if (message.role === "user") {
61
+ out.push({ role: "user", content: message.content, timestamp: NO_TIMESTAMP });
62
+ continue;
63
+ }
64
+ if (message.role === "assistant") {
65
+ for (const call of message.toolCalls ?? [])
66
+ toolNames.set(call.id, call.name);
67
+ out.push({
68
+ role: "assistant",
69
+ content: [
70
+ // Anthropic requires thinking blocks to lead the assistant
71
+ // message when present — this is a wire ordering requirement, not
72
+ // a style choice, so it goes first unconditionally.
73
+ ...(message.thinking ?? []).map(toPiThinking),
74
+ ...(message.content === "" ? [] : [{ type: "text", text: message.content }]),
75
+ ...(message.toolCalls ?? []).map((call) => ({
76
+ type: "toolCall",
77
+ id: call.id,
78
+ name: call.name,
79
+ arguments: (call.input ?? {}),
80
+ })),
81
+ ],
82
+ api: model.api,
83
+ provider: model.provider,
84
+ model: model.id,
85
+ usage: NO_USAGE,
86
+ stopReason: "stop",
87
+ timestamp: NO_TIMESTAMP,
88
+ });
89
+ continue;
90
+ }
91
+ // toolName is not on our ConversationMessage but is read on the wire by
92
+ // several providers, so it is recovered from the call that produced this
93
+ // result. No match means the caller assembled an impossible conversation.
94
+ const toolName = toolNames.get(message.toolCallId);
95
+ if (toolName === undefined) {
96
+ throw new Error(`Tool result references tool call "${message.toolCallId}", which no earlier assistant message made.`);
97
+ }
98
+ out.push({
99
+ role: "toolResult",
100
+ toolCallId: message.toolCallId,
101
+ toolName,
102
+ content: [{ type: "text", text: message.content }],
103
+ isError: message.isError ?? false,
104
+ timestamp: NO_TIMESTAMP,
105
+ });
106
+ }
107
+ return out;
108
+ }
109
+ export function toPiContext(req, model) {
110
+ return {
111
+ ...(req.system !== undefined ? { systemPrompt: req.system } : {}),
112
+ messages: toPiMessages(req.messages, model),
113
+ ...(req.tools !== undefined ? { tools: req.tools.map(toPiTool) } : {}),
114
+ };
115
+ }
116
+ export function toPiOptions(req) {
117
+ return {
118
+ ...(req.toolChoice !== undefined ? { toolChoice: req.toolChoice } : {}),
119
+ ...(req.maxTokens !== undefined ? { maxTokens: req.maxTokens } : {}),
120
+ ...(req.temperature !== undefined ? { temperature: req.temperature } : {}),
121
+ ...(req.cacheRetention !== undefined ? { cacheRetention: req.cacheRetention } : {}),
122
+ ...(req.signal !== undefined ? { signal: req.signal } : {}),
123
+ // pi-ai's scale has no "off": the absence of the field is how thinking is
124
+ // disabled, so mapping "off" to a value would silently enable it.
125
+ ...(req.thinking !== undefined && req.thinking !== "off" ? { reasoning: req.thinking } : {}),
126
+ };
127
+ }
128
+ /**
129
+ * pi-ai's terminal reasons, narrowed to ours.
130
+ *
131
+ * "deferred" is absent by design: we never request a deferred response, so
132
+ * receiving one means an assumption broke and it must surface rather than be
133
+ * folded into "stop". "content_filter" has no pi-ai equivalent and is
134
+ * unreachable here; it exists for a hand-written backend.
135
+ */
136
+ const STOP_REASONS = {
137
+ stop: "stop",
138
+ length: "length",
139
+ toolUse: "tool_use",
140
+ };
141
+ /** The in-progress tool call at a content index, when there is one. */
142
+ function toolCallAt(partial, index) {
143
+ const block = partial.content[index];
144
+ if (typeof block !== "object" || block === null)
145
+ return undefined;
146
+ const candidate = block;
147
+ if (candidate.type !== "toolCall" || typeof candidate.id !== "string" || typeof candidate.name !== "string") {
148
+ return undefined;
149
+ }
150
+ return { id: candidate.id, name: candidate.name };
151
+ }
152
+ /**
153
+ * The signature and redacted flag for the thinking block at a content index,
154
+ * when the block at that index has that shape. `thinking_end`'s own event
155
+ * carries no signature — pi accumulates it onto the block in `partial`
156
+ * during the stream (signature_delta, dist/api/anthropic-messages.js:501-502)
157
+ * so by the time the block ends it is complete there. Same trap as
158
+ * `toolCallAt` above: the terminal event is missing fields only the partial
159
+ * carries.
160
+ */
161
+ function thinkingBlockAt(partial, index) {
162
+ const block = partial.content[index];
163
+ if (typeof block !== "object" || block === null)
164
+ return {};
165
+ const candidate = block;
166
+ if (candidate.type !== "thinking")
167
+ return {};
168
+ return {
169
+ ...(typeof candidate.thinkingSignature === "string" ? { signature: candidate.thinkingSignature } : {}),
170
+ ...(typeof candidate.redacted === "boolean" ? { redacted: candidate.redacted } : {}),
171
+ };
172
+ }
173
+ export function createPiProtocol(name, deps) {
174
+ return {
175
+ name,
176
+ async *stream(req) {
177
+ const model = await deps.resolveModel(req.model, req.provider);
178
+ let observed;
179
+ const events = deps.stream(model, toPiContext(req, model), toPiOptions(req), (response) => {
180
+ observed = response;
181
+ });
182
+ const toolArgs = createToolArgAccumulator();
183
+ try {
184
+ for await (const event of events) {
185
+ switch (event.type) {
186
+ case "text_delta":
187
+ yield { type: "text-delta", text: event.delta };
188
+ break;
189
+ case "thinking_delta":
190
+ yield { type: "thinking-delta", text: event.delta };
191
+ break;
192
+ case "thinking_end": {
193
+ // Losing thinking text is worse than losing a signature: even
194
+ // when the block at this content index is not the shape we
195
+ // expect, still emit the text `thinking_end` itself carries.
196
+ const { signature, redacted } = thinkingBlockAt(event.partial, event.contentIndex);
197
+ yield {
198
+ type: "thinking",
199
+ block: {
200
+ text: event.content,
201
+ ...(signature !== undefined ? { signature } : {}),
202
+ ...(redacted !== undefined ? { redacted } : {}),
203
+ },
204
+ };
205
+ break;
206
+ }
207
+ case "toolcall_delta": {
208
+ // The delta carries neither id nor name; both are only on the
209
+ // in-progress call block that partial.content holds at this index.
210
+ const call = toolCallAt(event.partial, event.contentIndex);
211
+ if (call === undefined)
212
+ break;
213
+ const rawInput = toolArgs.append(call.id, call.name, event.delta);
214
+ yield { type: "tool-call-partial", id: call.id, name: call.name, rawInput };
215
+ break;
216
+ }
217
+ case "toolcall_end": {
218
+ const pending = toolArgs.take(event.toolCall.id);
219
+ let input;
220
+ try {
221
+ input = parseToolArgs(pending?.raw ?? "");
222
+ }
223
+ catch (cause) {
224
+ // An error event, not a throw: text and usage already yielded
225
+ // must survive.
226
+ yield {
227
+ type: "error",
228
+ error: {
229
+ kind: "bad-request",
230
+ message: `Tool "${event.toolCall.name}" returned unparseable arguments.`,
231
+ cause,
232
+ },
233
+ };
234
+ return;
235
+ }
236
+ yield { type: "tool-call", call: { id: event.toolCall.id, name: event.toolCall.name, input } };
237
+ break;
238
+ }
239
+ case "done": {
240
+ const stopReason = STOP_REASONS[event.reason];
241
+ yield { type: "usage", usage: toTokenUsage(event.message.usage) };
242
+ if (stopReason === undefined) {
243
+ yield {
244
+ type: "error",
245
+ error: {
246
+ kind: "unknown",
247
+ message: `Upstream reported stop reason "${event.reason}", which nax-ai never requests.`,
248
+ },
249
+ };
250
+ return;
251
+ }
252
+ yield { type: "done", stopReason };
253
+ return;
254
+ }
255
+ case "error": {
256
+ const status = observed?.status;
257
+ const retryAfter = parseRetryAfter(observed?.headers);
258
+ const usage = toTokenUsage(event.error.usage);
259
+ // A failed request that consumed tokens still bills for them.
260
+ if (totalTokens(usage) > 0)
261
+ yield { type: "usage", usage };
262
+ yield {
263
+ type: "error",
264
+ error: {
265
+ kind: classifyHttpError(status),
266
+ message: event.error.errorMessage ?? `Upstream stream ended: ${event.reason}.`,
267
+ ...(status !== undefined ? { status } : {}),
268
+ ...(retryAfter !== undefined ? { retryAfter } : {}),
269
+ },
270
+ };
271
+ return;
272
+ }
273
+ default:
274
+ // start, text_start, text_end, thinking_start and toolcall_start
275
+ // carry nothing our vocabulary expresses: content is already
276
+ // delivered by the deltas (and, for thinking, by "thinking_end"
277
+ // above).
278
+ break;
279
+ }
280
+ }
281
+ }
282
+ catch (cause) {
283
+ // A stream failure with no HTTP response (connection reset, DNS
284
+ // failure, an immediate socket error) propagates as a raw throw
285
+ // rather than pi-ai's own "error" event — there was never a response
286
+ // to build one from, which is why classifyHttpError(undefined) would
287
+ // otherwise return "unknown" here. The caller's own abort must not be
288
+ // relabelled as a transport fault: retryTransportFaults, and any
289
+ // consumer-level abort handling, both need to see abort as abort.
290
+ if (req.signal?.aborted)
291
+ throw cause;
292
+ yield { type: "error", error: classifyThrown(cause) };
293
+ }
294
+ },
295
+ };
296
+ }
297
+ let shared;
298
+ /**
299
+ * The credential-backed twin of `shared`, keyed by the store itself. Each of
300
+ * the four protocol entries resolves lazily through `createPiDeps`, so without
301
+ * this memo a consumer with credentials would construct one Models per entry
302
+ * instead of the single instance pi-protocols.ts promises.
303
+ */
304
+ const credentialed = new WeakMap();
305
+ export function createPiDeps(options = {}) {
306
+ const store = options.credentials;
307
+ let models;
308
+ if (store === undefined) {
309
+ models = shared ??= builtinModels();
310
+ }
311
+ else {
312
+ models = credentialed.get(store) ?? builtinModels({ credentials: toPiCredentialStore(store) });
313
+ credentialed.set(store, models);
314
+ }
315
+ const resolver = createPiAuthResolver(models);
316
+ return {
317
+ resolveModel: async (modelId, provider) => {
318
+ // pi-ai serves one model id from many providers (e.g. gpt-5.4 under
319
+ // azure-openai-responses, openai and openai-codex), so when the client
320
+ // supplies the owning provider the search is scoped to it. Without a
321
+ // provider — protocol-direct callers and existing tests — the global
322
+ // catalog's first match stays as the documented fallback.
323
+ const found = provider !== undefined
324
+ ? models.getModels(provider).find((candidate) => candidate.id === modelId)
325
+ : models.getModels().find((candidate) => candidate.id === modelId);
326
+ if (found === undefined) {
327
+ if (provider !== undefined) {
328
+ throw new Error(`Unknown model "${modelId}" for provider "${provider}" in the pi-ai catalog.`);
329
+ }
330
+ throw new Error(`Unknown model "${modelId}" in the pi-ai catalog.`);
331
+ }
332
+ return found;
333
+ },
334
+ stream: async function* (model, context, options_, onResponse) {
335
+ // Resolve through nax-ai's own port, not through Models' internal path,
336
+ // so the seam a native backend will use is exercised in production
337
+ // rather than merely exported.
338
+ const auth = await resolver.resolve({ provider: model.provider, model: model.id });
339
+ yield* models.streamSimple(model, context, {
340
+ ...options_,
341
+ ...(auth.apiKey !== undefined ? { apiKey: auth.apiKey } : {}),
342
+ ...(auth.headers !== undefined ? { headers: { ...auth.headers } } : {}),
343
+ onResponse: (response) => onResponse({ status: response.status, headers: response.headers }),
344
+ });
345
+ },
346
+ };
347
+ }
348
+ //# sourceMappingURL=pi-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-client.js","sourceRoot":"","sources":["../../src/protocols/pi-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The registration surface for the pi-backed protocols.
3
+ *
4
+ * A consumer cannot assemble these entries itself: the four protocols must
5
+ * share one pi-ai Models instance, and therefore one credential store and one
6
+ * catalog, rather than constructing four. That is why this is exported rather
7
+ * than documented.
8
+ *
9
+ * pi-ai is not imported here. The factory is lazy, so the import cost is paid
10
+ * on first resolve of a protocol and not before.
11
+ */
12
+ import type { CredentialStore } from "../types.ts";
13
+ import type { ProtocolEntries } from "./registry.ts";
14
+ export declare const PI_PROTOCOL_NAMES: readonly ["anthropic-messages", "openai-completions", "openai-responses", "openai-codex-responses"];
15
+ export type PiProtocolName = (typeof PI_PROTOCOL_NAMES)[number];
16
+ export interface PiProtocolOptions {
17
+ /** Where OAuth and api-key credentials live. Omitted means ambient only. */
18
+ readonly credentials?: CredentialStore;
19
+ }
20
+ export declare function piProtocols(options?: PiProtocolOptions): ProtocolEntries;
21
+ //# sourceMappingURL=pi-protocols.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-protocols.d.ts","sourceRoot":"","sources":["../../src/protocols/pi-protocols.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,eAAO,MAAM,iBAAiB,YAC5B,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,wBAAwB,CAChB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,CAAC,EAAE,eAAe,CAAC;CACxC;AAED,wBAAgB,WAAW,CAAC,OAAO,GAAE,iBAAsB,GAAG,eAAe,CAY5E"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The registration surface for the pi-backed protocols.
3
+ *
4
+ * A consumer cannot assemble these entries itself: the four protocols must
5
+ * share one pi-ai Models instance, and therefore one credential store and one
6
+ * catalog, rather than constructing four. That is why this is exported rather
7
+ * than documented.
8
+ *
9
+ * pi-ai is not imported here. The factory is lazy, so the import cost is paid
10
+ * on first resolve of a protocol and not before.
11
+ */
12
+ export const PI_PROTOCOL_NAMES = [
13
+ "anthropic-messages",
14
+ "openai-completions",
15
+ "openai-responses",
16
+ "openai-codex-responses",
17
+ ];
18
+ export function piProtocols(options = {}) {
19
+ return Object.fromEntries(PI_PROTOCOL_NAMES.map((name) => [
20
+ name,
21
+ {
22
+ pi: async () => {
23
+ const { createPiDeps, createPiProtocol } = await import("./pi-client.js");
24
+ return createPiProtocol(name, createPiDeps(options));
25
+ },
26
+ },
27
+ ]));
28
+ }
29
+ //# sourceMappingURL=pi-protocols.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-protocols.js","sourceRoot":"","sources":["../../src/protocols/pi-protocols.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,oBAAoB;IACpB,oBAAoB;IACpB,kBAAkB;IAClB,wBAAwB;CAChB,CAAC;AASX,MAAM,UAAU,WAAW,CAAC,OAAO,GAAsB,EAAE;IACzD,OAAO,MAAM,CAAC,WAAW,CACvB,iBAAiB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC9B,IAAI;QACJ;YACE,EAAE,EAAE,KAAK,IAAI,EAAE;gBACb,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;gBAC1E,OAAO,gBAAgB,CAAC,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;YACvD,CAAC;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,36 @@
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
+ import type { Protocol } from "./types.ts";
11
+ export type BackendId = "pi" | "native";
12
+ /** Lazy factories keyed by backend id. Laziness preserves pi-ai's deferred SDK loading. */
13
+ export type ProtocolBackends = Partial<Record<BackendId, () => Promise<Protocol>>>;
14
+ export type ProtocolEntries = Readonly<Record<string, ProtocolBackends>>;
15
+ export interface BackendSelection {
16
+ /** Applied to protocols not named in `byProtocol`. Defaults to "pi". */
17
+ readonly default?: BackendId;
18
+ readonly byProtocol?: Readonly<Record<string, BackendId>>;
19
+ }
20
+ export declare class UnknownProtocolError extends Error {
21
+ readonly protocolName: string;
22
+ constructor(protocolName: string);
23
+ }
24
+ export declare class UnregisteredBackendError extends Error {
25
+ readonly protocolName: string;
26
+ readonly backendId: BackendId;
27
+ constructor(protocolName: string, backendId: BackendId, available: readonly BackendId[]);
28
+ }
29
+ export interface ProtocolRegistry {
30
+ available(): ReadonlyMap<string, readonly BackendId[]>;
31
+ resolve(protocolName: string): Promise<Protocol>;
32
+ /** Throws if any configured selection names an unknown protocol or unregistered backend. */
33
+ validate(): void;
34
+ }
35
+ export declare function createRegistry(entries: ProtocolEntries, selection?: BackendSelection): ProtocolRegistry;
36
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/protocols/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,QAAQ,CAAC;AAExC,2FAA2F;AAC3F,MAAM,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAEnF,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAEzE,MAAM,WAAW,gBAAgB;IAC/B,wEAAwE;IACxE,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;CAC3D;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IACjC,QAAQ,CAAC,YAAY,EAAE,MAAM;IAAzC,YAAqB,YAAY,EAAE,MAAM,EAGxC;CACF;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IAE/C,QAAQ,CAAC,YAAY,EAAE,MAAM;IAC7B,QAAQ,CAAC,SAAS,EAAE,SAAS;IAF/B,YACW,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,SAAS,EAC7B,SAAS,EAAE,SAAS,SAAS,EAAE,EAQhC;CACF;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,IAAI,WAAW,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC,CAAC;IACvD,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjD,4FAA4F;IAC5F,QAAQ,IAAI,IAAI,CAAC;CAClB;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,EAAE,SAAS,GAAE,gBAAqB,GAAG,gBAAgB,CA8D3G"}