@intx/inference 0.1.2 → 0.3.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 +176 -0
- package/dist/actions.d.ts +16 -0
- package/dist/actions.js +200 -0
- package/dist/adapter.d.ts +40 -0
- package/dist/adapter.js +31 -0
- package/dist/assembly.d.ts +75 -0
- package/dist/assembly.js +133 -0
- package/dist/audit-collector.d.ts +10 -0
- package/dist/audit-collector.js +139 -0
- package/dist/auth.d.ts +24 -0
- package/{src/auth.ts → dist/auth.js} +13 -19
- package/dist/authz-extension.d.ts +46 -0
- package/dist/authz-extension.js +184 -0
- package/dist/correlation.d.ts +26 -0
- package/dist/correlation.js +39 -0
- package/dist/default-director.d.ts +111 -0
- package/dist/default-director.js +228 -0
- package/dist/director.d.ts +6 -0
- package/dist/director.js +56 -0
- package/dist/errors.d.ts +18 -0
- package/dist/errors.js +83 -0
- package/dist/gates.d.ts +28 -0
- package/dist/gates.js +103 -0
- package/dist/harness.d.ts +147 -0
- package/dist/harness.js +1407 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +21 -0
- package/dist/manifest.d.ts +31 -0
- package/dist/manifest.js +44 -0
- package/dist/providers/anthropic.d.ts +37 -0
- package/dist/providers/anthropic.js +917 -0
- package/dist/providers/google-genai-files.d.ts +48 -0
- package/dist/providers/google-genai-files.js +205 -0
- package/dist/providers/google-genai.d.ts +5 -0
- package/dist/providers/google-genai.js +1205 -0
- package/dist/providers/index.d.ts +38 -0
- package/dist/providers/index.js +56 -0
- package/dist/providers/openai.d.ts +9 -0
- package/dist/providers/openai.js +903 -0
- package/dist/reactor.d.ts +50 -0
- package/dist/reactor.js +1233 -0
- package/dist/retry-policy.d.ts +31 -0
- package/{src/retry-policy.ts → dist/retry-policy.js} +41 -53
- package/dist/sse.d.ts +1 -0
- package/dist/sse.js +63 -0
- package/dist/state.d.ts +23 -0
- package/dist/state.js +100 -0
- package/dist/tool-name.d.ts +6 -0
- package/dist/tool-name.js +110 -0
- package/dist/transform.d.ts +11 -0
- package/dist/transform.js +132 -0
- package/dist/transforms/index.d.ts +2 -0
- package/dist/transforms/index.js +1 -0
- package/dist/transforms/size-cap.d.ts +12 -0
- package/dist/transforms/size-cap.js +80 -0
- package/dist/turns.d.ts +21 -0
- package/dist/turns.js +135 -0
- package/package.json +22 -6
- package/src/actions.ts +0 -245
- package/src/adapter.ts +0 -57
- package/src/assembly.test.ts +0 -728
- package/src/assembly.ts +0 -250
- package/src/audit-collector.test.ts +0 -332
- package/src/audit-collector.ts +0 -172
- package/src/auth.test.ts +0 -117
- package/src/authz-extension.test.ts +0 -269
- package/src/authz-extension.ts +0 -145
- package/src/correlation.ts +0 -61
- package/src/default-director.test.ts +0 -314
- package/src/default-director.ts +0 -344
- package/src/director.ts +0 -87
- package/src/errors.test.ts +0 -133
- package/src/errors.ts +0 -115
- package/src/gates.ts +0 -128
- package/src/harness.test.ts +0 -655
- package/src/harness.ts +0 -1571
- package/src/index.ts +0 -76
- package/src/providers/anthropic.test.ts +0 -771
- package/src/providers/anthropic.ts +0 -810
- package/src/providers/google-genai-files.ts +0 -289
- package/src/providers/google-genai.ts +0 -1518
- package/src/providers/openai.ts +0 -719
- package/src/providers/registry.ts +0 -33
- package/src/reactor.test.ts +0 -3660
- package/src/reactor.ts +0 -1058
- package/src/scheduler.test.ts +0 -41
- package/src/sse.test.ts +0 -133
- package/src/sse.ts +0 -76
- package/src/state.ts +0 -135
- package/src/transform.test.ts +0 -207
- package/src/transform.ts +0 -159
- package/src/transforms/index.ts +0 -2
- package/src/transforms/size-cap.test.ts +0 -172
- package/src/transforms/size-cap.ts +0 -110
- package/src/turns.ts +0 -54
- package/tsconfig.json +0 -4
- 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
|
-
}
|