@intx/inference 0.1.2 → 0.2.2

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 (97) hide show
  1. package/LICENSE +176 -0
  2. package/dist/actions.d.ts +16 -0
  3. package/dist/actions.js +200 -0
  4. package/dist/adapter.d.ts +38 -0
  5. package/dist/adapter.js +31 -0
  6. package/dist/assembly.d.ts +68 -0
  7. package/dist/assembly.js +132 -0
  8. package/dist/audit-collector.d.ts +10 -0
  9. package/dist/audit-collector.js +139 -0
  10. package/dist/auth.d.ts +24 -0
  11. package/{src/auth.ts → dist/auth.js} +13 -19
  12. package/dist/authz-extension.d.ts +32 -0
  13. package/dist/authz-extension.js +100 -0
  14. package/dist/correlation.d.ts +25 -0
  15. package/dist/correlation.js +32 -0
  16. package/dist/default-director.d.ts +111 -0
  17. package/dist/default-director.js +199 -0
  18. package/dist/director.d.ts +6 -0
  19. package/dist/director.js +56 -0
  20. package/dist/errors.d.ts +18 -0
  21. package/dist/errors.js +83 -0
  22. package/dist/gates.d.ts +27 -0
  23. package/dist/gates.js +80 -0
  24. package/dist/harness.d.ts +147 -0
  25. package/dist/harness.js +1319 -0
  26. package/dist/index.d.ts +37 -0
  27. package/dist/index.js +21 -0
  28. package/dist/manifest.d.ts +31 -0
  29. package/dist/manifest.js +44 -0
  30. package/dist/providers/anthropic.d.ts +33 -0
  31. package/dist/providers/anthropic.js +670 -0
  32. package/dist/providers/google-genai-files.d.ts +48 -0
  33. package/dist/providers/google-genai-files.js +205 -0
  34. package/dist/providers/google-genai.d.ts +3 -0
  35. package/dist/providers/google-genai.js +1196 -0
  36. package/dist/providers/index.d.ts +38 -0
  37. package/dist/providers/index.js +56 -0
  38. package/dist/providers/openai.d.ts +3 -0
  39. package/dist/providers/openai.js +609 -0
  40. package/dist/reactor.d.ts +50 -0
  41. package/dist/reactor.js +920 -0
  42. package/dist/retry-policy.d.ts +31 -0
  43. package/{src/retry-policy.ts → dist/retry-policy.js} +41 -53
  44. package/dist/sse.d.ts +1 -0
  45. package/dist/sse.js +63 -0
  46. package/dist/state.d.ts +23 -0
  47. package/dist/state.js +100 -0
  48. package/dist/tool-name.d.ts +6 -0
  49. package/dist/tool-name.js +110 -0
  50. package/dist/transform.d.ts +11 -0
  51. package/dist/transform.js +117 -0
  52. package/dist/transforms/index.d.ts +2 -0
  53. package/dist/transforms/index.js +1 -0
  54. package/dist/transforms/size-cap.d.ts +12 -0
  55. package/dist/transforms/size-cap.js +80 -0
  56. package/dist/turns.d.ts +21 -0
  57. package/dist/turns.js +135 -0
  58. package/package.json +21 -6
  59. package/src/actions.ts +0 -245
  60. package/src/adapter.ts +0 -57
  61. package/src/assembly.test.ts +0 -728
  62. package/src/assembly.ts +0 -250
  63. package/src/audit-collector.test.ts +0 -332
  64. package/src/audit-collector.ts +0 -172
  65. package/src/auth.test.ts +0 -117
  66. package/src/authz-extension.test.ts +0 -269
  67. package/src/authz-extension.ts +0 -145
  68. package/src/correlation.ts +0 -61
  69. package/src/default-director.test.ts +0 -314
  70. package/src/default-director.ts +0 -344
  71. package/src/director.ts +0 -87
  72. package/src/errors.test.ts +0 -133
  73. package/src/errors.ts +0 -115
  74. package/src/gates.ts +0 -128
  75. package/src/harness.test.ts +0 -655
  76. package/src/harness.ts +0 -1571
  77. package/src/index.ts +0 -76
  78. package/src/providers/anthropic.test.ts +0 -771
  79. package/src/providers/anthropic.ts +0 -810
  80. package/src/providers/google-genai-files.ts +0 -289
  81. package/src/providers/google-genai.ts +0 -1518
  82. package/src/providers/openai.ts +0 -719
  83. package/src/providers/registry.ts +0 -33
  84. package/src/reactor.test.ts +0 -3660
  85. package/src/reactor.ts +0 -1058
  86. package/src/scheduler.test.ts +0 -41
  87. package/src/sse.test.ts +0 -133
  88. package/src/sse.ts +0 -76
  89. package/src/state.ts +0 -135
  90. package/src/transform.test.ts +0 -207
  91. package/src/transform.ts +0 -159
  92. package/src/transforms/index.ts +0 -2
  93. package/src/transforms/size-cap.test.ts +0 -172
  94. package/src/transforms/size-cap.ts +0 -110
  95. package/src/turns.ts +0 -54
  96. package/tsconfig.json +0 -4
  97. package/tsconfig.tsbuildinfo +0 -1
