modelpact 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +372 -0
- package/dist/helpers/abort.d.ts +14 -0
- package/dist/helpers/abort.d.ts.map +1 -0
- package/dist/helpers/abort.js +22 -0
- package/dist/helpers/abort.js.map +1 -0
- package/dist/helpers/lifetime.d.ts +34 -0
- package/dist/helpers/lifetime.d.ts.map +1 -0
- package/dist/helpers/lifetime.js +71 -0
- package/dist/helpers/lifetime.js.map +1 -0
- package/dist/helpers/monitor.d.ts +52 -0
- package/dist/helpers/monitor.d.ts.map +1 -0
- package/dist/helpers/monitor.js +69 -0
- package/dist/helpers/monitor.js.map +1 -0
- package/dist/helpers/ndjson.d.ts +19 -0
- package/dist/helpers/ndjson.d.ts.map +1 -0
- package/dist/helpers/ndjson.js +39 -0
- package/dist/helpers/ndjson.js.map +1 -0
- package/dist/helpers/overflow.d.ts +50 -0
- package/dist/helpers/overflow.d.ts.map +1 -0
- package/dist/helpers/overflow.js +72 -0
- package/dist/helpers/overflow.js.map +1 -0
- package/dist/helpers/transcript.d.ts +22 -0
- package/dist/helpers/transcript.d.ts.map +1 -0
- package/dist/helpers/transcript.js +26 -0
- package/dist/helpers/transcript.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle/01_access.d.ts +13 -0
- package/dist/lifecycle/01_access.d.ts.map +1 -0
- package/dist/lifecycle/01_access.js +45 -0
- package/dist/lifecycle/01_access.js.map +1 -0
- package/dist/lifecycle/02_download.d.ts +8 -0
- package/dist/lifecycle/02_download.d.ts.map +1 -0
- package/dist/lifecycle/02_download.js +12 -0
- package/dist/lifecycle/02_download.js.map +1 -0
- package/dist/lifecycle/03_open.d.ts +22 -0
- package/dist/lifecycle/03_open.d.ts.map +1 -0
- package/dist/lifecycle/03_open.js +39 -0
- package/dist/lifecycle/03_open.js.map +1 -0
- package/dist/lifecycle/04_generate.d.ts +15 -0
- package/dist/lifecycle/04_generate.d.ts.map +1 -0
- package/dist/lifecycle/04_generate.js +154 -0
- package/dist/lifecycle/04_generate.js.map +1 -0
- package/dist/lifecycle/05_close.d.ts +4 -0
- package/dist/lifecycle/05_close.d.ts.map +1 -0
- package/dist/lifecycle/05_close.js +8 -0
- package/dist/lifecycle/05_close.js.map +1 -0
- package/dist/providers/create.d.ts +5 -0
- package/dist/providers/create.d.ts.map +1 -0
- package/dist/providers/create.js +7 -0
- package/dist/providers/create.js.map +1 -0
- package/dist/providers/mock.d.ts +36 -0
- package/dist/providers/mock.d.ts.map +1 -0
- package/dist/providers/mock.js +128 -0
- package/dist/providers/mock.js.map +1 -0
- package/dist/providers/ollama.d.ts +33 -0
- package/dist/providers/ollama.d.ts.map +1 -0
- package/dist/providers/ollama.js +275 -0
- package/dist/providers/ollama.js.map +1 -0
- package/dist/providers/prompt-api.d.ts +23 -0
- package/dist/providers/prompt-api.d.ts.map +1 -0
- package/dist/providers/prompt-api.js +203 -0
- package/dist/providers/prompt-api.js.map +1 -0
- package/dist/providers/registry.d.ts +22 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +30 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/testing/contract.d.ts +47 -0
- package/dist/testing/contract.d.ts.map +1 -0
- package/dist/testing/contract.js +518 -0
- package/dist/testing/contract.js.map +1 -0
- package/dist/testing/index.d.ts +9 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +9 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/types/backend.d.ts +63 -0
- package/dist/types/backend.d.ts.map +1 -0
- package/dist/types/backend.js +11 -0
- package/dist/types/backend.js.map +1 -0
- package/dist/types/failures.d.ts +115 -0
- package/dist/types/failures.d.ts.map +1 -0
- package/dist/types/failures.js +68 -0
- package/dist/types/failures.js.map +1 -0
- package/dist/types/foundations.d.ts +35 -0
- package/dist/types/foundations.d.ts.map +1 -0
- package/dist/types/foundations.js +30 -0
- package/dist/types/foundations.js.map +1 -0
- package/dist/types/messages.d.ts +30 -0
- package/dist/types/messages.d.ts.map +1 -0
- package/dist/types/messages.js +2 -0
- package/dist/types/messages.js.map +1 -0
- package/dist/types/provider.d.ts +22 -0
- package/dist/types/provider.d.ts.map +1 -0
- package/dist/types/provider.js +2 -0
- package/dist/types/provider.js.map +1 -0
- package/dist/types/session.d.ts +156 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +2 -0
- package/dist/types/session.js.map +1 -0
- package/dist/types/usage.d.ts +25 -0
- package/dist/types/usage.d.ts.map +1 -0
- package/dist/types/usage.js +16 -0
- package/dist/types/usage.js.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ollama on a machine you can reach over HTTP.
|
|
3
|
+
*
|
|
4
|
+
* The daemon keeps nothing between requests: `/api/chat` is handed the whole
|
|
5
|
+
* conversation every time, which is what `request.history` is for. Three
|
|
6
|
+
* endpoints are the whole backend — `/api/tags` says what is downloaded,
|
|
7
|
+
* `/api/pull` downloads, `/api/chat` generates — and everything else the
|
|
8
|
+
* contract promises is `../lifecycle`'s.
|
|
9
|
+
*
|
|
10
|
+
* Shapes here were read off a running daemon, not off the docs: a chat stream
|
|
11
|
+
* is NDJSON whose last line carries the counts, a pull line carries `completed`
|
|
12
|
+
* and `total` per layer, and an error is an HTTP status with `{"error": "…"}`.
|
|
13
|
+
*/
|
|
14
|
+
import { ndjsonLines } from "../helpers/ndjson.js";
|
|
15
|
+
import { err, fraction, ok, tokens, } from "../types/foundations.js";
|
|
16
|
+
import { AiError } from "../types/failures.js";
|
|
17
|
+
import { contextUsage } from "../types/usage.js";
|
|
18
|
+
import { createProvider } from "./create.js";
|
|
19
|
+
const DEFAULTS = {
|
|
20
|
+
host: "http://127.0.0.1:11434",
|
|
21
|
+
contextWindow: 4096,
|
|
22
|
+
};
|
|
23
|
+
const asRecord = (value) => {
|
|
24
|
+
const isObject = typeof value === "object" && value !== null;
|
|
25
|
+
return isObject && !Array.isArray(value)
|
|
26
|
+
? value
|
|
27
|
+
: null;
|
|
28
|
+
};
|
|
29
|
+
const asString = (value) => typeof value === "string" ? value : null;
|
|
30
|
+
const asNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
31
|
+
const parseJson = (text) => {
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(text);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const toEndpoint = (config) => ({
|
|
40
|
+
host: config.host ?? DEFAULTS.host,
|
|
41
|
+
// Bound, and not optional: in a browser `fetch` is a method of the window and
|
|
42
|
+
// throws `TypeError: Illegal invocation` once it is held on its own. Node
|
|
43
|
+
// does not care, so nothing but a page catches this (measured).
|
|
44
|
+
call: config.fetch ?? globalThis.fetch.bind(globalThis),
|
|
45
|
+
});
|
|
46
|
+
const postTo = (endpoint, path, body, signal) => endpoint.call(`${endpoint.host}${path}`, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers: { "content-type": "application/json" },
|
|
49
|
+
body: JSON.stringify(body),
|
|
50
|
+
...(signal === undefined ? {} : { signal }),
|
|
51
|
+
});
|
|
52
|
+
/** The daemon says what went wrong in the body; a status alone would lose it. */
|
|
53
|
+
const failureFromResponse = async (response) => {
|
|
54
|
+
const text = await response.text().catch(() => "");
|
|
55
|
+
const errorText = asString(asRecord(parseJson(text))?.error);
|
|
56
|
+
const detail = errorText ?? `${response.status} from the daemon`;
|
|
57
|
+
// 400 is the daemon reading the request and refusing it, which is a bug on
|
|
58
|
+
// this side. Everything else is the daemon's own trouble.
|
|
59
|
+
return response.status === 400
|
|
60
|
+
? { kind: "invalid-input", detail }
|
|
61
|
+
: { kind: "failed", detail };
|
|
62
|
+
};
|
|
63
|
+
const listModels = async (endpoint) => {
|
|
64
|
+
const response = await endpoint.call(`${endpoint.host}/api/tags`);
|
|
65
|
+
if (!response.ok)
|
|
66
|
+
return [];
|
|
67
|
+
const listedModels = asRecord(await response.json().catch(() => null))?.models;
|
|
68
|
+
if (!Array.isArray(listedModels))
|
|
69
|
+
return [];
|
|
70
|
+
const names = listedModels.map((entry) => asString(asRecord(entry)?.model));
|
|
71
|
+
return names.filter((name) => name !== null);
|
|
72
|
+
};
|
|
73
|
+
const getAvailability = async (config) => {
|
|
74
|
+
const endpoint = toEndpoint(config);
|
|
75
|
+
let downloadedModels;
|
|
76
|
+
try {
|
|
77
|
+
downloadedModels = await listModels(endpoint);
|
|
78
|
+
}
|
|
79
|
+
catch (cause) {
|
|
80
|
+
// Nothing answering is not a failed request, it is no Ollama here.
|
|
81
|
+
return { kind: "unavailable", reason: { kind: "unsupported", cause } };
|
|
82
|
+
}
|
|
83
|
+
const isDownloaded = downloadedModels.includes(config.model);
|
|
84
|
+
return isDownloaded
|
|
85
|
+
? { kind: "ready" }
|
|
86
|
+
: { kind: "needs-download", started: false };
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Pull progress is per layer, and layers are announced as the pull reaches
|
|
90
|
+
* them, so the denominator grows while it runs. The share can therefore stall,
|
|
91
|
+
* and `ProgressMonitor` drops it if it would step back. `success` is what
|
|
92
|
+
* makes the last report a 1, since that line carries no numbers.
|
|
93
|
+
*/
|
|
94
|
+
const readPullProgress = (reportProgress) => {
|
|
95
|
+
const layers = new Map();
|
|
96
|
+
return new TransformStream({
|
|
97
|
+
transform: (line, controller) => {
|
|
98
|
+
const parsedLine = asRecord(parseJson(line));
|
|
99
|
+
if (parsedLine === null)
|
|
100
|
+
return;
|
|
101
|
+
const errorText = asString(parsedLine.error);
|
|
102
|
+
if (errorText !== null)
|
|
103
|
+
throw new AiError({ kind: "failed", detail: errorText });
|
|
104
|
+
const digest = asString(parsedLine.digest);
|
|
105
|
+
const total = asNumber(parsedLine.total);
|
|
106
|
+
const completed = asNumber(parsedLine.completed) ?? 0;
|
|
107
|
+
if (digest !== null && total !== null && total > 0) {
|
|
108
|
+
layers.set(digest, { total, completed });
|
|
109
|
+
}
|
|
110
|
+
const isDone = asString(parsedLine.status) === "success";
|
|
111
|
+
const pulledShare = isDone ? 1 : getPulledShare(layers);
|
|
112
|
+
const progress = fraction(pulledShare);
|
|
113
|
+
if (progress !== null)
|
|
114
|
+
reportProgress(progress);
|
|
115
|
+
controller.enqueue(line);
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
const getPulledShare = (layers) => {
|
|
120
|
+
let total = 0;
|
|
121
|
+
let completed = 0;
|
|
122
|
+
for (const layer of layers.values()) {
|
|
123
|
+
total += layer.total;
|
|
124
|
+
completed += layer.completed;
|
|
125
|
+
}
|
|
126
|
+
return total === 0 ? 0 : completed / total;
|
|
127
|
+
};
|
|
128
|
+
const pullModel = async (endpoint, model, reportProgress) => {
|
|
129
|
+
const response = await postTo(endpoint, "/api/pull", { model, stream: true });
|
|
130
|
+
if (!response.ok)
|
|
131
|
+
return err(await failureFromResponse(response));
|
|
132
|
+
if (response.body === null)
|
|
133
|
+
return err({ kind: "failed", detail: "the pull sent no body" });
|
|
134
|
+
const lines = response.body
|
|
135
|
+
.pipeThrough(new TextDecoderStream())
|
|
136
|
+
.pipeThrough(ndjsonLines())
|
|
137
|
+
.pipeThrough(readPullProgress(reportProgress));
|
|
138
|
+
const reader = lines.getReader();
|
|
139
|
+
try {
|
|
140
|
+
// Read to the end: the transform above is where the reporting happens, and
|
|
141
|
+
// the body is not finished until it stops yielding.
|
|
142
|
+
for (;;) {
|
|
143
|
+
const chunk = await reader.read();
|
|
144
|
+
if (chunk.done)
|
|
145
|
+
return ok(null);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
return err(error instanceof AiError
|
|
150
|
+
? error.failure
|
|
151
|
+
: { kind: "failed", detail: "the pull was interrupted", cause: error });
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
class OllamaModel {
|
|
155
|
+
#endpoint;
|
|
156
|
+
#model;
|
|
157
|
+
#contextWindow;
|
|
158
|
+
#system;
|
|
159
|
+
/** The last turn's counts, which is what the context holds now rather than a running sum. */
|
|
160
|
+
#usedTokens = 0;
|
|
161
|
+
constructor(config, options) {
|
|
162
|
+
this.#endpoint = toEndpoint(config);
|
|
163
|
+
this.#model = config.model;
|
|
164
|
+
this.#contextWindow = config.contextWindow ?? DEFAULTS.contextWindow;
|
|
165
|
+
this.#system = options.session.system;
|
|
166
|
+
}
|
|
167
|
+
generateStream = async (input, request) => {
|
|
168
|
+
const responseResult = await this.#chat(input, request, true);
|
|
169
|
+
if (!responseResult.ok)
|
|
170
|
+
return responseResult;
|
|
171
|
+
const body = responseResult.value.body;
|
|
172
|
+
if (body === null)
|
|
173
|
+
return err({ kind: "failed", detail: "the chat sent no body" });
|
|
174
|
+
const deltas = body
|
|
175
|
+
.pipeThrough(new TextDecoderStream())
|
|
176
|
+
.pipeThrough(ndjsonLines())
|
|
177
|
+
.pipeThrough(this.#readChatLines());
|
|
178
|
+
return ok(deltas);
|
|
179
|
+
};
|
|
180
|
+
generateWhole = async (input, request) => {
|
|
181
|
+
const responseResult = await this.#chat(input, request, false);
|
|
182
|
+
if (!responseResult.ok)
|
|
183
|
+
return responseResult;
|
|
184
|
+
const parsedBody = asRecord(await responseResult.value.json().catch(() => null));
|
|
185
|
+
if (parsedBody === null)
|
|
186
|
+
return err({ kind: "failed", detail: "the chat sent no JSON" });
|
|
187
|
+
const answerText = asString(asRecord(parsedBody.message)?.content);
|
|
188
|
+
if (answerText === null)
|
|
189
|
+
return err({ kind: "failed", detail: "the chat sent no message" });
|
|
190
|
+
this.#charge(parsedBody);
|
|
191
|
+
return ok(answerText);
|
|
192
|
+
};
|
|
193
|
+
usage = () => {
|
|
194
|
+
const used = tokens(this.#usedTokens) ?? ZERO_TOKENS;
|
|
195
|
+
return contextUsage(used, this.#contextWindow);
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* Nothing to release. The daemon unloads on its own timer, and telling it to
|
|
199
|
+
* unload here would take the model out from under whoever else is on it.
|
|
200
|
+
*/
|
|
201
|
+
dispose = () => undefined;
|
|
202
|
+
async #chat(input, request, stream) {
|
|
203
|
+
const askedMessage = { role: "user", content: input };
|
|
204
|
+
const conversation = [...request.history, askedMessage];
|
|
205
|
+
const messages = this.#system === undefined
|
|
206
|
+
? conversation
|
|
207
|
+
: [{ role: "user", content: this.#system }, ...conversation];
|
|
208
|
+
const body = {
|
|
209
|
+
model: this.#model,
|
|
210
|
+
messages,
|
|
211
|
+
stream,
|
|
212
|
+
options: { num_ctx: this.#contextWindow },
|
|
213
|
+
...(request.schema === undefined ? {} : { format: request.schema }),
|
|
214
|
+
};
|
|
215
|
+
const response = await postTo(this.#endpoint, "/api/chat", body, request.signal);
|
|
216
|
+
return response.ok
|
|
217
|
+
? ok(response)
|
|
218
|
+
: err(await failureFromResponse(response));
|
|
219
|
+
}
|
|
220
|
+
/** Content out, counts kept: the last line carries both `done` and the totals. */
|
|
221
|
+
#readChatLines() {
|
|
222
|
+
return new TransformStream({
|
|
223
|
+
transform: (line, controller) => {
|
|
224
|
+
const parsedLine = asRecord(parseJson(line));
|
|
225
|
+
if (parsedLine === null)
|
|
226
|
+
return;
|
|
227
|
+
const errorText = asString(parsedLine.error);
|
|
228
|
+
if (errorText !== null)
|
|
229
|
+
throw new AiError({ kind: "failed", detail: errorText });
|
|
230
|
+
if (parsedLine.done === true)
|
|
231
|
+
this.#charge(parsedLine);
|
|
232
|
+
const delta = asString(asRecord(parsedLine.message)?.content) ?? "";
|
|
233
|
+
if (delta !== "")
|
|
234
|
+
controller.enqueue(delta);
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* `prompt_eval_count` is the whole prompt, history included, so the two
|
|
240
|
+
* counts together are what the window holds after this turn. Summing across
|
|
241
|
+
* turns would count the history once per turn.
|
|
242
|
+
*/
|
|
243
|
+
#charge(finishedLine) {
|
|
244
|
+
const promptTokens = asNumber(finishedLine.prompt_eval_count) ?? 0;
|
|
245
|
+
const answerTokens = asNumber(finishedLine.eval_count) ?? 0;
|
|
246
|
+
this.#usedTokens = promptTokens + answerTokens;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const ZERO_TOKENS = tokens(0);
|
|
250
|
+
const connectOllama = async (config, options) => {
|
|
251
|
+
const endpoint = toEndpoint(config);
|
|
252
|
+
let downloadedModels;
|
|
253
|
+
try {
|
|
254
|
+
downloadedModels = await listModels(endpoint);
|
|
255
|
+
}
|
|
256
|
+
catch (cause) {
|
|
257
|
+
return err({ kind: "unsupported", cause });
|
|
258
|
+
}
|
|
259
|
+
if (!downloadedModels.includes(config.model)) {
|
|
260
|
+
const pullResult = await pullModel(endpoint, config.model, options.reportProgress);
|
|
261
|
+
if (!pullResult.ok)
|
|
262
|
+
return pullResult;
|
|
263
|
+
}
|
|
264
|
+
return ok(new OllamaModel(config, options));
|
|
265
|
+
};
|
|
266
|
+
export function makeOllamaProvider(config) {
|
|
267
|
+
const backend = {
|
|
268
|
+
name: "ollama",
|
|
269
|
+
modalities: ["text"],
|
|
270
|
+
availability: () => getAvailability(config),
|
|
271
|
+
connect: (options) => connectOllama(config, options),
|
|
272
|
+
};
|
|
273
|
+
return createProvider(backend);
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=ollama.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../src/providers/ollama.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrome's built-in model, through the Prompt API.
|
|
3
|
+
*
|
|
4
|
+
* The one backend that keeps the conversation itself: `LanguageModel` is a
|
|
5
|
+
* session object, `prompt()` appends to it, and `request.history` is therefore
|
|
6
|
+
* read by nobody here. Two more things it owns that the others do not — it
|
|
7
|
+
* fires its own `contextoverflow`, which is forwarded rather than re-derived,
|
|
8
|
+
* and it reports usage against a window it decides.
|
|
9
|
+
*
|
|
10
|
+
* It lives in a page and nowhere else. In node the global is missing, and
|
|
11
|
+
* `access` answers `unavailable` with `unsupported` rather than throwing.
|
|
12
|
+
*
|
|
13
|
+
* The declarations are `@types/dom-chromium-ai`, patched under `patches/` to
|
|
14
|
+
* close the gap between the IDL and the spec; `src/types.test-d.ts` is where
|
|
15
|
+
* the two meet. They are named in function bodies and nowhere in a signature
|
|
16
|
+
* that leaves this file: an exported type naming `LanguageModel` puts the same
|
|
17
|
+
* name in the emitted `.d.ts`, and a consumer who has not installed those
|
|
18
|
+
* declarations, or who lists `types` explicitly, then cannot compile the
|
|
19
|
+
* package at all. `external/webgpu-provider` is where that was found.
|
|
20
|
+
*/
|
|
21
|
+
import type { AiProvider } from "../types/provider.js";
|
|
22
|
+
export declare function makePromptApiProvider(): AiProvider;
|
|
23
|
+
//# sourceMappingURL=prompt-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-api.d.ts","sourceRoot":"","sources":["../../src/providers/prompt-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAkBH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AA4NvD,wBAAgB,qBAAqB,IAAI,UAAU,CAUlD"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrome's built-in model, through the Prompt API.
|
|
3
|
+
*
|
|
4
|
+
* The one backend that keeps the conversation itself: `LanguageModel` is a
|
|
5
|
+
* session object, `prompt()` appends to it, and `request.history` is therefore
|
|
6
|
+
* read by nobody here. Two more things it owns that the others do not — it
|
|
7
|
+
* fires its own `contextoverflow`, which is forwarded rather than re-derived,
|
|
8
|
+
* and it reports usage against a window it decides.
|
|
9
|
+
*
|
|
10
|
+
* It lives in a page and nowhere else. In node the global is missing, and
|
|
11
|
+
* `access` answers `unavailable` with `unsupported` rather than throwing.
|
|
12
|
+
*
|
|
13
|
+
* The declarations are `@types/dom-chromium-ai`, patched under `patches/` to
|
|
14
|
+
* close the gap between the IDL and the spec; `src/types.test-d.ts` is where
|
|
15
|
+
* the two meet. They are named in function bodies and nowhere in a signature
|
|
16
|
+
* that leaves this file: an exported type naming `LanguageModel` puts the same
|
|
17
|
+
* name in the emitted `.d.ts`, and a consumer who has not installed those
|
|
18
|
+
* declarations, or who lists `types` explicitly, then cannot compile the
|
|
19
|
+
* package at all. `external/webgpu-provider` is where that was found.
|
|
20
|
+
*/
|
|
21
|
+
import { failureFromError } from "../types/failures.js";
|
|
22
|
+
import { err, fraction, ok, tokens, } from "../types/foundations.js";
|
|
23
|
+
import { contextUsage } from "../types/usage.js";
|
|
24
|
+
import { createProvider } from "./create.js";
|
|
25
|
+
/**
|
|
26
|
+
* The page's own class, or nothing.
|
|
27
|
+
*
|
|
28
|
+
* There is no way to hand one in. A polyfill is already this — it defines the
|
|
29
|
+
* global — and a test sets the global too, which is the same path the browser
|
|
30
|
+
* takes rather than one beside it.
|
|
31
|
+
*
|
|
32
|
+
* `typeof` and not a bare read: outside a page the name is not declared, and
|
|
33
|
+
* naming it there throws rather than answering undefined.
|
|
34
|
+
*/
|
|
35
|
+
const getPlatformApi = () => typeof LanguageModel === "undefined" ? null : LanguageModel;
|
|
36
|
+
const toExpectations = (askedExpectations) => {
|
|
37
|
+
if (askedExpectations === undefined || askedExpectations.length === 0)
|
|
38
|
+
return undefined;
|
|
39
|
+
return askedExpectations.map((expectation) => ({
|
|
40
|
+
type: expectation.type,
|
|
41
|
+
...(expectation.languages === undefined
|
|
42
|
+
? {}
|
|
43
|
+
: { languages: [...expectation.languages] }),
|
|
44
|
+
}));
|
|
45
|
+
};
|
|
46
|
+
const toCoreOptions = (request) => {
|
|
47
|
+
const inputs = toExpectations(request.inputs);
|
|
48
|
+
const outputs = toExpectations(request.outputs);
|
|
49
|
+
return {
|
|
50
|
+
...(inputs === undefined ? {} : { expectedInputs: inputs }),
|
|
51
|
+
...(outputs === undefined ? {} : { expectedOutputs: outputs }),
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* The four the spec has, against the three the contract has. `downloading` and
|
|
56
|
+
* `downloadable` are one branch here and differ only in `started`, which is the
|
|
57
|
+
* question a caller actually has: is someone already fetching this.
|
|
58
|
+
*/
|
|
59
|
+
const toAvailability = (specAvailability) => {
|
|
60
|
+
switch (specAvailability) {
|
|
61
|
+
case "available":
|
|
62
|
+
return { kind: "ready" };
|
|
63
|
+
case "downloadable":
|
|
64
|
+
return { kind: "needs-download", started: false };
|
|
65
|
+
case "downloading":
|
|
66
|
+
return { kind: "needs-download", started: true };
|
|
67
|
+
case "unavailable":
|
|
68
|
+
// Empty lists: the spec says no for the whole request without naming a
|
|
69
|
+
// part, and inventing one would be worse than saying nothing.
|
|
70
|
+
return {
|
|
71
|
+
kind: "unavailable",
|
|
72
|
+
reason: { kind: "unsupported-config", languages: [] },
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const getAvailability = async (request) => {
|
|
77
|
+
const api = getPlatformApi();
|
|
78
|
+
if (api === null)
|
|
79
|
+
return { kind: "unavailable", reason: { kind: "unsupported" } };
|
|
80
|
+
try {
|
|
81
|
+
const specAvailability = await api.availability(toCoreOptions(request));
|
|
82
|
+
return toAvailability(specAvailability);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
// `NotAllowedError` for the permissions policy, `InvalidStateError` for a
|
|
86
|
+
// document that is not fully active: both are refusals, not crashes.
|
|
87
|
+
return { kind: "unavailable", reason: failureFromError(error) };
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
/** System first or not at all, which is what the patched tuple type says too. */
|
|
91
|
+
const toInitialPrompts = (session) => {
|
|
92
|
+
const historyPrompts = (session.history ?? []).map((message) => ({ role: message.role, content: message.content }));
|
|
93
|
+
if (session.system === undefined)
|
|
94
|
+
return historyPrompts.length === 0 ? undefined : historyPrompts;
|
|
95
|
+
return [{ role: "system", content: session.system }, ...historyPrompts];
|
|
96
|
+
};
|
|
97
|
+
const toPromptOptions = (request) => request.schema === undefined
|
|
98
|
+
? { signal: request.signal }
|
|
99
|
+
: { signal: request.signal, responseConstraint: request.schema };
|
|
100
|
+
/**
|
|
101
|
+
* `contextUsage` and `contextWindow` replaced `inputUsage` and `inputQuota`,
|
|
102
|
+
* and a browser in the field may have either pair. Read as unknown because the
|
|
103
|
+
* declarations promise the new names on a version that has only the old.
|
|
104
|
+
*/
|
|
105
|
+
const readUsage = (session) => {
|
|
106
|
+
const sessionFields = session;
|
|
107
|
+
const used = readNumber(sessionFields, "contextUsage", "inputUsage");
|
|
108
|
+
const windowTokens = readNumber(sessionFields, "contextWindow", "inputQuota");
|
|
109
|
+
if (used === null || windowTokens === null)
|
|
110
|
+
return { kind: "unknown" };
|
|
111
|
+
const usedTokens = tokens(used);
|
|
112
|
+
return usedTokens === null
|
|
113
|
+
? { kind: "unknown" }
|
|
114
|
+
: contextUsage(usedTokens, windowTokens);
|
|
115
|
+
};
|
|
116
|
+
const readNumber = (sessionFields, currentName, olderName) => {
|
|
117
|
+
const value = sessionFields[currentName] ?? sessionFields[olderName];
|
|
118
|
+
return typeof value === "number" ? value : null;
|
|
119
|
+
};
|
|
120
|
+
class PromptApiModel {
|
|
121
|
+
#session;
|
|
122
|
+
constructor(session) {
|
|
123
|
+
this.#session = session;
|
|
124
|
+
}
|
|
125
|
+
generateStream = (input, request) => {
|
|
126
|
+
try {
|
|
127
|
+
const deltas = this.#session.promptStreaming(input, toPromptOptions(request));
|
|
128
|
+
return Promise.resolve(ok(deltas));
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
return Promise.resolve(err(this.#refineFailure(error)));
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
generateWhole = async (input, request) => {
|
|
135
|
+
try {
|
|
136
|
+
const answerText = await this.#session.prompt(input, toPromptOptions(request));
|
|
137
|
+
return ok(answerText);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
return err(this.#refineFailure(error));
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
usage = () => readUsage(this.#session);
|
|
144
|
+
dispose = () => {
|
|
145
|
+
this.#session.destroy();
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* `QuotaExceededError` carries no measurement, and the generic mapping says
|
|
149
|
+
* so; holding the session is what lets this one attach the reading.
|
|
150
|
+
*/
|
|
151
|
+
#refineFailure(error) {
|
|
152
|
+
const failure = failureFromError(error);
|
|
153
|
+
return failure.kind === "context-overflow"
|
|
154
|
+
? { ...failure, usage: this.usage() }
|
|
155
|
+
: failure;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const connectPromptApi = async (options) => {
|
|
159
|
+
const api = getPlatformApi();
|
|
160
|
+
if (api === null)
|
|
161
|
+
return err({ kind: "unsupported" });
|
|
162
|
+
const initialPrompts = toInitialPrompts(options.session);
|
|
163
|
+
try {
|
|
164
|
+
const session = await api.create({
|
|
165
|
+
...toCoreOptions(options.request),
|
|
166
|
+
...(initialPrompts === undefined ? {} : { initialPrompts }),
|
|
167
|
+
...(options.session.signal === undefined
|
|
168
|
+
? {}
|
|
169
|
+
: { signal: options.session.signal }),
|
|
170
|
+
// Translated rather than forwarded, though the browser's monitor would
|
|
171
|
+
// satisfy `DownloadMonitor` as it stands: going through the lifecycle's
|
|
172
|
+
// own is what applies the never-decreasing rule to every backend alike.
|
|
173
|
+
monitor: (monitor) => {
|
|
174
|
+
monitor.ondownloadprogress = (event) => {
|
|
175
|
+
const progress = fraction(event.total === 0 ? 0 : event.loaded / event.total);
|
|
176
|
+
if (progress !== null)
|
|
177
|
+
options.reportProgress(progress);
|
|
178
|
+
};
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
// Forwarded, not re-derived: by the time a listener reads the counters the
|
|
182
|
+
// dropped turns are gone, and `used` can be back under the window.
|
|
183
|
+
session.oncontextoverflow = () => {
|
|
184
|
+
options.reportOverflow();
|
|
185
|
+
};
|
|
186
|
+
return ok(new PromptApiModel(session));
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
return err(failureFromError(error));
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
export function makePromptApiProvider() {
|
|
193
|
+
const backend = {
|
|
194
|
+
name: "prompt-api",
|
|
195
|
+
// Text only, because that is all `AiMessage` carries. The model takes more,
|
|
196
|
+
// and asking for it would promise a message this contract cannot build.
|
|
197
|
+
modalities: ["text"],
|
|
198
|
+
availability: (request) => getAvailability(request),
|
|
199
|
+
connect: (options) => connectPromptApi(options),
|
|
200
|
+
};
|
|
201
|
+
return createProvider(backend);
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=prompt-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-api.js","sourceRoot":"","sources":["../../src/providers/prompt-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The app's list of providers, which is the only place the full set is known.
|
|
3
|
+
*
|
|
4
|
+
* A backend written outside this package names itself, so `ProviderName` is a
|
|
5
|
+
* plain string and the closed union moved here. `keyof typeof registry` is the
|
|
6
|
+
* app's own set, and a switch over it stays exhaustive the way one over a
|
|
7
|
+
* hand-written union did.
|
|
8
|
+
*
|
|
9
|
+
* `defineProviders` exists for the trap in doing it by hand: annotating with
|
|
10
|
+
* `const providers: ProviderRegistry = {…}` widens the keys back to `string`
|
|
11
|
+
* and takes the exhaustiveness with them.
|
|
12
|
+
*/
|
|
13
|
+
import type { AiProvider } from "../types/provider.js";
|
|
14
|
+
export type ProviderRegistry = Readonly<Record<string, AiProvider>>;
|
|
15
|
+
/** Identity at runtime: it checks the values and leaves the keys as literals. */
|
|
16
|
+
export declare const defineProviders: <Registry extends ProviderRegistry>(registry: Registry) => Registry;
|
|
17
|
+
/**
|
|
18
|
+
* A saved choice comes back from storage as a string. This is the one place it
|
|
19
|
+
* becomes a name the registry holds, or nothing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function findProviderName<Name extends string>(registry: Readonly<Record<Name, AiProvider>>, saved: string): Name | null;
|
|
22
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;AAEpE,iFAAiF;AACjF,eAAO,MAAM,eAAe,GAAI,QAAQ,SAAS,gBAAgB,EAC/D,UAAU,QAAQ,KACjB,QAAoB,CAAC;AAExB;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,SAAS,MAAM,EAClD,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,EAC5C,KAAK,EAAE,MAAM,GACZ,IAAI,GAAG,IAAI,CASb"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The app's list of providers, which is the only place the full set is known.
|
|
3
|
+
*
|
|
4
|
+
* A backend written outside this package names itself, so `ProviderName` is a
|
|
5
|
+
* plain string and the closed union moved here. `keyof typeof registry` is the
|
|
6
|
+
* app's own set, and a switch over it stays exhaustive the way one over a
|
|
7
|
+
* hand-written union did.
|
|
8
|
+
*
|
|
9
|
+
* `defineProviders` exists for the trap in doing it by hand: annotating with
|
|
10
|
+
* `const providers: ProviderRegistry = {…}` widens the keys back to `string`
|
|
11
|
+
* and takes the exhaustiveness with them.
|
|
12
|
+
*/
|
|
13
|
+
/** Identity at runtime: it checks the values and leaves the keys as literals. */
|
|
14
|
+
export const defineProviders = (registry) => registry;
|
|
15
|
+
/**
|
|
16
|
+
* A saved choice comes back from storage as a string. This is the one place it
|
|
17
|
+
* becomes a name the registry holds, or nothing.
|
|
18
|
+
*/
|
|
19
|
+
export function findProviderName(registry, saved) {
|
|
20
|
+
// `Object.hasOwn`, not `in`: an inherited `toString` is not a provider, and
|
|
21
|
+
// `__proto__` is not a name anyone registered.
|
|
22
|
+
const registered = Object.hasOwn(registry, saved);
|
|
23
|
+
if (!registered)
|
|
24
|
+
return null;
|
|
25
|
+
// The check on the line above is what makes this cast honest. The names are
|
|
26
|
+
// a parameter rather than `keyof Registry` so that it stays one: under that
|
|
27
|
+
// constraint the compiler reads every key as a plain string.
|
|
28
|
+
return saved;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,iFAAiF;AACjF,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,QAAkB,EACR,EAAE,CAAC,QAAQ,CAAC;AAExB;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAA4C,EAC5C,KAAa;IAEb,4EAA4E;IAC5E,+CAA+C;IAC/C,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC7B,4EAA4E;IAC5E,4EAA4E;IAC5E,6DAA6D;IAC7D,OAAO,KAAa,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One set of assertions, run against every `AiProvider`.
|
|
3
|
+
*
|
|
4
|
+
* Written once and called for each backend, which sets a hard rule for what
|
|
5
|
+
* may be asserted here: only what `../types` promises. Anything about how a
|
|
6
|
+
* provider works inside — how many requests it made, what the prompt string
|
|
7
|
+
* looked like, which internal method ran first — differs between backends and
|
|
8
|
+
* would quietly turn this into a test of one of them.
|
|
9
|
+
*
|
|
10
|
+
* Published as `modelpact/testing`, so a backend written outside this package
|
|
11
|
+
* is held to the same standard as the ones inside it. `vitest` is a peer
|
|
12
|
+
* dependency: the file is `describe`/`test` calls, and two copies of the runner
|
|
13
|
+
* would register them in the wrong one.
|
|
14
|
+
*
|
|
15
|
+
* The filename carries no `.test` — the runner's glob is `src/**\/*.test.ts`
|
|
16
|
+
* and misses this file, which is a function others call rather than a suite of
|
|
17
|
+
* its own.
|
|
18
|
+
*/
|
|
19
|
+
import { type JsonSchema } from "../types/foundations.js";
|
|
20
|
+
import type { AiProvider } from "../types/provider.js";
|
|
21
|
+
/**
|
|
22
|
+
* `unavailable`, `needs-download` and a narrow window cannot be staged by every
|
|
23
|
+
* backend, so the factory returns null for a scenario it cannot produce and
|
|
24
|
+
* those tests skip. Skipping shows in the run output; silently passing would
|
|
25
|
+
* not.
|
|
26
|
+
*/
|
|
27
|
+
export type ContractScenario = "ready" | "unavailable" | "needs-download"
|
|
28
|
+
/**
|
|
29
|
+
* A window so narrow that one ordinary turn spends more than it holds. Its
|
|
30
|
+
* own scenario because overflowing a real window means minutes of
|
|
31
|
+
* generation, and a backend that cannot be told how wide to load returns
|
|
32
|
+
* null for it.
|
|
33
|
+
*/
|
|
34
|
+
| "tiny-window";
|
|
35
|
+
export type ProviderFactory = (scenario: ContractScenario) => AiProvider | null | Promise<AiProvider | null>;
|
|
36
|
+
/**
|
|
37
|
+
* The constraint the suite sends, and the shape a provider that honours one is
|
|
38
|
+
* measured against.
|
|
39
|
+
*
|
|
40
|
+
* Exported because a backend able to honour a schema has to be handed an answer
|
|
41
|
+
* that fits this exact one — a mock configures its reply against it. Kept to
|
|
42
|
+
* four keywords because the suite validates the answer itself: a general JSON
|
|
43
|
+
* Schema validator would be a dependency, and a second thing that can be wrong.
|
|
44
|
+
*/
|
|
45
|
+
export declare const CONTRACT_SCHEMA: JsonSchema;
|
|
46
|
+
export declare function describeContract(name: string, makeProvider: ProviderFactory): void;
|
|
47
|
+
//# sourceMappingURL=contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/testing/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAGtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAOvD;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GACxB,OAAO,GACP,aAAa,GACb,gBAAgB;AAClB;;;;;GAKG;GACD,aAAa,CAAC;AAElB,MAAM,MAAM,eAAe,GAAG,CAC5B,QAAQ,EAAE,gBAAgB,KACvB,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;AAiBpD;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,YAK1B,CAAC;AAiCH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,eAAe,GAC5B,IAAI,CA2bN"}
|