apple-llm 0.1.0 → 0.2.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/CHANGELOG.md +94 -0
- package/README.md +251 -112
- package/dist/ai-sdk.cjs +281 -0
- package/dist/ai-sdk.d.cts +54 -0
- package/dist/ai-sdk.d.ts +54 -0
- package/dist/ai-sdk.js +281 -0
- package/dist/chunk-GM325EMJ.js +2584 -0
- package/dist/chunk-NRDZIP5G.cjs +2588 -0
- package/dist/chunk-OQATUZWF.cjs +81 -0
- package/dist/chunk-ZB4RDEPW.js +81 -0
- package/dist/cli.js +3163 -24
- package/dist/client-CXewzZTj.d.cts +1160 -0
- package/dist/client-CXewzZTj.d.ts +1160 -0
- package/dist/index.cjs +110 -1667
- package/dist/index.d.cts +84 -627
- package/dist/index.d.ts +84 -627
- package/dist/index.js +31 -1
- package/dist/server.cjs +361 -0
- package/dist/server.d.cts +51 -0
- package/dist/server.d.ts +51 -0
- package/dist/server.js +361 -0
- package/package.json +66 -14
- package/swift/helper.swift +748 -255
- package/dist/chunk-FQTRQ3KP.js +0 -1590
- package/dist/cli.cjs +0 -2027
|
@@ -0,0 +1,1160 @@
|
|
|
1
|
+
import { ChildProcess } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
interface Progress {
|
|
4
|
+
status: string;
|
|
5
|
+
percent?: number;
|
|
6
|
+
}
|
|
7
|
+
type OnProgress = (p: Progress) => void;
|
|
8
|
+
/**
|
|
9
|
+
* Where the compiled helper is cached.
|
|
10
|
+
*
|
|
11
|
+
* Deliberately not namespaced per language binding: the npm and the pip package
|
|
12
|
+
* embed byte-identical Swift, so they derive the same fingerprint and share one
|
|
13
|
+
* compiled binary. Installing both costs one compile, not two.
|
|
14
|
+
*/
|
|
15
|
+
declare function cacheDir(): string;
|
|
16
|
+
/**
|
|
17
|
+
* The cache key: sha256 over the Swift source, a newline, and the target triple,
|
|
18
|
+
* truncated to 12 hex characters.
|
|
19
|
+
*
|
|
20
|
+
* The exact recipe is load-bearing — the Python package computes the same string
|
|
21
|
+
* and must agree byte for byte, or the two would each compile their own copy.
|
|
22
|
+
* A helper edit or an OS upgrade changes it, so both rebuild automatically.
|
|
23
|
+
*/
|
|
24
|
+
declare function fingerprint(source: string, triple: string): string;
|
|
25
|
+
/** The embedded Swift source, shipped as package data beside the built output. */
|
|
26
|
+
declare function helperSource(): Promise<string>;
|
|
27
|
+
/**
|
|
28
|
+
* Compile the helper on first use and cache it. Never called at install time —
|
|
29
|
+
* importing this package on Linux, an Intel Mac or macOS 25 must not fail.
|
|
30
|
+
*
|
|
31
|
+
* `force` bypasses the in-process memo, so a caller can rebuild after the cached
|
|
32
|
+
* binary is removed or found corrupt without restarting the program.
|
|
33
|
+
*
|
|
34
|
+
* The memo is fingerprint-aware: a helper edit or OS upgrade changes the
|
|
35
|
+
* fingerprint, so a stale in-process memo is discarded rather than reused.
|
|
36
|
+
*/
|
|
37
|
+
declare function ensureBinary(onProgress?: OnProgress, options?: {
|
|
38
|
+
force?: boolean;
|
|
39
|
+
}): Promise<string>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Apple's `GenerationSchema` is `Decodable` from JSON Schema, but only accepts a
|
|
43
|
+
* restricted dialect. These rules were established empirically, by decoding
|
|
44
|
+
* real schemas against macOS 26 and 27 until they were accepted:
|
|
45
|
+
*
|
|
46
|
+
* 1. Union types are rejected — `type: ['string','null']` fails with
|
|
47
|
+
* "Expected value of type String". Nullability is expressed by leaving the
|
|
48
|
+
* property out of `required` instead.
|
|
49
|
+
* 2. Every object schema requires an `x-order` array naming its properties in
|
|
50
|
+
* generation order. Omitting it fails with "Key 'x-order' not found".
|
|
51
|
+
* 3. `enum` is not recognized. A node may only carry `type`, `const`, `$ref` or
|
|
52
|
+
* `anyOf`, so enums become `anyOf` of `const` branches.
|
|
53
|
+
* 4. Every object schema *and* every `anyOf` schema requires a `title`, and
|
|
54
|
+
* `$ref` resolves by that title rather than by JSON pointer — so a
|
|
55
|
+
* definition's title must equal the key it is referenced by.
|
|
56
|
+
* 5. Every object schema must state `additionalProperties`; omitting it fails
|
|
57
|
+
* with "Key 'additionalProperties' not found". macOS 26's decoder tolerated
|
|
58
|
+
* its absence, so this one only surfaced on macOS 27.
|
|
59
|
+
*
|
|
60
|
+
* 6. `const` is decoded as a String, always. A numeric member (`const: 200`)
|
|
61
|
+
* fails with "Expected value of type String". Stringifying it is accepted
|
|
62
|
+
* but changes the output type — the model then emits `"200"` rather than
|
|
63
|
+
* `200` — so a numeric enum is converted to its underlying type instead and
|
|
64
|
+
* the literal constraint is dropped. A string-typed status-code union once
|
|
65
|
+
* produced junk like `": 201"`; a plain `integer` is what works.
|
|
66
|
+
* 7. An object with no properties still needs an explicit `properties: {}`.
|
|
67
|
+
* Without it Apple reads `additionalProperties` in its other JSON Schema
|
|
68
|
+
* sense — a schema for the values — and fails with "Expected value of type
|
|
69
|
+
* Dictionary<String, Any>". Supplying a dictionary there is accepted but
|
|
70
|
+
* turns the field into a free-form map the model fills with invented keys.
|
|
71
|
+
*
|
|
72
|
+
* 8. A `title` on a `type: "string"` node is rejected: Apple reads it as a
|
|
73
|
+
* "named string type" and fails with "Named string types must have a
|
|
74
|
+
* non-empty enum field". Other primitives (integer, number, boolean) and
|
|
75
|
+
* arrays accept a title happily. Titles are therefore stripped from plain
|
|
76
|
+
* strings. This matters most for pydantic, whose `model_json_schema()`
|
|
77
|
+
* titles every single property.
|
|
78
|
+
*
|
|
79
|
+
* 9. `pattern` is rejected at generation time with "UnsupportedGuide", for any
|
|
80
|
+
* regex — even `^[A-Z]{3}$`. It is stripped, and checked on the reply
|
|
81
|
+
* instead. (Found on macOS 27.2 through Zod, which puts a pattern on
|
|
82
|
+
* `.email()`, `.uuid()` and `.datetime()`.)
|
|
83
|
+
*
|
|
84
|
+
* Rules 6, 7 and 8 were found by decoding this package's own fixture corpus
|
|
85
|
+
* against macOS 27: they only show up with numeric enums, empty objects, and
|
|
86
|
+
* machine-generated schemas that title every string.
|
|
87
|
+
*
|
|
88
|
+
* macOS 27.2 relaxed rules 2, 4 and 5 for objects: an object without a title,
|
|
89
|
+
* x-order or additionalProperties now decodes. They are still applied, since
|
|
90
|
+
* macOS 26 and 27.0–27.1 require them and they cost nothing where not needed.
|
|
91
|
+
*
|
|
92
|
+
* `$ref` / `$defs` are otherwise supported and pass through untouched.
|
|
93
|
+
*
|
|
94
|
+
* Why this matters more than it looks: constrained decoding makes a schema
|
|
95
|
+
* mistake invisible but total. Collapsing a `["number","string"]` union to
|
|
96
|
+
* `"string"` made it physically impossible for the model to emit a status code —
|
|
97
|
+
* it wrote `": 201"` and the literal `"default"` instead. Never collapse a
|
|
98
|
+
* multi-type union to one branch; convert it to `anyOf`.
|
|
99
|
+
*/
|
|
100
|
+
type JsonSchema = Record<string, unknown>;
|
|
101
|
+
/**
|
|
102
|
+
* Translate a standard JSON Schema into the dialect Apple's `GenerationSchema`
|
|
103
|
+
* accepts. Constrained decoding then makes the shape of the reply a guarantee
|
|
104
|
+
* rather than a request.
|
|
105
|
+
*/
|
|
106
|
+
declare function toAppleSchema(schema: JsonSchema, rootName?: string): JsonSchema;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* OpenAI-style message lists, mapped onto what Apple's model actually has.
|
|
110
|
+
*
|
|
111
|
+
* Apple has one instructions slot, a native transcript of prompt / response /
|
|
112
|
+
* tool-call / tool-output entries, and one new prompt per call. So: every
|
|
113
|
+
* system message joins the instructions, the last user message is the prompt,
|
|
114
|
+
* and everything before it becomes a native transcript — not a text preamble,
|
|
115
|
+
* which the model would read as part of the question.
|
|
116
|
+
*
|
|
117
|
+
* Messages *after* the last user message are a tool exchange in progress: the
|
|
118
|
+
* model asked for tool calls, the caller ran them, and the results are here.
|
|
119
|
+
* Apple cannot resume generation from a tool output without a new prompt, so
|
|
120
|
+
* the exchange is replayed instead: the same prompt runs again, and when the
|
|
121
|
+
* model makes the same call its recorded result is returned immediately rather
|
|
122
|
+
* than executed twice.
|
|
123
|
+
*/
|
|
124
|
+
|
|
125
|
+
interface ChatToolCall {
|
|
126
|
+
id: string;
|
|
127
|
+
name: string;
|
|
128
|
+
arguments: unknown;
|
|
129
|
+
}
|
|
130
|
+
type ChatMessage = {
|
|
131
|
+
role: 'system';
|
|
132
|
+
content: string;
|
|
133
|
+
} | {
|
|
134
|
+
role: 'user';
|
|
135
|
+
content: string;
|
|
136
|
+
images?: ImageAttachment[];
|
|
137
|
+
} | {
|
|
138
|
+
role: 'assistant';
|
|
139
|
+
content?: string | null;
|
|
140
|
+
toolCalls?: ChatToolCall[];
|
|
141
|
+
} | {
|
|
142
|
+
role: 'tool';
|
|
143
|
+
toolCallId: string;
|
|
144
|
+
name?: string;
|
|
145
|
+
content: string;
|
|
146
|
+
};
|
|
147
|
+
/** The helper's wire form of one history entry. */
|
|
148
|
+
type HistoryEntry = {
|
|
149
|
+
role: 'user';
|
|
150
|
+
content: string;
|
|
151
|
+
} | {
|
|
152
|
+
role: 'assistant';
|
|
153
|
+
content: string;
|
|
154
|
+
toolCalls?: ChatToolCall[];
|
|
155
|
+
} | {
|
|
156
|
+
role: 'tool';
|
|
157
|
+
toolCallId: string;
|
|
158
|
+
name: string;
|
|
159
|
+
content: string;
|
|
160
|
+
};
|
|
161
|
+
/** A tool result recorded by the caller, to be handed back if the model repeats the call. */
|
|
162
|
+
interface ReplayedResult {
|
|
163
|
+
name: string;
|
|
164
|
+
arguments: unknown;
|
|
165
|
+
output: string;
|
|
166
|
+
}
|
|
167
|
+
interface SplitMessages {
|
|
168
|
+
system?: string;
|
|
169
|
+
history: HistoryEntry[];
|
|
170
|
+
prompt: string;
|
|
171
|
+
/** Images on the last user message, which the model sees. */
|
|
172
|
+
images: ImageAttachment[];
|
|
173
|
+
replay: ReplayedResult[];
|
|
174
|
+
}
|
|
175
|
+
/** Map message lists onto instructions + history + prompt (+ replayed tool results). */
|
|
176
|
+
declare function splitMessages(messages: ReadonlyArray<ChatMessage>): SplitMessages;
|
|
177
|
+
/**
|
|
178
|
+
* Hands recorded results back to repeated calls: an exact (name, arguments)
|
|
179
|
+
* match first, then the next unused result for that tool name — the model's
|
|
180
|
+
* second attempt at "Paris, France" should still get the Paris weather.
|
|
181
|
+
*/
|
|
182
|
+
declare class ReplayBook {
|
|
183
|
+
private readonly unused;
|
|
184
|
+
constructor(results: ReadonlyArray<ReplayedResult>);
|
|
185
|
+
take(name: string, args: unknown): string | undefined;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** How a child is created. Injectable so tests can script stdout without Apple hardware. */
|
|
189
|
+
type Spawner = (binary: string, args: string[]) => ChildProcess;
|
|
190
|
+
interface HelperServerOptions {
|
|
191
|
+
timeoutMs?: number;
|
|
192
|
+
spawner?: Spawner;
|
|
193
|
+
}
|
|
194
|
+
/** A line the helper sent before a request's final line (`"done": false`). */
|
|
195
|
+
type HelperEvent = Record<string, unknown> & {
|
|
196
|
+
done: false;
|
|
197
|
+
};
|
|
198
|
+
interface RequestHooks {
|
|
199
|
+
/** Called for every event line; `write` sends a control line for this request. */
|
|
200
|
+
onEvent?: (event: HelperEvent, write: (control: Record<string, unknown>) => void) => void;
|
|
201
|
+
/** Cancels the request: a queued one is never sent, a running one is cancelled in the helper. */
|
|
202
|
+
signal?: AbortSignal;
|
|
203
|
+
/** Request id, the target of a cancel line. Needed to cancel mid-flight. */
|
|
204
|
+
id?: string;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* A long-lived helper process speaking newline-delimited JSON.
|
|
208
|
+
*
|
|
209
|
+
* This is the single most important piece of the on-device path. Spawning a
|
|
210
|
+
* helper per request measured ~17s per call against ~1.5s once the model was
|
|
211
|
+
* resident, with identical prompts and identically short outputs — so keeping
|
|
212
|
+
* one process alive is worth roughly an order of magnitude. Both failure modes
|
|
213
|
+
* it guards against are silent: they produce correct output, just 10-20x
|
|
214
|
+
* slower.
|
|
215
|
+
*
|
|
216
|
+
* Requests are serialised, and that costs nothing: Apple's framework serialises
|
|
217
|
+
* inference anyway. Four concurrent requests measured 29.19s against 29.45s
|
|
218
|
+
* sequentially, so concurrency > 1 buys precisely nothing. A request owns the
|
|
219
|
+
* head of the queue from the moment it is written until its final line; the
|
|
220
|
+
* lines in between (`"done": false`) are its events — stream deltas, partial
|
|
221
|
+
* objects, tool calls — and nothing else is written meanwhile except control
|
|
222
|
+
* lines for that same request.
|
|
223
|
+
*
|
|
224
|
+
* The child is unref'd whenever nothing is in flight, so a script that forgets
|
|
225
|
+
* `close()` still exits instead of hanging on an idle helper.
|
|
226
|
+
*/
|
|
227
|
+
declare class HelperServer {
|
|
228
|
+
private readonly binary;
|
|
229
|
+
private child;
|
|
230
|
+
private buffer;
|
|
231
|
+
private queue;
|
|
232
|
+
/** Serialises callers so one request's reply cannot be handed to another. */
|
|
233
|
+
private chain;
|
|
234
|
+
private inFlight;
|
|
235
|
+
/** The helper's recent stderr, quoted when it dies. Always drained: an unread pipe blocks the writer. */
|
|
236
|
+
private stderrTail;
|
|
237
|
+
private readonly timeoutMs;
|
|
238
|
+
private readonly spawner;
|
|
239
|
+
constructor(binary: string, options?: HelperServerOptions);
|
|
240
|
+
private start;
|
|
241
|
+
/** Keep the event loop alive only while a request is in flight. */
|
|
242
|
+
private setRef;
|
|
243
|
+
/** Route one line: an event to the head's hooks, anything else completes the head. */
|
|
244
|
+
private dispatch;
|
|
245
|
+
/**
|
|
246
|
+
* (Re)start the wedge timer. It measures silence, not total time: every
|
|
247
|
+
* event resets it, so a long stream is fine while a helper that stops
|
|
248
|
+
* talking is not.
|
|
249
|
+
*/
|
|
250
|
+
private arm;
|
|
251
|
+
/**
|
|
252
|
+
* Pause the wedge timer while the client itself is busy — a function tool
|
|
253
|
+
* running in JS. The helper is legitimately silent then: it is waiting on us.
|
|
254
|
+
*/
|
|
255
|
+
pause(): void;
|
|
256
|
+
/** Resume the wedge timer paused by `pause()`. */
|
|
257
|
+
resume(): void;
|
|
258
|
+
private timeOut;
|
|
259
|
+
/** Write a control line (cancel, toolResult) for the request in flight. */
|
|
260
|
+
write(control: Record<string, unknown>): void;
|
|
261
|
+
/**
|
|
262
|
+
* One request. Resolves with its final line; events go to `hooks.onEvent`.
|
|
263
|
+
* Serialised against every other request through one chain.
|
|
264
|
+
*/
|
|
265
|
+
request(payload: string, hooks?: RequestHooks): Promise<string>;
|
|
266
|
+
/** Version-1 shape: one request, one line. */
|
|
267
|
+
send(payload: string, hooks?: RequestHooks): Promise<string>;
|
|
268
|
+
/**
|
|
269
|
+
* Streaming request, kept for callers of the version-1 API: deltas go to
|
|
270
|
+
* `onDelta` and the promise resolves with the final line.
|
|
271
|
+
*/
|
|
272
|
+
stream(payload: string, onDelta: (delta: string) => void, hooks?: RequestHooks): Promise<string>;
|
|
273
|
+
stop(): void;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Schema interop without a dependency.
|
|
278
|
+
*
|
|
279
|
+
* Any library implementing Standard Schema (https://standardschema.dev) *and*
|
|
280
|
+
* Standard JSON Schema — Zod 4.2+, ArkType 2.1+, Valibot through
|
|
281
|
+
* `toStandardJsonSchema()` — can be passed wherever a JSON Schema is accepted.
|
|
282
|
+
* The JSON Schema goes to Apple's decoder; the library's own `validate` runs on
|
|
283
|
+
* the reply, so refinements the decoder cannot enforce (`.email()`, `.min(3)`,
|
|
284
|
+
* transforms, defaults) still apply, and the result is typed by the library.
|
|
285
|
+
*
|
|
286
|
+
* The interfaces below are copied from the spec rather than imported: the spec
|
|
287
|
+
* is designed to be vendored, and the package stays at zero dependencies.
|
|
288
|
+
*/
|
|
289
|
+
|
|
290
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
291
|
+
readonly '~standard': StandardSchemaV1.Props<Input, Output>;
|
|
292
|
+
}
|
|
293
|
+
declare namespace StandardSchemaV1 {
|
|
294
|
+
interface Props<Input = unknown, Output = Input> {
|
|
295
|
+
readonly version: 1;
|
|
296
|
+
readonly vendor: string;
|
|
297
|
+
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
298
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
299
|
+
}
|
|
300
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
301
|
+
interface SuccessResult<Output> {
|
|
302
|
+
readonly value: Output;
|
|
303
|
+
readonly issues?: undefined;
|
|
304
|
+
}
|
|
305
|
+
interface FailureResult {
|
|
306
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
307
|
+
}
|
|
308
|
+
interface Issue {
|
|
309
|
+
readonly message: string;
|
|
310
|
+
readonly path?: ReadonlyArray<PropertyKey | {
|
|
311
|
+
readonly key: PropertyKey;
|
|
312
|
+
}> | undefined;
|
|
313
|
+
}
|
|
314
|
+
interface Types<Input = unknown, Output = Input> {
|
|
315
|
+
readonly input: Input;
|
|
316
|
+
readonly output: Output;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/** The Standard JSON Schema extension: a schema that can describe itself. */
|
|
320
|
+
interface StandardJSONSchemaV1 {
|
|
321
|
+
readonly '~standard': {
|
|
322
|
+
readonly jsonSchema: {
|
|
323
|
+
readonly input: (options: {
|
|
324
|
+
target: string;
|
|
325
|
+
}) => Record<string, unknown>;
|
|
326
|
+
readonly output: (options: {
|
|
327
|
+
target: string;
|
|
328
|
+
}) => Record<string, unknown>;
|
|
329
|
+
};
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/** Anything `json()`, `streamJson()` and `tool()` accept as a schema. */
|
|
333
|
+
type SchemaLike = JsonSchema | StandardSchemaV1;
|
|
334
|
+
/** The parsed type a schema produces: inferred for Standard Schemas, `unknown` for plain JSON Schema. */
|
|
335
|
+
type InferSchema<S> = S extends StandardSchemaV1<any, infer Output> ? Output : unknown;
|
|
336
|
+
declare function isStandardSchema(value: unknown): value is StandardSchemaV1;
|
|
337
|
+
/** A schema reduced to the two things this package needs from it. */
|
|
338
|
+
interface ResolvedSchema {
|
|
339
|
+
/** Plain JSON Schema, before the Apple-dialect rewrite. */
|
|
340
|
+
json: JsonSchema;
|
|
341
|
+
/** The library's validator, when there is one. */
|
|
342
|
+
validate?: (value: unknown) => Promise<StandardSchemaV1.Result<unknown>>;
|
|
343
|
+
}
|
|
344
|
+
declare function resolveSchema(schema: SchemaLike): ResolvedSchema;
|
|
345
|
+
/**
|
|
346
|
+
* Put back the `null`s Apple's dialect took away.
|
|
347
|
+
*
|
|
348
|
+
* Apple has no union types, so a property that is required-but-nullable is
|
|
349
|
+
* rewritten as simply not required, and the model then omits it rather than
|
|
350
|
+
* writing `null`. Your schema still says the key must be present, so a
|
|
351
|
+
* validator (or plain code reading `obj.key === null`) would reject or
|
|
352
|
+
* misread the reply. This walks the *original* schema and fills each such
|
|
353
|
+
* missing key with `null`. Never overwrites a value the model produced.
|
|
354
|
+
*/
|
|
355
|
+
declare function restoreNulls(value: unknown, schema: JsonSchema, root?: JsonSchema, depth?: number): unknown;
|
|
356
|
+
|
|
357
|
+
/** Apple's built-in on-device tools (all macOS 27+, all local). */
|
|
358
|
+
type BuiltInTool = 'ocr' | 'barcode' | 'spotlight';
|
|
359
|
+
interface ToolExecutionContext {
|
|
360
|
+
/** The id of this call, as it will appear in `toolCalls`. */
|
|
361
|
+
toolCallId: string;
|
|
362
|
+
/** Fires when the request is aborted; long-running tools should honour it. */
|
|
363
|
+
signal?: AbortSignal;
|
|
364
|
+
}
|
|
365
|
+
interface FunctionTool<Args = any, Result = unknown> {
|
|
366
|
+
/** What the model calls it. Letters, digits, `_` and `-`; must start with a letter or `_`. */
|
|
367
|
+
name: string;
|
|
368
|
+
/** When to use it. The model reads this, so write it for the model. */
|
|
369
|
+
description?: string;
|
|
370
|
+
/** JSON Schema or a Standard Schema (Zod, ArkType, …). Omit for a tool that takes no arguments. */
|
|
371
|
+
parameters?: SchemaLike;
|
|
372
|
+
/**
|
|
373
|
+
* Runs the tool. Return a string, or anything JSON-serialisable. Omit it for
|
|
374
|
+
* a client-driven tool that stops generation instead (see above).
|
|
375
|
+
* A thrown error ends the request with a ToolExecutionError whose `cause` is
|
|
376
|
+
* your error; return an error *message* instead if the model should see it
|
|
377
|
+
* and recover.
|
|
378
|
+
*/
|
|
379
|
+
execute?: (args: Args, context: ToolExecutionContext) => Result | Promise<Result>;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Define a function tool, with the argument type inferred from a Standard
|
|
383
|
+
* Schema.
|
|
384
|
+
*
|
|
385
|
+
* const weather = tool({
|
|
386
|
+
* name: 'getWeather',
|
|
387
|
+
* description: 'Current weather for a city',
|
|
388
|
+
* parameters: z.object({ city: z.string() }),
|
|
389
|
+
* execute: async ({ city }) => fetchWeather(city), // city: string
|
|
390
|
+
* });
|
|
391
|
+
*/
|
|
392
|
+
declare function tool<S extends SchemaLike, Result = unknown>(definition: {
|
|
393
|
+
name: string;
|
|
394
|
+
description?: string;
|
|
395
|
+
parameters?: S;
|
|
396
|
+
execute?: (args: InferSchema<S>, context: ToolExecutionContext) => Result | Promise<Result>;
|
|
397
|
+
}): FunctionTool<InferSchema<S>, Result>;
|
|
398
|
+
/** Everything `tools` accepts: built-in names, function tools, or a record of function tools keyed by name. */
|
|
399
|
+
type ToolSet = ReadonlyArray<BuiltInTool | FunctionTool> | Readonly<Record<string, Omit<FunctionTool, 'name'> & {
|
|
400
|
+
name?: string;
|
|
401
|
+
}>>;
|
|
402
|
+
interface NormalizedTools {
|
|
403
|
+
builtIn: BuiltInTool[];
|
|
404
|
+
functions: Array<FunctionTool & {
|
|
405
|
+
resolved?: ResolvedSchema;
|
|
406
|
+
json: JsonSchema;
|
|
407
|
+
}>;
|
|
408
|
+
}
|
|
409
|
+
/** Split and check a tool set. Throws before any model call on a bad definition. */
|
|
410
|
+
declare function normalizeTools(tools: ToolSet | undefined): NormalizedTools;
|
|
411
|
+
/** Tool output as the model will read it. */
|
|
412
|
+
declare function toolOutputText(value: unknown): string;
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Sampling temperature. Not zero on purpose.
|
|
416
|
+
*
|
|
417
|
+
* Constrained decoding already guarantees the schema, so greedy decoding buys
|
|
418
|
+
* nothing and reliably degenerates: at 0 the model padded an unbounded array
|
|
419
|
+
* forever, then ran away *inside a single string*, emitting 2.7KB of
|
|
420
|
+
* "tasks-tasks-tasks-…". A 2s call became 20s. Apple honours `maxItems` but
|
|
421
|
+
* ignores `maxLength`, so bounding strings is not available as a fix — a little
|
|
422
|
+
* sampling is. Nothing about this is a quality/creativity tradeoff.
|
|
423
|
+
*/
|
|
424
|
+
declare const DEFAULT_TEMPERATURE = 0.4;
|
|
425
|
+
/**
|
|
426
|
+
* Cap on generated tokens. Left uncapped, the model occasionally runs away and
|
|
427
|
+
* only stops when it exhausts the context window — one observed run burned
|
|
428
|
+
* ~206s before failing. This bounds that to well under a minute while leaving
|
|
429
|
+
* room for a few paragraphs of prose.
|
|
430
|
+
*/
|
|
431
|
+
declare const DEFAULT_MAX_TOKENS = 2048;
|
|
432
|
+
/**
|
|
433
|
+
* Tool calls allowed in one request before the model is told to stop calling
|
|
434
|
+
* and answer. A small model can loop on a tool whose output it misreads.
|
|
435
|
+
*/
|
|
436
|
+
declare const DEFAULT_MAX_TOOL_CALLS = 8;
|
|
437
|
+
/** What the model can actually do, as reported by the framework (macOS 27+). */
|
|
438
|
+
interface ModelCapabilities {
|
|
439
|
+
vision: boolean;
|
|
440
|
+
guidedGeneration: boolean;
|
|
441
|
+
reasoning: boolean;
|
|
442
|
+
toolCalling: boolean;
|
|
443
|
+
}
|
|
444
|
+
/** Feature flags reported by --probe (absent on older helpers). */
|
|
445
|
+
interface HelperFeatures {
|
|
446
|
+
protocol?: number;
|
|
447
|
+
streaming: boolean;
|
|
448
|
+
structuredStreaming?: boolean;
|
|
449
|
+
sessions: boolean;
|
|
450
|
+
history: boolean;
|
|
451
|
+
transcripts?: boolean;
|
|
452
|
+
labelledAttachments: boolean;
|
|
453
|
+
functionTools?: boolean;
|
|
454
|
+
cancellation?: boolean;
|
|
455
|
+
builtInTools: string[];
|
|
456
|
+
}
|
|
457
|
+
/** An image attachment: a bare path, or a path with a Siri-style label. */
|
|
458
|
+
type ImageAttachment = string | {
|
|
459
|
+
path: string;
|
|
460
|
+
label?: string;
|
|
461
|
+
};
|
|
462
|
+
/** A history turn mirrored by the helper for a named session. */
|
|
463
|
+
interface HistoryTurn {
|
|
464
|
+
role: string;
|
|
465
|
+
content: string;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Private Cloud Compute quota, read from the framework without calling it.
|
|
469
|
+
*
|
|
470
|
+
* PCC *inference* needs an entitlement no installable package can ship, which is
|
|
471
|
+
* why the cloud tier goes through Shortcuts — but `quotaUsage` is readable from
|
|
472
|
+
* an unentitled process, so this is real first-party quota state rather than a
|
|
473
|
+
* guess parsed out of an error message.
|
|
474
|
+
*/
|
|
475
|
+
interface CloudQuota {
|
|
476
|
+
isAvailable: boolean;
|
|
477
|
+
status: 'belowLimit' | 'limitReached' | 'unknown';
|
|
478
|
+
approachingLimit?: boolean;
|
|
479
|
+
resetDate?: string;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* The Private Cloud Compute model as the framework describes it (macOS 27+):
|
|
483
|
+
* quota, capabilities and context size, all readable without the entitlement
|
|
484
|
+
* that blocks calling it directly.
|
|
485
|
+
*/
|
|
486
|
+
interface CloudModelInfo extends CloudQuota {
|
|
487
|
+
capabilities?: ModelCapabilities;
|
|
488
|
+
contextSize?: number;
|
|
489
|
+
}
|
|
490
|
+
interface DeviceProbe {
|
|
491
|
+
available: boolean;
|
|
492
|
+
reason?: string;
|
|
493
|
+
contextSize?: number;
|
|
494
|
+
variant?: string;
|
|
495
|
+
/** macOS 27+ only; absent on macOS 26. */
|
|
496
|
+
capabilities?: ModelCapabilities;
|
|
497
|
+
useCases?: string[];
|
|
498
|
+
/** Helper feature flags; absent when the cached binary predates them. */
|
|
499
|
+
features?: HelperFeatures;
|
|
500
|
+
/** PCC quota and model info, surfaced here because the on-device helper is what can read them. */
|
|
501
|
+
cloud?: CloudModelInfo;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* How tokens are chosen.
|
|
505
|
+
*
|
|
506
|
+
* `greedy` is deterministic but degenerates under guided generation — it is the
|
|
507
|
+
* `temperature: 0` trap by another name. The seeded modes give the same
|
|
508
|
+
* reproducibility *without* that failure: `{ mode: 'topK', k: 50, seed: 42 }`
|
|
509
|
+
* returned byte-identical output across three runs here. Determinism relies on
|
|
510
|
+
* a fresh session per request, which is the default.
|
|
511
|
+
*/
|
|
512
|
+
type SamplingMode = {
|
|
513
|
+
mode: 'greedy';
|
|
514
|
+
} | {
|
|
515
|
+
mode: 'topK';
|
|
516
|
+
k?: number;
|
|
517
|
+
seed?: number;
|
|
518
|
+
} | {
|
|
519
|
+
mode: 'threshold';
|
|
520
|
+
p?: number;
|
|
521
|
+
seed?: number;
|
|
522
|
+
};
|
|
523
|
+
/** Apple ships a use case specialised for tagging and topic extraction. */
|
|
524
|
+
type UseCase = 'general' | 'contentTagging';
|
|
525
|
+
/**
|
|
526
|
+
* `permissive` selects `permissiveContentTransformations`, which relaxes the
|
|
527
|
+
* guardrails for content *transformation* — rewriting or summarising text the
|
|
528
|
+
* default guardrails would refuse to touch.
|
|
529
|
+
*/
|
|
530
|
+
type Guardrails = 'default' | 'permissive';
|
|
531
|
+
/** Token accounting for one generation (macOS 27+). */
|
|
532
|
+
interface Usage {
|
|
533
|
+
inputTokens: number;
|
|
534
|
+
outputTokens: number;
|
|
535
|
+
totalTokens: number;
|
|
536
|
+
/** Prompt tokens served from the session's cache — a conversation's earlier turns. */
|
|
537
|
+
cachedInputTokens?: number;
|
|
538
|
+
}
|
|
539
|
+
/** Why generation ended. `length` means `maxTokens` cut it off; `tool-calls` means a client-driven tool is waiting. */
|
|
540
|
+
type FinishReason = 'stop' | 'length' | 'tool-calls';
|
|
541
|
+
/** One tool call the model made while producing a reply. */
|
|
542
|
+
interface ToolCallRecord {
|
|
543
|
+
id: string;
|
|
544
|
+
name: string;
|
|
545
|
+
arguments: unknown;
|
|
546
|
+
/** What the tool returned to the model. Absent for a client-driven call not yet run. */
|
|
547
|
+
output?: string;
|
|
548
|
+
}
|
|
549
|
+
interface DeviceRequest {
|
|
550
|
+
system?: string;
|
|
551
|
+
prompt: string;
|
|
552
|
+
schema?: JsonSchema | null;
|
|
553
|
+
temperature?: number;
|
|
554
|
+
maxTokens?: number;
|
|
555
|
+
/** Image attachments. Entries may carry a label for follow-up turns. */
|
|
556
|
+
images?: ImageAttachment[];
|
|
557
|
+
/** Text documents inlined into the prompt client-side (see withDocuments). */
|
|
558
|
+
documents?: string[];
|
|
559
|
+
/** Named multi-turn conversation; the helper keeps the native transcript. */
|
|
560
|
+
sessionId?: string;
|
|
561
|
+
/** Earlier turns, sent as a native transcript (stateless multi-turn). */
|
|
562
|
+
history?: HistoryEntry[];
|
|
563
|
+
/** Drop the oldest history turns rather than fail when they do not fit. */
|
|
564
|
+
trimHistory?: boolean;
|
|
565
|
+
/** Built-in Apple tools: on-device OCR, barcode reading, Spotlight RAG. */
|
|
566
|
+
tools?: BuiltInTool[];
|
|
567
|
+
/** Function tools, already normalised (see normalizeTools). */
|
|
568
|
+
functions?: NormalizedTools['functions'];
|
|
569
|
+
useCase?: UseCase;
|
|
570
|
+
guardrails?: Guardrails;
|
|
571
|
+
sampling?: SamplingMode;
|
|
572
|
+
/** Send the schema in the prompt as well as to the decoder. See helper.swift. */
|
|
573
|
+
includeSchemaInPrompt?: boolean;
|
|
574
|
+
/**
|
|
575
|
+
* Reuse one session across calls. Off by default: it makes unrelated calls
|
|
576
|
+
* share a transcript. See the note in helper.swift.
|
|
577
|
+
* Prefer sessionId for conversations; this flag is the legacy single slot.
|
|
578
|
+
*/
|
|
579
|
+
reuseSession?: boolean;
|
|
580
|
+
}
|
|
581
|
+
/** Per-call hooks for `run`. */
|
|
582
|
+
interface RunHooks {
|
|
583
|
+
signal?: AbortSignal;
|
|
584
|
+
onDelta?: (delta: string) => void;
|
|
585
|
+
/** Each partial JSON document while streaming with a schema. */
|
|
586
|
+
onPartial?: (json: string) => void;
|
|
587
|
+
/** Every tool call, as the model makes it. */
|
|
588
|
+
onToolCall?: (call: ToolCallRecord) => void;
|
|
589
|
+
/** Results the caller already has for calls the model may repeat. */
|
|
590
|
+
replay?: ReplayBook;
|
|
591
|
+
maxToolCalls?: number;
|
|
592
|
+
}
|
|
593
|
+
/** What one generation produced. */
|
|
594
|
+
interface DeviceOutcome {
|
|
595
|
+
content: string;
|
|
596
|
+
finishReason: FinishReason;
|
|
597
|
+
usage?: Usage;
|
|
598
|
+
toolCalls: ToolCallRecord[];
|
|
599
|
+
trimmedTurns: number;
|
|
600
|
+
}
|
|
601
|
+
/** Assert every requested tool is one the helper knows, before spending a call. */
|
|
602
|
+
declare function assertTools(tools: BuiltInTool[] | undefined): void;
|
|
603
|
+
/** Probe the on-device model without constructing a client. */
|
|
604
|
+
declare function probeDevice(onProgress?: OnProgress): Promise<DeviceProbe>;
|
|
605
|
+
/**
|
|
606
|
+
* The on-device tier: Apple's `FoundationModels` framework, reached through a
|
|
607
|
+
* self-compiled Swift helper. Nothing leaves the machine.
|
|
608
|
+
*/
|
|
609
|
+
interface DeviceClientOptions {
|
|
610
|
+
useCase?: UseCase;
|
|
611
|
+
guardrails?: Guardrails;
|
|
612
|
+
/**
|
|
613
|
+
* A ready helper to use instead of probing and compiling one. For tests,
|
|
614
|
+
* which script a fake helper; not needed in normal use.
|
|
615
|
+
*/
|
|
616
|
+
server?: HelperServer;
|
|
617
|
+
}
|
|
618
|
+
declare class DeviceClient {
|
|
619
|
+
private readonly options;
|
|
620
|
+
private binary?;
|
|
621
|
+
private probeResult?;
|
|
622
|
+
private server?;
|
|
623
|
+
private readying?;
|
|
624
|
+
constructor(options?: DeviceClientOptions);
|
|
625
|
+
get label(): string;
|
|
626
|
+
get contextSize(): number | undefined;
|
|
627
|
+
/** Probe and build once; concurrent first calls share the one attempt. */
|
|
628
|
+
ensureReady(onProgress?: OnProgress): Promise<void>;
|
|
629
|
+
getProbe(): DeviceProbe | undefined;
|
|
630
|
+
private helper;
|
|
631
|
+
/** Send one single-line envelope and return the parsed reply, raising a typed error on failure. */
|
|
632
|
+
private exchange;
|
|
633
|
+
/** The request envelope, shared by every generation path. */
|
|
634
|
+
private envelopeFor;
|
|
635
|
+
/**
|
|
636
|
+
* One generation, with every event handled: text deltas, partial objects,
|
|
637
|
+
* and function tool calls, which run here and answer the helper.
|
|
638
|
+
*/
|
|
639
|
+
run(request: DeviceRequest, op?: 'generate' | 'stream', hooks?: RunHooks): Promise<DeviceOutcome>;
|
|
640
|
+
/** One request. Returns the helper's `content` string, unparsed. */
|
|
641
|
+
complete(request: DeviceRequest, hooks?: RunHooks): Promise<string>;
|
|
642
|
+
/**
|
|
643
|
+
* Streaming text. Deltas arrive via onDelta as the model generates; the
|
|
644
|
+
* promise resolves with the full text.
|
|
645
|
+
*/
|
|
646
|
+
stream(prompt: string, options?: Omit<DeviceRequest, 'prompt' | 'schema'> & {
|
|
647
|
+
onDelta?: (delta: string) => void;
|
|
648
|
+
signal?: AbortSignal;
|
|
649
|
+
}): Promise<string>;
|
|
650
|
+
/**
|
|
651
|
+
* Conversation history for a named session: the mirrored turns the helper
|
|
652
|
+
* persisted, oldest first. Survives helper restarts, and the next call
|
|
653
|
+
* rebuilds the native transcript from it.
|
|
654
|
+
*/
|
|
655
|
+
history(sessionId: string): Promise<{
|
|
656
|
+
instructions: string;
|
|
657
|
+
history: HistoryTurn[];
|
|
658
|
+
}>;
|
|
659
|
+
/** Drop a named session (and its persisted history), or all of them. */
|
|
660
|
+
resetSession(sessionId?: string): Promise<void>;
|
|
661
|
+
/**
|
|
662
|
+
* How many tokens a request costs, before sending it.
|
|
663
|
+
*
|
|
664
|
+
* The point is to turn a ContextLengthError into an arithmetic check: compare
|
|
665
|
+
* against `contextSize` and trim, rather than discovering the ceiling by
|
|
666
|
+
* hitting it. Counts everything that shares the window: instructions,
|
|
667
|
+
* history, tools, schema, images and inlined documents.
|
|
668
|
+
*/
|
|
669
|
+
countTokens(prompt: string, options?: {
|
|
670
|
+
system?: string;
|
|
671
|
+
images?: ImageAttachment[];
|
|
672
|
+
tools?: BuiltInTool[];
|
|
673
|
+
documents?: string[];
|
|
674
|
+
history?: HistoryEntry[];
|
|
675
|
+
schema?: JsonSchema;
|
|
676
|
+
functions?: NormalizedTools['functions'];
|
|
677
|
+
signal?: AbortSignal;
|
|
678
|
+
}): Promise<{
|
|
679
|
+
tokens: number;
|
|
680
|
+
contextSize: number;
|
|
681
|
+
}>;
|
|
682
|
+
/**
|
|
683
|
+
* Load the model assets now so the first real call does not pay for it.
|
|
684
|
+
*
|
|
685
|
+
* Cheap and idempotent, but do not expect much on a warm machine: with the
|
|
686
|
+
* assets already resident this measured 0.31s against 0.36s for an
|
|
687
|
+
* unprewarmed first call — inside the noise. The win is on a genuinely cold
|
|
688
|
+
* system, where the very first call to the framework here took 7.8s. Worth
|
|
689
|
+
* calling at startup when you know a request is coming; not worth building
|
|
690
|
+
* around.
|
|
691
|
+
*/
|
|
692
|
+
prewarm(system?: string): Promise<void>;
|
|
693
|
+
text(prompt: string, options?: Omit<DeviceRequest, 'prompt' | 'schema'>): Promise<string>;
|
|
694
|
+
json(prompt: string, options: Omit<DeviceRequest, 'prompt'> & {
|
|
695
|
+
schema: JsonSchema;
|
|
696
|
+
}): Promise<unknown>;
|
|
697
|
+
/** Shut the helper process down. Safe to call more than once. */
|
|
698
|
+
close(): void;
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Inline text documents into the prompt client-side.
|
|
702
|
+
*
|
|
703
|
+
* The helper's vision path handles images; plain-text sources (.txt/.md/.json
|
|
704
|
+
* and friends) are cheaper to splice here than to teach the Swift side about.
|
|
705
|
+
* Binary files are refused loudly — silently skipping a document the caller
|
|
706
|
+
* asked about would be the vision-drop trap by another name.
|
|
707
|
+
*/
|
|
708
|
+
declare function withDocuments(prompt: string, documents: string[] | undefined): Promise<string>;
|
|
709
|
+
/** Parse a CLI --image value: "path" or "path::label". */
|
|
710
|
+
declare function parseImageFlag(value: string): ImageAttachment;
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* Apple's Private Cloud Compute model, reached through the Shortcuts action
|
|
714
|
+
* `is.workflow.actions.askllm`.
|
|
715
|
+
*
|
|
716
|
+
* Why this route rather than the framework: macOS 27 exposes
|
|
717
|
+
* `FoundationModels.PrivateCloudComputeLanguageModel` as public API and it even
|
|
718
|
+
* reports `isAvailable: true`, but every call fails with `ModelManagerError
|
|
719
|
+
* 1046` unless the process carries `com.apple.developer.private-cloud-compute`.
|
|
720
|
+
* That entitlement is AMFI-restricted — an ad-hoc-signed binary carrying it is
|
|
721
|
+
* SIGKILLed (exit 137), and wrapping it in a signed .app with a real bundle ID
|
|
722
|
+
* does not help. It needs a paid Developer Program provisioning profile, which
|
|
723
|
+
* no installable package can ship. Shortcuts.app already holds the entitlement
|
|
724
|
+
* and `/usr/bin/shortcuts` is public, so a generated shortcut is the only route
|
|
725
|
+
* that works. Do not spend time re-confirming this.
|
|
726
|
+
*
|
|
727
|
+
* This tier sends your prompt off the machine. It is not local.
|
|
728
|
+
*
|
|
729
|
+
* Measured on an M4 Air: ~2s typical, ~11s at 14k tokens.
|
|
730
|
+
*/
|
|
731
|
+
/** Distinctive, so `shortcuts run` cannot match a shortcut the user wrote. */
|
|
732
|
+
declare const CLOUD_SHORTCUT_NAME = "Apple LLM Cloud";
|
|
733
|
+
/** Web search is fixed in the shortcut at install time, so it needs its own copy. */
|
|
734
|
+
declare const CLOUD_SHORTCUT_NAME_WEB = "Apple LLM Cloud Web";
|
|
735
|
+
/** Context window, measured empirically: 14.4k succeeds, ~33.5k is refused. */
|
|
736
|
+
declare const CLOUD_CONTEXT_TOKENS = 32768;
|
|
737
|
+
interface CloudProbe {
|
|
738
|
+
available: boolean;
|
|
739
|
+
reason?: string;
|
|
740
|
+
installed?: boolean;
|
|
741
|
+
contextSize?: number;
|
|
742
|
+
/**
|
|
743
|
+
* Real quota state, read from `PrivateCloudComputeLanguageModel.quotaUsage`
|
|
744
|
+
* by the on-device helper. Absent when the helper could not run (macOS 26, or
|
|
745
|
+
* no on-device model), since that is the only thing that can read it.
|
|
746
|
+
*/
|
|
747
|
+
quota?: CloudQuota;
|
|
748
|
+
/**
|
|
749
|
+
* What the server model can do, from the framework (macOS 27+). On Golden
|
|
750
|
+
* Gate: reasoning, vision, tool calling and guided generation. Tools and
|
|
751
|
+
* guided generation are not reachable through Shortcuts; vision is.
|
|
752
|
+
*/
|
|
753
|
+
capabilities?: ModelCapabilities;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* The shortcut definition, as plain JSON.
|
|
757
|
+
*
|
|
758
|
+
* Every key here was confirmed against a shortcut built in the Shortcuts GUI and
|
|
759
|
+
* exported, rather than guessed — the difference matters because a wrong
|
|
760
|
+
* parameter name does not fail loudly. Shortcuts imports the action, silently
|
|
761
|
+
* discards the unrecognised parameter, and the action then blocks on its
|
|
762
|
+
* interactive prompt at run time, forever. This is the single most expensive
|
|
763
|
+
* mistake available on this path.
|
|
764
|
+
*
|
|
765
|
+
* In particular the prompt key is `WFLLMPrompt`, *not* the `WFInput` that the
|
|
766
|
+
* action's own localised strings suggest.
|
|
767
|
+
*
|
|
768
|
+
* The model key is deliberately absent: with no model key the action uses its
|
|
769
|
+
* default, which is the Cloud (Private Cloud Compute) tier.
|
|
770
|
+
*/
|
|
771
|
+
declare function shortcutDefinition(webSearch?: boolean): Record<string, unknown>;
|
|
772
|
+
declare function cloudSetupHint(): string;
|
|
773
|
+
/**
|
|
774
|
+
* Generate, sign and install the shortcut. Idempotent unless `force` is set.
|
|
775
|
+
*
|
|
776
|
+
* Signing needs no developer account and no signing identity: `shortcuts sign -m
|
|
777
|
+
* anyone` issues a per-signature certificate that chains to Apple Root CA - G3
|
|
778
|
+
* on the device. Every user signs their own copy, so nothing has to be
|
|
779
|
+
* pre-signed, hosted, or shipped in the package.
|
|
780
|
+
*/
|
|
781
|
+
declare function installCloudShortcut(onProgress?: OnProgress, options?: {
|
|
782
|
+
force?: boolean;
|
|
783
|
+
webSearch?: boolean;
|
|
784
|
+
}): Promise<void>;
|
|
785
|
+
/** Probe the cloud tier without constructing a client. */
|
|
786
|
+
declare function probeCloud(): Promise<CloudProbe>;
|
|
787
|
+
interface CloudRequest {
|
|
788
|
+
system?: string;
|
|
789
|
+
prompt: string;
|
|
790
|
+
/** Run with "Use Broad World Knowledge" — needs the web shortcut installed. */
|
|
791
|
+
webSearch?: boolean;
|
|
792
|
+
/** Kills the `shortcuts run` process. The quota spent so far is not refunded. */
|
|
793
|
+
signal?: AbortSignal;
|
|
794
|
+
/**
|
|
795
|
+
* Images for the server model to look at, passed to the shortcut as extra
|
|
796
|
+
* inputs. Needs a server model that reports vision (macOS 27 Golden Gate).
|
|
797
|
+
*/
|
|
798
|
+
images?: ImageAttachment[];
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* The Private Cloud Compute tier. Free but quota'd, and text-out only: there is
|
|
802
|
+
* no constrained decoding here, so `json()` asks for JSON in the prompt and
|
|
803
|
+
* recovers it from prose rather than guaranteeing it.
|
|
804
|
+
*/
|
|
805
|
+
declare class CloudClient {
|
|
806
|
+
private ready;
|
|
807
|
+
/** Last known quota, set by `probe()` so a call can fail fast. */
|
|
808
|
+
private quota?;
|
|
809
|
+
/** What the framework says the server model can do, when it could be read. */
|
|
810
|
+
private model?;
|
|
811
|
+
/**
|
|
812
|
+
* Tell the client what the framework reported about the quota.
|
|
813
|
+
*
|
|
814
|
+
* Worth doing because a `shortcuts run` against an exhausted quota costs a
|
|
815
|
+
* full round trip to find out; this turns that into an immediate typed error.
|
|
816
|
+
*/
|
|
817
|
+
setQuota(quota: CloudModelInfo | undefined): void;
|
|
818
|
+
/** Whether the server model is known to read images. False when it could not be read (macOS 26). */
|
|
819
|
+
get supportsImages(): boolean;
|
|
820
|
+
private assertQuota;
|
|
821
|
+
get label(): string;
|
|
822
|
+
get contextSize(): number;
|
|
823
|
+
ensureReady(onProgress?: OnProgress): Promise<void>;
|
|
824
|
+
text(request: CloudRequest): Promise<string>;
|
|
825
|
+
/**
|
|
826
|
+
* There is no constrained decoding on this tier, so the schema is spelled out
|
|
827
|
+
* in the prompt and the reply is mined for JSON. The shape is a request here,
|
|
828
|
+
* not a guarantee — unlike on device.
|
|
829
|
+
*/
|
|
830
|
+
json(request: CloudRequest & {
|
|
831
|
+
schema: JsonSchema;
|
|
832
|
+
}): Promise<unknown>;
|
|
833
|
+
close(): void;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Streams that are both `for await`-able and awaitable.
|
|
838
|
+
*
|
|
839
|
+
* for await (const delta of llm.stream(prompt)) process.stdout.write(delta);
|
|
840
|
+
* const text = await llm.stream(prompt); // the whole reply
|
|
841
|
+
* const { usage } = await llm.stream(prompt).result;
|
|
842
|
+
*
|
|
843
|
+
* The request starts immediately, whichever way it is consumed. Breaking out
|
|
844
|
+
* of a `for await` loop cancels it — nothing keeps generating for a reader who
|
|
845
|
+
* has gone. An error surfaces through whichever of the two you use; a stream
|
|
846
|
+
* nobody consumes never raises an unhandled rejection.
|
|
847
|
+
*/
|
|
848
|
+
/**
|
|
849
|
+
* The shared shape: `Chunk`s arrive through the iterator, the promise
|
|
850
|
+
* resolves with `Final`, and `result` carries the full result object.
|
|
851
|
+
*/
|
|
852
|
+
declare class ResultStream<Chunk, Final, Result> implements AsyncIterable<Chunk>, PromiseLike<Final> {
|
|
853
|
+
/** Everything about the finished generation: text, usage, tool calls, finish reason. */
|
|
854
|
+
readonly result: Promise<Result>;
|
|
855
|
+
private readonly channel;
|
|
856
|
+
private readonly controller;
|
|
857
|
+
private readonly final;
|
|
858
|
+
private iterated;
|
|
859
|
+
private finished;
|
|
860
|
+
constructor(run: (emit: (chunk: Chunk) => void, signal: AbortSignal) => Promise<Result>, pick: (result: Result) => Final);
|
|
861
|
+
/** Stop generating. The promise and the iterator both reject with an AbortError. */
|
|
862
|
+
abort(reason?: unknown): void;
|
|
863
|
+
then<A = Final, B = never>(onfulfilled?: ((value: Final) => A | PromiseLike<A>) | null, onrejected?: ((reason: unknown) => B | PromiseLike<B>) | null): Promise<A | B>;
|
|
864
|
+
catch<B = never>(onrejected?: ((reason: unknown) => B | PromiseLike<B>) | null): Promise<Final | B>;
|
|
865
|
+
finally(onfinally?: (() => void) | null): Promise<Final>;
|
|
866
|
+
[Symbol.asyncIterator](): AsyncIterator<Chunk>;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* The public client: one API over both tiers.
|
|
871
|
+
*
|
|
872
|
+
* Every generation method takes either a prompt string or a message list, and
|
|
873
|
+
* funnels into one private `execute`, so a feature added there reaches `text`,
|
|
874
|
+
* `json`, `generate` and both streams at once.
|
|
875
|
+
*/
|
|
876
|
+
|
|
877
|
+
type Tier = 'device' | 'cloud' | 'auto';
|
|
878
|
+
interface ProbeResult {
|
|
879
|
+
device: DeviceProbe;
|
|
880
|
+
cloud: CloudProbe;
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* What this machine can actually do. Never throws: on Linux, an Intel Mac or
|
|
884
|
+
* macOS 25 it returns `available: false` with a reason naming the fix.
|
|
885
|
+
*/
|
|
886
|
+
declare function probe(onProgress?: OnProgress): Promise<ProbeResult>;
|
|
887
|
+
interface AppleLLMOptions {
|
|
888
|
+
tier?: Tier;
|
|
889
|
+
/** Default instructions for every call; a per-call `system` replaces it. */
|
|
890
|
+
system?: string;
|
|
891
|
+
/** Default sampling temperature. See DEFAULT_TEMPERATURE — do not set 0. */
|
|
892
|
+
temperature?: number;
|
|
893
|
+
maxTokens?: number;
|
|
894
|
+
/** Default per-call deadline in milliseconds. Aborts the call with a TimeoutError. */
|
|
895
|
+
timeoutMs?: number;
|
|
896
|
+
/** Called for the one-time compile and the shortcut install; both take seconds. */
|
|
897
|
+
onProgress?: OnProgress;
|
|
898
|
+
/** `contentTagging` selects Apple's tagging-specialised model. Device tier only. */
|
|
899
|
+
useCase?: UseCase;
|
|
900
|
+
/** `permissive` relaxes guardrails for rewriting tasks. Device tier only. */
|
|
901
|
+
guardrails?: Guardrails;
|
|
902
|
+
/** Default sampling mode; a seeded one makes output reproducible. */
|
|
903
|
+
sampling?: SamplingMode;
|
|
904
|
+
}
|
|
905
|
+
/** A prompt, or a whole conversation in OpenAI-style messages. */
|
|
906
|
+
type Input = string | ReadonlyArray<ChatMessage>;
|
|
907
|
+
interface TextOptions {
|
|
908
|
+
system?: string;
|
|
909
|
+
temperature?: number;
|
|
910
|
+
maxTokens?: number;
|
|
911
|
+
/** Cloud tier only: run with "Use Broad World Knowledge". */
|
|
912
|
+
webSearch?: boolean;
|
|
913
|
+
/** Image attachments; entries may carry a label for follow-up turns. */
|
|
914
|
+
images?: ImageAttachment[];
|
|
915
|
+
/** Text files inlined into the prompt. */
|
|
916
|
+
documents?: string[];
|
|
917
|
+
/** Named multi-turn conversation kept by the helper (device tier). */
|
|
918
|
+
sessionId?: string;
|
|
919
|
+
/**
|
|
920
|
+
* Tools the model may call: Apple's built-ins (`'ocr'`, `'barcode'`,
|
|
921
|
+
* `'spotlight'`) and your own function tools (see `tool()`), as an array or
|
|
922
|
+
* a record keyed by name. Device tier.
|
|
923
|
+
*/
|
|
924
|
+
tools?: ToolSet;
|
|
925
|
+
/** Tool calls allowed per request before the model is told to answer. Default 8. */
|
|
926
|
+
maxToolCalls?: number;
|
|
927
|
+
useCase?: UseCase;
|
|
928
|
+
guardrails?: Guardrails;
|
|
929
|
+
sampling?: SamplingMode;
|
|
930
|
+
/** Cancels the call. Rejects with an AbortError (a TimeoutError for `AbortSignal.timeout`). */
|
|
931
|
+
signal?: AbortSignal;
|
|
932
|
+
/** Deadline for this call in milliseconds. */
|
|
933
|
+
timeoutMs?: number;
|
|
934
|
+
/**
|
|
935
|
+
* For message-list input: drop the oldest turns when the conversation no
|
|
936
|
+
* longer fits the context window, instead of failing. Default true; the
|
|
937
|
+
* result's `trimmedTurns` says how many went.
|
|
938
|
+
*/
|
|
939
|
+
trimHistory?: boolean;
|
|
940
|
+
}
|
|
941
|
+
interface StreamOptions extends TextOptions {
|
|
942
|
+
/** Called with each delta; the returned stream can be iterated as well. */
|
|
943
|
+
onDelta?: (delta: string) => void;
|
|
944
|
+
}
|
|
945
|
+
interface JsonOptions<S extends SchemaLike = SchemaLike> extends TextOptions {
|
|
946
|
+
/** JSON Schema, or a Standard Schema (Zod 4, ArkType, Valibot via toStandardJsonSchema). */
|
|
947
|
+
schema: S;
|
|
948
|
+
}
|
|
949
|
+
interface GenerateResult<T = undefined> {
|
|
950
|
+
/** The reply text; for a schema, the JSON as the model wrote it. */
|
|
951
|
+
text: string;
|
|
952
|
+
/** The parsed and validated reply; `undefined` without a schema. */
|
|
953
|
+
object: T;
|
|
954
|
+
finishReason: FinishReason;
|
|
955
|
+
/** Token accounting — device tier on macOS 27+. */
|
|
956
|
+
usage?: Usage;
|
|
957
|
+
/** Every tool call made along the way, with what each returned. */
|
|
958
|
+
toolCalls: ToolCallRecord[];
|
|
959
|
+
/** Oldest conversation turns dropped to fit the context window. 0 almost always. */
|
|
960
|
+
trimmedTurns: number;
|
|
961
|
+
tier: 'device' | 'cloud';
|
|
962
|
+
durationMs: number;
|
|
963
|
+
/** The assistant turn, ready to append to a message list for the next call. */
|
|
964
|
+
message: Extract<ChatMessage, {
|
|
965
|
+
role: 'assistant';
|
|
966
|
+
}>;
|
|
967
|
+
}
|
|
968
|
+
/** Recursively optional — the shape of an object that is still being generated. */
|
|
969
|
+
type DeepPartial<T> = T extends ReadonlyArray<infer U> ? Array<DeepPartial<U>> : T extends object ? {
|
|
970
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
971
|
+
} : T;
|
|
972
|
+
/** `for await` the deltas, or `await` the whole text. `.result` has usage and the rest. */
|
|
973
|
+
type TextStream = ResultStream<string, string, GenerateResult<undefined>>;
|
|
974
|
+
/** `for await` partial objects as they fill in, or `await` the final validated object. */
|
|
975
|
+
type ObjectStream<T> = ResultStream<DeepPartial<T>, T, GenerateResult<T>>;
|
|
976
|
+
/**
|
|
977
|
+
* The main entry point.
|
|
978
|
+
*
|
|
979
|
+
* const llm = new AppleLLM();
|
|
980
|
+
* await llm.text('Summarize this');
|
|
981
|
+
* await llm.json('Extract the fields', { schema });
|
|
982
|
+
* for await (const d of llm.stream('Tell me a story')) process.stdout.write(d);
|
|
983
|
+
*
|
|
984
|
+
* One instance keeps one helper process warm. It is unref'd between calls, so
|
|
985
|
+
* a script exits on its own; `close()` (or `await using`) releases it early.
|
|
986
|
+
*/
|
|
987
|
+
declare class AppleLLM {
|
|
988
|
+
private device?;
|
|
989
|
+
private cloud?;
|
|
990
|
+
/** Which tier `auto` settled on, once resolved. */
|
|
991
|
+
private resolved?;
|
|
992
|
+
private readying?;
|
|
993
|
+
private readonly options;
|
|
994
|
+
constructor(options?: AppleLLMOptions);
|
|
995
|
+
get tier(): Tier;
|
|
996
|
+
/** Human-readable name of the tier in use, for logs. */
|
|
997
|
+
get label(): string;
|
|
998
|
+
/** Context window of the resolved tier, in tokens. */
|
|
999
|
+
get contextSize(): number | undefined;
|
|
1000
|
+
/**
|
|
1001
|
+
* Resolve the tier and do any one-time setup. Called automatically, but
|
|
1002
|
+
* exposed so a caller can pay the compile cost up front with a progress bar.
|
|
1003
|
+
* Concurrent first calls share one attempt.
|
|
1004
|
+
*/
|
|
1005
|
+
ensureReady(onProgress?: OnProgress): Promise<void>;
|
|
1006
|
+
private newDevice;
|
|
1007
|
+
private readyCloud;
|
|
1008
|
+
private resolve;
|
|
1009
|
+
/** Free text. */
|
|
1010
|
+
text(input: Input, options?: TextOptions): Promise<string>;
|
|
1011
|
+
/**
|
|
1012
|
+
* Everything about one generation: text, parsed object (with a schema),
|
|
1013
|
+
* usage, tool calls, finish reason, and the assistant `message` to append.
|
|
1014
|
+
*/
|
|
1015
|
+
generate<S extends SchemaLike>(input: Input, options: TextOptions & {
|
|
1016
|
+
schema: S;
|
|
1017
|
+
}): Promise<GenerateResult<InferSchema<S>>>;
|
|
1018
|
+
generate(input: Input, options?: TextOptions & {
|
|
1019
|
+
schema?: undefined;
|
|
1020
|
+
}): Promise<GenerateResult<undefined>>;
|
|
1021
|
+
/**
|
|
1022
|
+
* Ask for JSON. On device the *shape* is guaranteed by constrained decoding;
|
|
1023
|
+
* a Standard Schema's own validation (refinements, transforms) then runs on
|
|
1024
|
+
* top, and the result is typed by it. On cloud the shape is requested in the
|
|
1025
|
+
* prompt and recovered from the reply. Either way, a reply that fails
|
|
1026
|
+
* validation is retried once with the problems pointed out, then raised as a
|
|
1027
|
+
* SchemaValidationError.
|
|
1028
|
+
*/
|
|
1029
|
+
json<S extends SchemaLike>(input: Input, options: JsonOptions<S>): Promise<InferSchema<S>>;
|
|
1030
|
+
/**
|
|
1031
|
+
* Streaming text. Iterate it for deltas, or await it for the whole reply:
|
|
1032
|
+
*
|
|
1033
|
+
* for await (const delta of llm.stream(prompt)) process.stdout.write(delta);
|
|
1034
|
+
* const text = await llm.stream(prompt, { onDelta });
|
|
1035
|
+
*
|
|
1036
|
+
* On the cloud tier the reply arrives as one chunk: Shortcuts is not
|
|
1037
|
+
* incremental.
|
|
1038
|
+
*/
|
|
1039
|
+
stream(input: Input, options?: StreamOptions): TextStream;
|
|
1040
|
+
/**
|
|
1041
|
+
* Streaming JSON: partial objects as the model fills them in — render a form
|
|
1042
|
+
* or a card while it is still being written — and the final object, parsed
|
|
1043
|
+
* and validated, as the awaited value.
|
|
1044
|
+
*
|
|
1045
|
+
* for await (const partial of llm.streamJson(prompt, { schema })) render(partial);
|
|
1046
|
+
*/
|
|
1047
|
+
streamJson<S extends SchemaLike>(input: Input, options: JsonOptions<S>): ObjectStream<InferSchema<S>>;
|
|
1048
|
+
/** The one path every generation takes. */
|
|
1049
|
+
private execute;
|
|
1050
|
+
/** Parse, restore nulls, validate. Throws SchemaValidationError for anything the schema rejects. */
|
|
1051
|
+
private parseObject;
|
|
1052
|
+
private assertCloudCompatible;
|
|
1053
|
+
/** Conversation history for a named session (device tier only). */
|
|
1054
|
+
history(sessionId: string): Promise<{
|
|
1055
|
+
instructions: string;
|
|
1056
|
+
history: HistoryTurn[];
|
|
1057
|
+
}>;
|
|
1058
|
+
/** Drop a named session, or all sessions when omitted (device tier only). */
|
|
1059
|
+
resetSession(sessionId?: string): Promise<void>;
|
|
1060
|
+
/**
|
|
1061
|
+
* A named conversation: calls sharing one native transcript, like one thread
|
|
1062
|
+
* in the Siri app. History persists across helper restarts, and the
|
|
1063
|
+
* transcript is rebuilt from it — trimmed to fit when it outgrows the window.
|
|
1064
|
+
*/
|
|
1065
|
+
conversation(sessionId: string, options?: {
|
|
1066
|
+
system?: string;
|
|
1067
|
+
}): Conversation;
|
|
1068
|
+
/**
|
|
1069
|
+
* Write with Siri, anywhere you type: drafting, rewriting and feedback
|
|
1070
|
+
* built on the permissive-content-transformation guardrails. Device tier
|
|
1071
|
+
* only — these are transformation tasks the default guardrails refuse.
|
|
1072
|
+
*/
|
|
1073
|
+
rewrite(text: string, options?: {
|
|
1074
|
+
instruction?: string;
|
|
1075
|
+
} & TextOptions): Promise<string>;
|
|
1076
|
+
proofread(text: string, options?: TextOptions): Promise<string>;
|
|
1077
|
+
/**
|
|
1078
|
+
* Summarise text of any length. Text that does not fit the context window
|
|
1079
|
+
* is summarised in parts, then the parts are summarised together — so a
|
|
1080
|
+
* long report works on an 8k-token model instead of failing.
|
|
1081
|
+
*/
|
|
1082
|
+
summarize(text: string, options?: {
|
|
1083
|
+
length?: string;
|
|
1084
|
+
} & TextOptions): Promise<string>;
|
|
1085
|
+
/** Split text into pieces that each fit one call, on paragraph boundaries where possible. */
|
|
1086
|
+
private chunksFor;
|
|
1087
|
+
draft(topic: string, options?: {
|
|
1088
|
+
kind?: string;
|
|
1089
|
+
} & TextOptions): Promise<string>;
|
|
1090
|
+
tone(text: string, tone: string, options?: TextOptions): Promise<string>;
|
|
1091
|
+
/**
|
|
1092
|
+
* Ask about what's on screen: captures a screenshot (interactive selection
|
|
1093
|
+
* by default, like Cmd+Shift+Space Visual Intelligence) and asks the model
|
|
1094
|
+
* about it with vision. Device tier, macOS 27+.
|
|
1095
|
+
*/
|
|
1096
|
+
askScreen(question: string, options?: {
|
|
1097
|
+
mode?: 'interactive' | 'window' | 'fullscreen';
|
|
1098
|
+
} & TextOptions): Promise<string>;
|
|
1099
|
+
/**
|
|
1100
|
+
* `json()` in the `(system, user, schema)` shape many LLM clients use, for
|
|
1101
|
+
* dropping this in behind an existing interface.
|
|
1102
|
+
*/
|
|
1103
|
+
completeJson(system: string, user: string, schema: JsonSchema): Promise<unknown>;
|
|
1104
|
+
/**
|
|
1105
|
+
* How many tokens a request costs, before sending it. Device tier only.
|
|
1106
|
+
*
|
|
1107
|
+
* Turns a ContextLengthError into arithmetic: compare against `contextSize`
|
|
1108
|
+
* and trim, rather than finding the ceiling by hitting it. Counts
|
|
1109
|
+
* everything that shares the window — instructions, message history, tools,
|
|
1110
|
+
* schema, images and documents.
|
|
1111
|
+
*/
|
|
1112
|
+
countTokens(input: Input, options?: Pick<TextOptions, 'system' | 'images' | 'tools' | 'documents' | 'signal'> & {
|
|
1113
|
+
schema?: SchemaLike;
|
|
1114
|
+
}): Promise<{
|
|
1115
|
+
tokens: number;
|
|
1116
|
+
contextSize: number;
|
|
1117
|
+
}>;
|
|
1118
|
+
/**
|
|
1119
|
+
* Load the model assets now so the first real call does not pay for it.
|
|
1120
|
+
* Device tier only; a no-op elsewhere. See `DeviceClient.prewarm` for what it
|
|
1121
|
+
* is actually worth (little, on a warm machine).
|
|
1122
|
+
*/
|
|
1123
|
+
prewarm(system?: string): Promise<void>;
|
|
1124
|
+
/** Release the long-lived helper process. Safe to call more than once. */
|
|
1125
|
+
close(): void;
|
|
1126
|
+
/** `using llm = new AppleLLM()` closes it at the end of the block. */
|
|
1127
|
+
[Symbol.dispose](): void;
|
|
1128
|
+
/** `await using llm = new AppleLLM()` closes it at the end of the block. */
|
|
1129
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* One thread in the Siri-app sense: every call carries the same sessionId,
|
|
1133
|
+
* so the helper's native transcript accumulates across turns.
|
|
1134
|
+
*/
|
|
1135
|
+
declare class Conversation {
|
|
1136
|
+
private readonly llm;
|
|
1137
|
+
readonly sessionId: string;
|
|
1138
|
+
private readonly defaults;
|
|
1139
|
+
constructor(llm: AppleLLM, sessionId: string, defaults?: {
|
|
1140
|
+
system?: string;
|
|
1141
|
+
});
|
|
1142
|
+
private with;
|
|
1143
|
+
text(prompt: string, options?: TextOptions): Promise<string>;
|
|
1144
|
+
stream(prompt: string, options?: StreamOptions): TextStream;
|
|
1145
|
+
generate(prompt: string, options?: TextOptions): Promise<GenerateResult<undefined>>;
|
|
1146
|
+
json<S extends SchemaLike>(prompt: string, options: JsonOptions<S>): Promise<InferSchema<S>>;
|
|
1147
|
+
history(): Promise<{
|
|
1148
|
+
instructions: string;
|
|
1149
|
+
history: HistoryTurn[];
|
|
1150
|
+
}>;
|
|
1151
|
+
reset(): Promise<void>;
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Capture a screenshot to a temp file. Interactive selection mirrors the
|
|
1155
|
+
* Visual Intelligence entry point (Cmd+Shift+Space): drag to select, and the
|
|
1156
|
+
* path comes back ready to pass as an image attachment.
|
|
1157
|
+
*/
|
|
1158
|
+
declare function captureScreenshot(mode?: 'interactive' | 'window' | 'fullscreen'): Promise<string>;
|
|
1159
|
+
|
|
1160
|
+
export { type ToolExecutionContext as $, type AppleLLMOptions as A, type BuiltInTool as B, CLOUD_CONTEXT_TOKENS as C, DEFAULT_MAX_TOKENS as D, type OnProgress as E, type FinishReason as F, type Guardrails as G, type HelperFeatures as H, type ImageAttachment as I, type JsonOptions as J, type Progress as K, ResultStream as L, type ModelCapabilities as M, type RunHooks as N, type ObjectStream as O, type ProbeResult as P, type SchemaLike as Q, ReplayBook as R, type SamplingMode as S, type StandardJSONSchemaV1 as T, type UseCase as U, StandardSchemaV1 as V, type StreamOptions as W, type TextOptions as X, type TextStream as Y, type Tier as Z, type ToolCallRecord as _, AppleLLM as a, type ToolSet as a0, type Usage as a1, assertTools as a2, cacheDir as a3, captureScreenshot as a4, cloudSetupHint as a5, ensureBinary as a6, fingerprint as a7, helperSource as a8, installCloudShortcut as a9, isStandardSchema as aa, normalizeTools as ab, parseImageFlag as ac, probe as ad, probeCloud as ae, probeDevice as af, resolveSchema as ag, restoreNulls as ah, shortcutDefinition as ai, splitMessages as aj, toAppleSchema as ak, tool as al, toolOutputText as am, withDocuments as an, CLOUD_SHORTCUT_NAME as b, CLOUD_SHORTCUT_NAME_WEB as c, type ChatMessage as d, type ChatToolCall as e, CloudClient as f, type CloudModelInfo as g, type CloudProbe as h, type CloudQuota as i, type CloudRequest as j, Conversation as k, DEFAULT_MAX_TOOL_CALLS as l, DEFAULT_TEMPERATURE as m, type DeepPartial as n, DeviceClient as o, type DeviceClientOptions as p, type DeviceOutcome as q, type DeviceProbe as r, type DeviceRequest as s, type FunctionTool as t, type GenerateResult as u, type HistoryEntry as v, type HistoryTurn as w, type InferSchema as x, type Input as y, type JsonSchema as z };
|