@@ -1,289 +0,0 @@
1
- import { type } from "arktype";
2
-
3
- // Google's Generative Language Files API endpoint for raw single-part
4
- // uploads. The "raw" upload protocol (declared via
5
- // `X-Goog-Upload-Protocol: raw`) accepts the bytes as the request
6
- // body and returns the file resource (uri + metadata) on the
7
- // response. The resumable and multipart protocols target larger
8
- // files and a different endpoint vocabulary; the helper here covers
9
- // only the raw shape because it maps cleanly onto a single fetch.
10
- const FILES_API_UPLOAD_DEFAULT_URL =
11
- "https://generativelanguage.googleapis.com/upload/v1beta/files";
12
-
13
- // Parseable-integer pattern. Accepts an optional minus sign followed
14
- // by digits and nothing else. Excludes whitespace, trailing
15
- // non-digits, scientific notation, decimals. `Number.parseInt`
16
- // alone is permissive on all four ("42abc" parses to 42, " 42"
17
- // parses to 42); this guard makes the wire schema honest.
18
- const PARSEABLE_INTEGER = /^-?\d+$/;
19
-
20
- const FilesApiUploadResponse = type({
21
- file: {
22
- // `> 0` rejects empty strings -- a "" uri is not dereferenceable
23
- // and would slip through a `"string"` validator. Same for the
24
- // mime type.
25
- uri: "string > 0",
26
- mimeType: "string > 0",
27
- // `sizeBytes` lands as a stringified number on the wire. The
28
- // schema accepts string or number; the parser normalizes both
29
- // to a runtime integer at extraction time and throws on any
30
- // value that is not a parseable integer.
31
- "sizeBytes?": "string | number",
32
- "name?": "string",
33
- "state?": "string",
34
- "source?": "string",
35
- "createTime?": "string",
36
- "updateTime?": "string",
37
- "expirationTime?": "string",
38
- "sha256Hash?": "string",
39
- },
40
- });
41
-
42
- /**
43
- * Callable shape the helper accepts for `fetch` injection. Mirrors
44
- * `Dependencies.fetch` on the inference harness, so test doubles
45
- * stay structurally compatible across both surfaces. Bun's global
46
- * `typeof fetch` carries non-callable members (e.g. `preconnect`)
47
- * that test doubles would otherwise have to satisfy gratuitously.
48
- */
49
- export type UploadGoogleGenAIFileFetch = (
50
- input: string | URL | Request,
51
- init?: RequestInit,
52
- ) => Promise<Response>;
53
-
54
- export interface UploadGoogleGenAIFileOpts {
55
- apiKey: string;
56
- mimeType: string;
57
- // Display name surfaced on the file resource. The Files API
58
- // accepts arbitrary strings here; callers typically pass the
59
- // local file's basename.
60
- displayName: string;
61
- bytes: Uint8Array;
62
- // Optional override for the upload endpoint. Defaults to
63
- // Google's public Files API full URL (path included). A
64
- // self-hosted or regional endpoint can be substituted by
65
- // passing the full target URL -- the helper does not append
66
- // any path to this value.
67
- uploadURL?: string;
68
- // Optional fetch implementation. Defaults to the global `fetch`.
69
- fetch?: UploadGoogleGenAIFileFetch;
70
- // Optional AbortSignal for caller cancellation. Forwarded to
71
- // `fetch` verbatim.
72
- signal?: AbortSignal;
73
- }
74
-
75
- export interface UploadedGoogleGenAIFile {
76
- // The dereferenceable `fileUri` the caller threads back into a
77
- // `fileData.fileUri` part on a subsequent inference request, or
78
- // into a `MediaSource` with `kind: "file-reference"`.
79
- fileUri: string;
80
- // The MIME type the API recorded for the file (echoed from the
81
- // upload request).
82
- mimeType: string;
83
- // Size in bytes, normalized from the wire's string-encoded
84
- // integer. Absent on the wire becomes absent here -- the
85
- // helper does not synthesize a value.
86
- sizeBytes?: number;
87
- // Provider-side file id (`files/<id>`). Useful for management
88
- // operations against the Files API (delete, list).
89
- name?: string;
90
- // Lifecycle state (`ACTIVE`, `PROCESSING`, `FAILED`).
91
- state?: string;
92
- }
93
-
94
- // Header values must be free of control characters (CR/LF are
95
- // the smuggling-relevant ones, but NUL and other CTL bytes are
96
- // also illegal per RFC 9110 §5.5 visible-US-ASCII rule). The
97
- // downstream `fetch` typically rejects CR/LF but not NUL, so
98
- // catching the broader set here keeps the diagnostic specific
99
- // to the offending input. This is the boundary that turns
100
- // caller strings into HTTP request structure (per the style
101
- // skill's Data Validation rule), so the check belongs here.
102
- //
103
- // `apiKey` flows through the same guard because the rule is
104
- // "validate at the boundary" -- the boundary cannot know an
105
- // input's provenance, and the caller may not have run their own
106
- // sanity check.
107
- // The guard's whole purpose is to reject CR/LF/NUL/other CTL
108
- // bytes before they reach the downstream fetch, so the regex
109
- // MUST match those code points.
110
- // eslint-disable-next-line no-control-regex
111
- const FORBIDDEN_HEADER_CHARS = /[\x00-\x1f\x7f]/;
112
- function assertHeaderValueSafe(name: string, value: string): void {
113
- if (FORBIDDEN_HEADER_CHARS.test(value)) {
114
- throw new Error(
115
- `google-genai files-API upload: header ${JSON.stringify(name)} ` +
116
- `contains a control character (CR, LF, NUL, or other CTL byte), ` +
117
- `which would let the value smuggle additional headers or be ` +
118
- `rejected downstream with a less specific message.`,
119
- );
120
- }
121
- }
122
-
123
- /**
124
- * Upload bytes to the Gemini Files API and return the file URI.
125
- *
126
- * The Files API is the dereferencable handle path for Gemini media:
127
- * upload once, reference the returned `fileUri` on subsequent
128
- * inference requests via a `fileData.fileUri` part (or a
129
- * `MediaSource` of `kind: "file-reference"` whose `reference` is the
130
- * URI). The trade-off relative to inline `base64` is bytes-on-the-wire:
131
- * inline payloads ship with every request, file references ship
132
- * once and are then quoted.
133
- *
134
- * The helper exclusively uses the "raw" upload protocol (one
135
- * `POST` carries the full bytes). The resumable and multipart
136
- * protocols are out of scope; large-file workflows that need them
137
- * should compose against the Gemini SDK directly.
138
- *
139
- * @throws an Error when the upload returns non-2xx, when the
140
- * response is not JSON, or when the response shape does not
141
- * carry a non-empty `file.uri` + `file.mimeType`. The thrown
142
- * error's message names the failure mode; HTTP errors include
143
- * the status code and a snippet of the response body, and
144
- * schema/JSON failures carry a snippet of the response body too.
145
- */
146
- export async function uploadGoogleGenAIFile(
147
- opts: UploadGoogleGenAIFileOpts,
148
- ): Promise<UploadedGoogleGenAIFile> {
149
- const fetchImpl = opts.fetch ?? fetch;
150
- const url = opts.uploadURL ?? FILES_API_UPLOAD_DEFAULT_URL;
151
-
152
- assertHeaderValueSafe("Content-Type", opts.mimeType);
153
- assertHeaderValueSafe("X-Goog-Upload-File-Name", opts.displayName);
154
- assertHeaderValueSafe("x-goog-api-key", opts.apiKey);
155
-
156
- // The `x-goog-api-key` header is intentionally lowercase to
157
- // match the wire shape Google's Files API responds to (the
158
- // captured `request-headers.json` records the same casing).
159
- // HTTP header names are case-insensitive on the wire, so the
160
- // mixed-case neighbors are functionally identical -- the choice
161
- // is documentation, not behavior.
162
- const headers: Record<string, string> = {
163
- "Content-Type": opts.mimeType,
164
- "X-Goog-Upload-Protocol": "raw",
165
- "X-Goog-Upload-File-Name": opts.displayName,
166
- "x-goog-api-key": opts.apiKey,
167
- };
168
-
169
- const init: RequestInit = {
170
- method: "POST",
171
- headers,
172
- body: opts.bytes,
173
- };
174
- // `RequestInit.signal` is typed as `AbortSignal | null` under
175
- // `exactOptionalPropertyTypes`; only attach the property when
176
- // the caller actually supplied a signal so an absent `signal`
177
- // does not become `undefined` on the init object (which the
178
- // overload then rejects).
179
- if (opts.signal !== undefined) {
180
- init.signal = opts.signal;
181
- }
182
- const response = await fetchImpl(url, init);
183
-
184
- // Read the body as text first, then parse JSON ourselves. This
185
- // keeps a snippet of the actual server response available for
186
- // both the JSON-parse and schema-mismatch error paths; reading
187
- // through `response.json()` would consume the stream before the
188
- // error site can sample it.
189
- let body: string;
190
- try {
191
- body = await response.text();
192
- } catch (cause) {
193
- const message = cause instanceof Error ? cause.message : String(cause);
194
- throw new Error(
195
- `google-genai files-API upload: failed to read response body ` +
196
- `(status ${String(response.status)} ${response.statusText}): ${message}`,
197
- { cause },
198
- );
199
- }
200
-
201
- if (!response.ok) {
202
- throw new Error(
203
- `google-genai files-API upload failed: ${String(response.status)} ` +
204
- `${response.statusText}: ${body.slice(0, 500)}`,
205
- );
206
- }
207
-
208
- let parsed: unknown;
209
- try {
210
- parsed = JSON.parse(body);
211
- } catch (cause) {
212
- const message = cause instanceof Error ? cause.message : String(cause);
213
- throw new Error(
214
- `google-genai files-API upload: response was not valid JSON ` +
215
- `(${message}): ${body.slice(0, 500)}`,
216
- { cause },
217
- );
218
- }
219
-
220
- const validated = FilesApiUploadResponse(parsed);
221
- if (validated instanceof type.errors) {
222
- throw new Error(
223
- `google-genai files-API upload: response did not match the expected ` +
224
- `shape (missing file.uri/mimeType or a malformed file resource): ` +
225
- `${validated.summary}; body: ${body.slice(0, 500)}`,
226
- );
227
- }
228
-
229
- const { file } = validated;
230
- // Normalize `sizeBytes` from `string | number | undefined` to
231
- // `number | undefined`. The wire ships an integer as a string
232
- // ("4193"); the helper rejects strings that are not exactly a
233
- // parseable integer and numbers that are not integers (a size
234
- // in bytes by definition is not fractional). `Number.parseInt`
235
- // alone is permissive ("42abc" parses to 42) so the regex guard
236
- // is what makes the contract honest. The final integer must
237
- // also be non-negative (bytes count up from zero) and within
238
- // JavaScript's safe-integer range -- Files API docs call this
239
- // field int64, and a string like "9007199254740993" silently
240
- // rounds when coerced to a JS number, so a precision check at
241
- // the boundary keeps the returned value faithful to the wire.
242
- function assertSafeNonNegativeInteger(n: number, raw: string | number): void {
243
- if (n < 0) {
244
- throw new Error(
245
- `google-genai files-API upload: file.sizeBytes ` +
246
- `${JSON.stringify(raw)} is negative; a byte count cannot be ` +
247
- `less than zero.`,
248
- );
249
- }
250
- if (n > Number.MAX_SAFE_INTEGER) {
251
- throw new Error(
252
- `google-genai files-API upload: file.sizeBytes ` +
253
- `${JSON.stringify(raw)} exceeds Number.MAX_SAFE_INTEGER and ` +
254
- `cannot be represented as a JS number without precision loss.`,
255
- );
256
- }
257
- }
258
-
259
- let sizeBytes: number | undefined;
260
- if (typeof file.sizeBytes === "string") {
261
- if (!PARSEABLE_INTEGER.test(file.sizeBytes)) {
262
- throw new Error(
263
- `google-genai files-API upload: file.sizeBytes ` +
264
- `${JSON.stringify(file.sizeBytes)} is not a parseable integer.`,
265
- );
266
- }
267
- const parsedSize = Number.parseInt(file.sizeBytes, 10);
268
- assertSafeNonNegativeInteger(parsedSize, file.sizeBytes);
269
- sizeBytes = parsedSize;
270
- } else if (typeof file.sizeBytes === "number") {
271
- if (!Number.isInteger(file.sizeBytes)) {
272
- throw new Error(
273
- `google-genai files-API upload: file.sizeBytes ` +
274
- `${JSON.stringify(file.sizeBytes)} is not an integer.`,
275
- );
276
- }
277
- assertSafeNonNegativeInteger(file.sizeBytes, file.sizeBytes);
278
- sizeBytes = file.sizeBytes;
279
- }
280
-
281
- const result: UploadedGoogleGenAIFile = {
282
- fileUri: file.uri,
283
- mimeType: file.mimeType,
284
- };
285
- if (sizeBytes !== undefined) result.sizeBytes = sizeBytes;
286
- if (file.name !== undefined) result.name = file.name;
287
- if (file.state !== undefined) result.state = file.state;
288
- return result;
289
- }