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.
@@ -0,0 +1,281 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
2
+
3
+ var _chunkOQATUZWFcjs = require('./chunk-OQATUZWF.cjs');
4
+
5
+
6
+
7
+
8
+ var _chunkNRDZIP5Gcjs = require('./chunk-NRDZIP5G.cjs');
9
+
10
+ // src/ai-sdk.ts
11
+ var PROVIDER = "apple";
12
+ function usageV3(usage) {
13
+ return {
14
+ inputTokens: {
15
+ total: _optionalChain([usage, 'optionalAccess', _ => _.inputTokens]),
16
+ noCache: usage === void 0 ? void 0 : usage.inputTokens - (_nullishCoalesce(usage.cachedInputTokens, () => ( 0))),
17
+ cacheRead: _optionalChain([usage, 'optionalAccess', _2 => _2.cachedInputTokens]),
18
+ cacheWrite: void 0
19
+ },
20
+ outputTokens: { total: _optionalChain([usage, 'optionalAccess', _3 => _3.outputTokens]), text: _optionalChain([usage, 'optionalAccess', _4 => _4.outputTokens]), reasoning: void 0 }
21
+ };
22
+ }
23
+ function finishV3(reason) {
24
+ return { unified: reason, raw: reason };
25
+ }
26
+ function toolOutputText(output) {
27
+ switch (output.type) {
28
+ case "text":
29
+ case "error-text":
30
+ return output.value;
31
+ case "json":
32
+ case "error-json":
33
+ return JSON.stringify(output.value);
34
+ case "execution-denied":
35
+ return `The tool call was not executed${output.reason ? `: ${output.reason}` : "."}`;
36
+ case "content":
37
+ return output.value.map((part) => part.type === "text" ? part.text : `[${part.type}]`).join("\n");
38
+ default:
39
+ return "";
40
+ }
41
+ }
42
+ async function toMessages(prompt, images, warnings, signal) {
43
+ const out = [];
44
+ for (const message of prompt) {
45
+ switch (message.role) {
46
+ case "system":
47
+ out.push({ role: "system", content: message.content });
48
+ break;
49
+ case "user": {
50
+ const texts = [];
51
+ const paths = [];
52
+ for (const part of message.content) {
53
+ if (part.type === "text") {
54
+ texts.push(part.text);
55
+ } else if (part.mediaType.startsWith("image/")) {
56
+ paths.push(await images.add(part.data, part.mediaType, signal));
57
+ } else if (part.mediaType.startsWith("text/") || part.mediaType === "application/json") {
58
+ const body = typeof part.data === "string" ? Buffer.from(part.data, "base64").toString("utf8") : part.data instanceof URL ? await (await fetch(part.data, { signal })).text() : Buffer.from(part.data).toString("utf8");
59
+ texts.push(`--- Document: ${_nullishCoalesce(part.filename, () => ( "attachment"))} ---
60
+ ${body}`);
61
+ } else {
62
+ warnings.push({ type: "unsupported", feature: `file part of type ${part.mediaType}` });
63
+ }
64
+ }
65
+ out.push({ role: "user", content: texts.join("\n\n"), ...paths.length > 0 ? { images: paths } : {} });
66
+ break;
67
+ }
68
+ case "assistant": {
69
+ const texts = [];
70
+ const calls = [];
71
+ const results = [];
72
+ for (const part of message.content) {
73
+ if (part.type === "text") texts.push(part.text);
74
+ else if (part.type === "tool-call") calls.push({ id: part.toolCallId, name: part.toolName, arguments: part.input });
75
+ else if (part.type === "tool-result") {
76
+ results.push({ role: "tool", toolCallId: part.toolCallId, name: part.toolName, content: toolOutputText(part.output) });
77
+ }
78
+ }
79
+ out.push({ role: "assistant", content: texts.join(""), ...calls.length > 0 ? { toolCalls: calls } : {} });
80
+ out.push(...results);
81
+ break;
82
+ }
83
+ case "tool":
84
+ for (const part of message.content) {
85
+ if (part.type !== "tool-result") continue;
86
+ out.push({ role: "tool", toolCallId: part.toolCallId, name: part.toolName, content: toolOutputText(part.output) });
87
+ }
88
+ break;
89
+ default:
90
+ break;
91
+ }
92
+ }
93
+ return out;
94
+ }
95
+ var AppleLanguageModel = (_class = class {
96
+ constructor(modelId, client) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);
97
+ this.modelId = modelId;
98
+ this.client = client;
99
+ }
100
+
101
+
102
+ __init() {this.specificationVersion = "v3"}
103
+ __init2() {this.provider = PROVIDER}
104
+ __init3() {this.supportedUrls = {}}
105
+ /** Map call options onto a request; collect warnings for what does not map. */
106
+ async prepare(options) {
107
+ const warnings = [];
108
+ const images = new (0, _chunkOQATUZWFcjs.TempImages)();
109
+ const messages = await toMessages(options.prompt, images, warnings, options.abortSignal);
110
+ const apple2 = _nullishCoalesce(_optionalChain([options, 'access', _5 => _5.providerOptions, 'optionalAccess', _6 => _6.apple]), () => ( {}));
111
+ for (const [feature, value] of [
112
+ ["stopSequences", options.stopSequences],
113
+ ["presencePenalty", options.presencePenalty],
114
+ ["frequencyPenalty", options.frequencyPenalty]
115
+ ]) {
116
+ if (value !== void 0 && !(Array.isArray(value) && value.length === 0)) {
117
+ warnings.push({ type: "unsupported", feature });
118
+ }
119
+ }
120
+ let sampling;
121
+ if (options.topK !== void 0) sampling = { mode: "topK", k: options.topK, seed: options.seed };
122
+ else if (options.topP !== void 0) sampling = { mode: "threshold", p: options.topP, seed: options.seed };
123
+ else if (options.seed !== void 0) sampling = { mode: "topK", k: 50, seed: options.seed };
124
+ const functions = [];
125
+ if (_optionalChain([options, 'access', _7 => _7.toolChoice, 'optionalAccess', _8 => _8.type]) !== "none") {
126
+ for (const def of _nullishCoalesce(options.tools, () => ( []))) {
127
+ if (def.type !== "function") {
128
+ warnings.push({ type: "unsupported", feature: `provider tool ${def.name}` });
129
+ continue;
130
+ }
131
+ functions.push(_chunkNRDZIP5Gcjs.tool.call(void 0, { name: def.name, description: def.description, parameters: def.inputSchema }));
132
+ }
133
+ }
134
+ if (_optionalChain([options, 'access', _9 => _9.toolChoice, 'optionalAccess', _10 => _10.type]) === "required" || _optionalChain([options, 'access', _11 => _11.toolChoice, 'optionalAccess', _12 => _12.type]) === "tool") {
135
+ warnings.push({
136
+ type: "unsupported",
137
+ feature: `toolChoice "${options.toolChoice.type}"`,
138
+ details: "Apple\u2019s model decides for itself whether to call a tool."
139
+ });
140
+ }
141
+ let schema;
142
+ if (_optionalChain([options, 'access', _13 => _13.responseFormat, 'optionalAccess', _14 => _14.type]) === "json") {
143
+ if (options.responseFormat.schema !== void 0) {
144
+ schema = options.responseFormat.schema;
145
+ } else {
146
+ messages.unshift({ role: "system", content: "Reply with a single JSON value and nothing else." });
147
+ warnings.push({ type: "compatibility", feature: "responseFormat json without a schema", details: "requested in the prompt, not enforced" });
148
+ }
149
+ }
150
+ const tools = [..._nullishCoalesce(apple2.builtInTools, () => ( [])), ...functions];
151
+ return {
152
+ messages,
153
+ schema,
154
+ warnings,
155
+ images,
156
+ call: {
157
+ temperature: options.temperature,
158
+ maxTokens: options.maxOutputTokens,
159
+ sampling,
160
+ signal: options.abortSignal,
161
+ tools: tools.length > 0 ? tools : void 0,
162
+ useCase: apple2.useCase,
163
+ guardrails: apple2.guardrails,
164
+ trimHistory: apple2.trimHistory,
165
+ webSearch: apple2.webSearch
166
+ }
167
+ };
168
+ }
169
+ /** Content parts: the text, then any tool call the SDK has to run. */
170
+ content(result) {
171
+ const content = [];
172
+ if (result.text !== "" && result.finishReason !== "tool-calls") content.push({ type: "text", text: result.text });
173
+ for (const call of result.toolCalls) {
174
+ if (call.output !== void 0) continue;
175
+ content.push({ type: "tool-call", toolCallId: call.id, toolName: call.name, input: JSON.stringify(_nullishCoalesce(call.arguments, () => ( {}))) });
176
+ }
177
+ return content;
178
+ }
179
+ async doGenerate(options) {
180
+ const { messages, call, schema, warnings, images } = await this.prepare(options);
181
+ try {
182
+ const result = schema === void 0 ? await this.client.generate(messages, call) : await this.client.generate(messages, { ...call, schema });
183
+ return {
184
+ content: this.content(result),
185
+ finishReason: finishV3(result.finishReason),
186
+ usage: usageV3(result.usage),
187
+ warnings,
188
+ response: { id: `apple-${Date.now().toString(36)}`, timestamp: /* @__PURE__ */ new Date(), modelId: this.modelId },
189
+ providerMetadata: {
190
+ apple: { tier: result.tier, durationMs: result.durationMs, trimmedTurns: result.trimmedTurns }
191
+ }
192
+ };
193
+ } finally {
194
+ await images.dispose();
195
+ }
196
+ }
197
+ async doStream(options) {
198
+ const { messages, call, schema, warnings, images } = await this.prepare(options);
199
+ const client = this.client;
200
+ const modelId = this.modelId;
201
+ const content = (result) => this.content(result);
202
+ const stream = new ReadableStream({
203
+ async start(controller) {
204
+ controller.enqueue({ type: "stream-start", warnings });
205
+ controller.enqueue({ type: "response-metadata", id: `apple-${Date.now().toString(36)}`, timestamp: /* @__PURE__ */ new Date(), modelId });
206
+ const textId = "text-0";
207
+ let textOpen = false;
208
+ const openText = () => {
209
+ if (!textOpen) controller.enqueue({ type: "text-start", id: textId });
210
+ textOpen = true;
211
+ };
212
+ try {
213
+ let result;
214
+ if (schema === void 0) {
215
+ const textStream = client.stream(messages, call);
216
+ for await (const delta of textStream) {
217
+ openText();
218
+ controller.enqueue({ type: "text-delta", id: textId, delta });
219
+ }
220
+ result = await textStream.result;
221
+ } else {
222
+ result = await client.generate(messages, { ...call, schema });
223
+ if (result.finishReason !== "tool-calls") {
224
+ openText();
225
+ controller.enqueue({ type: "text-delta", id: textId, delta: result.text });
226
+ }
227
+ }
228
+ if (textOpen) controller.enqueue({ type: "text-end", id: textId });
229
+ for (const part of content(result)) {
230
+ if (part.type === "tool-call") controller.enqueue(part);
231
+ }
232
+ controller.enqueue({
233
+ type: "finish",
234
+ finishReason: finishV3(result.finishReason),
235
+ usage: usageV3(result.usage),
236
+ providerMetadata: { apple: { tier: result.tier, durationMs: result.durationMs, trimmedTurns: result.trimmedTurns } }
237
+ });
238
+ } catch (error) {
239
+ controller.enqueue({ type: "error", error });
240
+ } finally {
241
+ await images.dispose();
242
+ controller.close();
243
+ }
244
+ }
245
+ });
246
+ return { stream };
247
+ }
248
+ }, _class);
249
+ function createApple(settings = {}) {
250
+ const { client: shared, ...defaults } = settings;
251
+ const clients = /* @__PURE__ */ new Map();
252
+ const clientFor = (tier) => {
253
+ if (shared !== void 0) return shared;
254
+ let client = clients.get(tier);
255
+ if (client === void 0) {
256
+ client = new (0, _chunkNRDZIP5Gcjs.AppleLLM)({ ...defaults, tier });
257
+ clients.set(tier, client);
258
+ }
259
+ return client;
260
+ };
261
+ const languageModel = (modelId = "device") => {
262
+ if (modelId !== "device" && modelId !== "cloud" && modelId !== "auto") {
263
+ throw new (0, _chunkNRDZIP5Gcjs.AppleLLMError)(`Unknown Apple model "${String(modelId)}" (want device, cloud or auto).`);
264
+ }
265
+ return new AppleLanguageModel(modelId, clientFor(modelId));
266
+ };
267
+ const unsupported = (kind) => () => {
268
+ throw new (0, _chunkNRDZIP5Gcjs.AppleLLMError)(`Apple's built-in models do not provide ${kind} models.`);
269
+ };
270
+ return Object.assign((modelId) => languageModel(modelId), {
271
+ specificationVersion: "v3",
272
+ languageModel,
273
+ embeddingModel: unsupported("embedding"),
274
+ imageModel: unsupported("image")
275
+ });
276
+ }
277
+ var apple = createApple();
278
+
279
+
280
+
281
+ exports.apple = apple; exports.createApple = createApple;
@@ -0,0 +1,54 @@
1
+ import { ProviderV3, LanguageModelV3 } from '@ai-sdk/provider';
2
+ import { U as UseCase, G as Guardrails, B as BuiltInTool, A as AppleLLMOptions, a as AppleLLM } from './client-CXewzZTj.cjs';
3
+ import 'node:child_process';
4
+
5
+ /**
6
+ * Vercel AI SDK provider (specification v3: AI SDK 6 and 7).
7
+ *
8
+ * import { generateText, streamText } from 'ai';
9
+ * import { apple } from 'apple-llm/ai-sdk';
10
+ *
11
+ * const { text } = await generateText({ model: apple(), prompt: 'Hello' });
12
+ *
13
+ * `apple()` is the on-device model; `apple('cloud')` is Private Cloud Compute,
14
+ * which sends the prompt off the machine; `apple('auto')` prefers the device.
15
+ * Tools, structured output (`Output.object`), images, streaming and abort
16
+ * signals all map onto the native features. The AI SDK runs tools itself, so
17
+ * each call stops at a tool call and the SDK sends the result back — see
18
+ * messages.ts for how that is replayed on a model that cannot resume from a
19
+ * tool output.
20
+ *
21
+ * Only types are imported from `@ai-sdk/provider`; nothing here loads at
22
+ * runtime unless you import this entry point.
23
+ */
24
+
25
+ type AppleModelId = 'device' | 'cloud' | 'auto';
26
+ /** Per-call options, under `providerOptions: { apple: { … } }`. */
27
+ interface AppleProviderOptions {
28
+ useCase?: UseCase;
29
+ guardrails?: Guardrails;
30
+ /** Apple's built-in tools, run on device alongside your own. */
31
+ builtInTools?: BuiltInTool[];
32
+ /** Drop the oldest turns when a conversation outgrows the window. Default true. */
33
+ trimHistory?: boolean;
34
+ /** Cloud tier: "Use Broad World Knowledge". */
35
+ webSearch?: boolean;
36
+ }
37
+ interface AppleProviderSettings extends Omit<AppleLLMOptions, 'tier'> {
38
+ /** Share one client (and so one warm helper) with the rest of your code. */
39
+ client?: AppleLLM;
40
+ }
41
+ interface AppleProvider extends ProviderV3 {
42
+ (modelId?: AppleModelId): LanguageModelV3;
43
+ /** `string` too, as ProviderV3 requires; anything but the three ids throws. */
44
+ languageModel(modelId?: AppleModelId | (string & {})): LanguageModelV3;
45
+ }
46
+ /**
47
+ * Create a provider. Pass settings to change defaults for every model it
48
+ * makes, or `client` to share an existing AppleLLM (and its warm helper).
49
+ */
50
+ declare function createApple(settings?: AppleProviderSettings): AppleProvider;
51
+ /** The default provider: `apple()` on device, `apple('cloud')`, `apple('auto')`. */
52
+ declare const apple: AppleProvider;
53
+
54
+ export { type AppleModelId, type AppleProvider, type AppleProviderOptions, type AppleProviderSettings, apple, createApple };
@@ -0,0 +1,54 @@
1
+ import { ProviderV3, LanguageModelV3 } from '@ai-sdk/provider';
2
+ import { U as UseCase, G as Guardrails, B as BuiltInTool, A as AppleLLMOptions, a as AppleLLM } from './client-CXewzZTj.js';
3
+ import 'node:child_process';
4
+
5
+ /**
6
+ * Vercel AI SDK provider (specification v3: AI SDK 6 and 7).
7
+ *
8
+ * import { generateText, streamText } from 'ai';
9
+ * import { apple } from 'apple-llm/ai-sdk';
10
+ *
11
+ * const { text } = await generateText({ model: apple(), prompt: 'Hello' });
12
+ *
13
+ * `apple()` is the on-device model; `apple('cloud')` is Private Cloud Compute,
14
+ * which sends the prompt off the machine; `apple('auto')` prefers the device.
15
+ * Tools, structured output (`Output.object`), images, streaming and abort
16
+ * signals all map onto the native features. The AI SDK runs tools itself, so
17
+ * each call stops at a tool call and the SDK sends the result back — see
18
+ * messages.ts for how that is replayed on a model that cannot resume from a
19
+ * tool output.
20
+ *
21
+ * Only types are imported from `@ai-sdk/provider`; nothing here loads at
22
+ * runtime unless you import this entry point.
23
+ */
24
+
25
+ type AppleModelId = 'device' | 'cloud' | 'auto';
26
+ /** Per-call options, under `providerOptions: { apple: { … } }`. */
27
+ interface AppleProviderOptions {
28
+ useCase?: UseCase;
29
+ guardrails?: Guardrails;
30
+ /** Apple's built-in tools, run on device alongside your own. */
31
+ builtInTools?: BuiltInTool[];
32
+ /** Drop the oldest turns when a conversation outgrows the window. Default true. */
33
+ trimHistory?: boolean;
34
+ /** Cloud tier: "Use Broad World Knowledge". */
35
+ webSearch?: boolean;
36
+ }
37
+ interface AppleProviderSettings extends Omit<AppleLLMOptions, 'tier'> {
38
+ /** Share one client (and so one warm helper) with the rest of your code. */
39
+ client?: AppleLLM;
40
+ }
41
+ interface AppleProvider extends ProviderV3 {
42
+ (modelId?: AppleModelId): LanguageModelV3;
43
+ /** `string` too, as ProviderV3 requires; anything but the three ids throws. */
44
+ languageModel(modelId?: AppleModelId | (string & {})): LanguageModelV3;
45
+ }
46
+ /**
47
+ * Create a provider. Pass settings to change defaults for every model it
48
+ * makes, or `client` to share an existing AppleLLM (and its warm helper).
49
+ */
50
+ declare function createApple(settings?: AppleProviderSettings): AppleProvider;
51
+ /** The default provider: `apple()` on device, `apple('cloud')`, `apple('auto')`. */
52
+ declare const apple: AppleProvider;
53
+
54
+ export { type AppleModelId, type AppleProvider, type AppleProviderOptions, type AppleProviderSettings, apple, createApple };
package/dist/ai-sdk.js ADDED
@@ -0,0 +1,281 @@
1
+ import {
2
+ TempImages
3
+ } from "./chunk-ZB4RDEPW.js";
4
+ import {
5
+ AppleLLM,
6
+ AppleLLMError,
7
+ tool
8
+ } from "./chunk-GM325EMJ.js";
9
+
10
+ // src/ai-sdk.ts
11
+ var PROVIDER = "apple";
12
+ function usageV3(usage) {
13
+ return {
14
+ inputTokens: {
15
+ total: usage?.inputTokens,
16
+ noCache: usage === void 0 ? void 0 : usage.inputTokens - (usage.cachedInputTokens ?? 0),
17
+ cacheRead: usage?.cachedInputTokens,
18
+ cacheWrite: void 0
19
+ },
20
+ outputTokens: { total: usage?.outputTokens, text: usage?.outputTokens, reasoning: void 0 }
21
+ };
22
+ }
23
+ function finishV3(reason) {
24
+ return { unified: reason, raw: reason };
25
+ }
26
+ function toolOutputText(output) {
27
+ switch (output.type) {
28
+ case "text":
29
+ case "error-text":
30
+ return output.value;
31
+ case "json":
32
+ case "error-json":
33
+ return JSON.stringify(output.value);
34
+ case "execution-denied":
35
+ return `The tool call was not executed${output.reason ? `: ${output.reason}` : "."}`;
36
+ case "content":
37
+ return output.value.map((part) => part.type === "text" ? part.text : `[${part.type}]`).join("\n");
38
+ default:
39
+ return "";
40
+ }
41
+ }
42
+ async function toMessages(prompt, images, warnings, signal) {
43
+ const out = [];
44
+ for (const message of prompt) {
45
+ switch (message.role) {
46
+ case "system":
47
+ out.push({ role: "system", content: message.content });
48
+ break;
49
+ case "user": {
50
+ const texts = [];
51
+ const paths = [];
52
+ for (const part of message.content) {
53
+ if (part.type === "text") {
54
+ texts.push(part.text);
55
+ } else if (part.mediaType.startsWith("image/")) {
56
+ paths.push(await images.add(part.data, part.mediaType, signal));
57
+ } else if (part.mediaType.startsWith("text/") || part.mediaType === "application/json") {
58
+ const body = typeof part.data === "string" ? Buffer.from(part.data, "base64").toString("utf8") : part.data instanceof URL ? await (await fetch(part.data, { signal })).text() : Buffer.from(part.data).toString("utf8");
59
+ texts.push(`--- Document: ${part.filename ?? "attachment"} ---
60
+ ${body}`);
61
+ } else {
62
+ warnings.push({ type: "unsupported", feature: `file part of type ${part.mediaType}` });
63
+ }
64
+ }
65
+ out.push({ role: "user", content: texts.join("\n\n"), ...paths.length > 0 ? { images: paths } : {} });
66
+ break;
67
+ }
68
+ case "assistant": {
69
+ const texts = [];
70
+ const calls = [];
71
+ const results = [];
72
+ for (const part of message.content) {
73
+ if (part.type === "text") texts.push(part.text);
74
+ else if (part.type === "tool-call") calls.push({ id: part.toolCallId, name: part.toolName, arguments: part.input });
75
+ else if (part.type === "tool-result") {
76
+ results.push({ role: "tool", toolCallId: part.toolCallId, name: part.toolName, content: toolOutputText(part.output) });
77
+ }
78
+ }
79
+ out.push({ role: "assistant", content: texts.join(""), ...calls.length > 0 ? { toolCalls: calls } : {} });
80
+ out.push(...results);
81
+ break;
82
+ }
83
+ case "tool":
84
+ for (const part of message.content) {
85
+ if (part.type !== "tool-result") continue;
86
+ out.push({ role: "tool", toolCallId: part.toolCallId, name: part.toolName, content: toolOutputText(part.output) });
87
+ }
88
+ break;
89
+ default:
90
+ break;
91
+ }
92
+ }
93
+ return out;
94
+ }
95
+ var AppleLanguageModel = class {
96
+ constructor(modelId, client) {
97
+ this.modelId = modelId;
98
+ this.client = client;
99
+ }
100
+ modelId;
101
+ client;
102
+ specificationVersion = "v3";
103
+ provider = PROVIDER;
104
+ supportedUrls = {};
105
+ /** Map call options onto a request; collect warnings for what does not map. */
106
+ async prepare(options) {
107
+ const warnings = [];
108
+ const images = new TempImages();
109
+ const messages = await toMessages(options.prompt, images, warnings, options.abortSignal);
110
+ const apple2 = options.providerOptions?.apple ?? {};
111
+ for (const [feature, value] of [
112
+ ["stopSequences", options.stopSequences],
113
+ ["presencePenalty", options.presencePenalty],
114
+ ["frequencyPenalty", options.frequencyPenalty]
115
+ ]) {
116
+ if (value !== void 0 && !(Array.isArray(value) && value.length === 0)) {
117
+ warnings.push({ type: "unsupported", feature });
118
+ }
119
+ }
120
+ let sampling;
121
+ if (options.topK !== void 0) sampling = { mode: "topK", k: options.topK, seed: options.seed };
122
+ else if (options.topP !== void 0) sampling = { mode: "threshold", p: options.topP, seed: options.seed };
123
+ else if (options.seed !== void 0) sampling = { mode: "topK", k: 50, seed: options.seed };
124
+ const functions = [];
125
+ if (options.toolChoice?.type !== "none") {
126
+ for (const def of options.tools ?? []) {
127
+ if (def.type !== "function") {
128
+ warnings.push({ type: "unsupported", feature: `provider tool ${def.name}` });
129
+ continue;
130
+ }
131
+ functions.push(tool({ name: def.name, description: def.description, parameters: def.inputSchema }));
132
+ }
133
+ }
134
+ if (options.toolChoice?.type === "required" || options.toolChoice?.type === "tool") {
135
+ warnings.push({
136
+ type: "unsupported",
137
+ feature: `toolChoice "${options.toolChoice.type}"`,
138
+ details: "Apple\u2019s model decides for itself whether to call a tool."
139
+ });
140
+ }
141
+ let schema;
142
+ if (options.responseFormat?.type === "json") {
143
+ if (options.responseFormat.schema !== void 0) {
144
+ schema = options.responseFormat.schema;
145
+ } else {
146
+ messages.unshift({ role: "system", content: "Reply with a single JSON value and nothing else." });
147
+ warnings.push({ type: "compatibility", feature: "responseFormat json without a schema", details: "requested in the prompt, not enforced" });
148
+ }
149
+ }
150
+ const tools = [...apple2.builtInTools ?? [], ...functions];
151
+ return {
152
+ messages,
153
+ schema,
154
+ warnings,
155
+ images,
156
+ call: {
157
+ temperature: options.temperature,
158
+ maxTokens: options.maxOutputTokens,
159
+ sampling,
160
+ signal: options.abortSignal,
161
+ tools: tools.length > 0 ? tools : void 0,
162
+ useCase: apple2.useCase,
163
+ guardrails: apple2.guardrails,
164
+ trimHistory: apple2.trimHistory,
165
+ webSearch: apple2.webSearch
166
+ }
167
+ };
168
+ }
169
+ /** Content parts: the text, then any tool call the SDK has to run. */
170
+ content(result) {
171
+ const content = [];
172
+ if (result.text !== "" && result.finishReason !== "tool-calls") content.push({ type: "text", text: result.text });
173
+ for (const call of result.toolCalls) {
174
+ if (call.output !== void 0) continue;
175
+ content.push({ type: "tool-call", toolCallId: call.id, toolName: call.name, input: JSON.stringify(call.arguments ?? {}) });
176
+ }
177
+ return content;
178
+ }
179
+ async doGenerate(options) {
180
+ const { messages, call, schema, warnings, images } = await this.prepare(options);
181
+ try {
182
+ const result = schema === void 0 ? await this.client.generate(messages, call) : await this.client.generate(messages, { ...call, schema });
183
+ return {
184
+ content: this.content(result),
185
+ finishReason: finishV3(result.finishReason),
186
+ usage: usageV3(result.usage),
187
+ warnings,
188
+ response: { id: `apple-${Date.now().toString(36)}`, timestamp: /* @__PURE__ */ new Date(), modelId: this.modelId },
189
+ providerMetadata: {
190
+ apple: { tier: result.tier, durationMs: result.durationMs, trimmedTurns: result.trimmedTurns }
191
+ }
192
+ };
193
+ } finally {
194
+ await images.dispose();
195
+ }
196
+ }
197
+ async doStream(options) {
198
+ const { messages, call, schema, warnings, images } = await this.prepare(options);
199
+ const client = this.client;
200
+ const modelId = this.modelId;
201
+ const content = (result) => this.content(result);
202
+ const stream = new ReadableStream({
203
+ async start(controller) {
204
+ controller.enqueue({ type: "stream-start", warnings });
205
+ controller.enqueue({ type: "response-metadata", id: `apple-${Date.now().toString(36)}`, timestamp: /* @__PURE__ */ new Date(), modelId });
206
+ const textId = "text-0";
207
+ let textOpen = false;
208
+ const openText = () => {
209
+ if (!textOpen) controller.enqueue({ type: "text-start", id: textId });
210
+ textOpen = true;
211
+ };
212
+ try {
213
+ let result;
214
+ if (schema === void 0) {
215
+ const textStream = client.stream(messages, call);
216
+ for await (const delta of textStream) {
217
+ openText();
218
+ controller.enqueue({ type: "text-delta", id: textId, delta });
219
+ }
220
+ result = await textStream.result;
221
+ } else {
222
+ result = await client.generate(messages, { ...call, schema });
223
+ if (result.finishReason !== "tool-calls") {
224
+ openText();
225
+ controller.enqueue({ type: "text-delta", id: textId, delta: result.text });
226
+ }
227
+ }
228
+ if (textOpen) controller.enqueue({ type: "text-end", id: textId });
229
+ for (const part of content(result)) {
230
+ if (part.type === "tool-call") controller.enqueue(part);
231
+ }
232
+ controller.enqueue({
233
+ type: "finish",
234
+ finishReason: finishV3(result.finishReason),
235
+ usage: usageV3(result.usage),
236
+ providerMetadata: { apple: { tier: result.tier, durationMs: result.durationMs, trimmedTurns: result.trimmedTurns } }
237
+ });
238
+ } catch (error) {
239
+ controller.enqueue({ type: "error", error });
240
+ } finally {
241
+ await images.dispose();
242
+ controller.close();
243
+ }
244
+ }
245
+ });
246
+ return { stream };
247
+ }
248
+ };
249
+ function createApple(settings = {}) {
250
+ const { client: shared, ...defaults } = settings;
251
+ const clients = /* @__PURE__ */ new Map();
252
+ const clientFor = (tier) => {
253
+ if (shared !== void 0) return shared;
254
+ let client = clients.get(tier);
255
+ if (client === void 0) {
256
+ client = new AppleLLM({ ...defaults, tier });
257
+ clients.set(tier, client);
258
+ }
259
+ return client;
260
+ };
261
+ const languageModel = (modelId = "device") => {
262
+ if (modelId !== "device" && modelId !== "cloud" && modelId !== "auto") {
263
+ throw new AppleLLMError(`Unknown Apple model "${String(modelId)}" (want device, cloud or auto).`);
264
+ }
265
+ return new AppleLanguageModel(modelId, clientFor(modelId));
266
+ };
267
+ const unsupported = (kind) => () => {
268
+ throw new AppleLLMError(`Apple's built-in models do not provide ${kind} models.`);
269
+ };
270
+ return Object.assign((modelId) => languageModel(modelId), {
271
+ specificationVersion: "v3",
272
+ languageModel,
273
+ embeddingModel: unsupported("embedding"),
274
+ imageModel: unsupported("image")
275
+ });
276
+ }
277
+ var apple = createApple();
278
+ export {
279
+ apple,
280
+ createApple
281
+ };