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.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +372 -0
  3. package/dist/helpers/abort.d.ts +14 -0
  4. package/dist/helpers/abort.d.ts.map +1 -0
  5. package/dist/helpers/abort.js +22 -0
  6. package/dist/helpers/abort.js.map +1 -0
  7. package/dist/helpers/lifetime.d.ts +34 -0
  8. package/dist/helpers/lifetime.d.ts.map +1 -0
  9. package/dist/helpers/lifetime.js +71 -0
  10. package/dist/helpers/lifetime.js.map +1 -0
  11. package/dist/helpers/monitor.d.ts +52 -0
  12. package/dist/helpers/monitor.d.ts.map +1 -0
  13. package/dist/helpers/monitor.js +69 -0
  14. package/dist/helpers/monitor.js.map +1 -0
  15. package/dist/helpers/ndjson.d.ts +19 -0
  16. package/dist/helpers/ndjson.d.ts.map +1 -0
  17. package/dist/helpers/ndjson.js +39 -0
  18. package/dist/helpers/ndjson.js.map +1 -0
  19. package/dist/helpers/overflow.d.ts +50 -0
  20. package/dist/helpers/overflow.d.ts.map +1 -0
  21. package/dist/helpers/overflow.js +72 -0
  22. package/dist/helpers/overflow.js.map +1 -0
  23. package/dist/helpers/transcript.d.ts +22 -0
  24. package/dist/helpers/transcript.d.ts.map +1 -0
  25. package/dist/helpers/transcript.js +26 -0
  26. package/dist/helpers/transcript.js.map +1 -0
  27. package/dist/index.d.ts +23 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +19 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/lifecycle/01_access.d.ts +13 -0
  32. package/dist/lifecycle/01_access.d.ts.map +1 -0
  33. package/dist/lifecycle/01_access.js +45 -0
  34. package/dist/lifecycle/01_access.js.map +1 -0
  35. package/dist/lifecycle/02_download.d.ts +8 -0
  36. package/dist/lifecycle/02_download.d.ts.map +1 -0
  37. package/dist/lifecycle/02_download.js +12 -0
  38. package/dist/lifecycle/02_download.js.map +1 -0
  39. package/dist/lifecycle/03_open.d.ts +22 -0
  40. package/dist/lifecycle/03_open.d.ts.map +1 -0
  41. package/dist/lifecycle/03_open.js +39 -0
  42. package/dist/lifecycle/03_open.js.map +1 -0
  43. package/dist/lifecycle/04_generate.d.ts +15 -0
  44. package/dist/lifecycle/04_generate.d.ts.map +1 -0
  45. package/dist/lifecycle/04_generate.js +154 -0
  46. package/dist/lifecycle/04_generate.js.map +1 -0
  47. package/dist/lifecycle/05_close.d.ts +4 -0
  48. package/dist/lifecycle/05_close.d.ts.map +1 -0
  49. package/dist/lifecycle/05_close.js +8 -0
  50. package/dist/lifecycle/05_close.js.map +1 -0
  51. package/dist/providers/create.d.ts +5 -0
  52. package/dist/providers/create.d.ts.map +1 -0
  53. package/dist/providers/create.js +7 -0
  54. package/dist/providers/create.js.map +1 -0
  55. package/dist/providers/mock.d.ts +36 -0
  56. package/dist/providers/mock.d.ts.map +1 -0
  57. package/dist/providers/mock.js +128 -0
  58. package/dist/providers/mock.js.map +1 -0
  59. package/dist/providers/ollama.d.ts +33 -0
  60. package/dist/providers/ollama.d.ts.map +1 -0
  61. package/dist/providers/ollama.js +275 -0
  62. package/dist/providers/ollama.js.map +1 -0
  63. package/dist/providers/prompt-api.d.ts +23 -0
  64. package/dist/providers/prompt-api.d.ts.map +1 -0
  65. package/dist/providers/prompt-api.js +203 -0
  66. package/dist/providers/prompt-api.js.map +1 -0
  67. package/dist/providers/registry.d.ts +22 -0
  68. package/dist/providers/registry.d.ts.map +1 -0
  69. package/dist/providers/registry.js +30 -0
  70. package/dist/providers/registry.js.map +1 -0
  71. package/dist/testing/contract.d.ts +47 -0
  72. package/dist/testing/contract.d.ts.map +1 -0
  73. package/dist/testing/contract.js +518 -0
  74. package/dist/testing/contract.js.map +1 -0
  75. package/dist/testing/index.d.ts +9 -0
  76. package/dist/testing/index.d.ts.map +1 -0
  77. package/dist/testing/index.js +9 -0
  78. package/dist/testing/index.js.map +1 -0
  79. package/dist/types/backend.d.ts +63 -0
  80. package/dist/types/backend.d.ts.map +1 -0
  81. package/dist/types/backend.js +11 -0
  82. package/dist/types/backend.js.map +1 -0
  83. package/dist/types/failures.d.ts +115 -0
  84. package/dist/types/failures.d.ts.map +1 -0
  85. package/dist/types/failures.js +68 -0
  86. package/dist/types/failures.js.map +1 -0
  87. package/dist/types/foundations.d.ts +35 -0
  88. package/dist/types/foundations.d.ts.map +1 -0
  89. package/dist/types/foundations.js +30 -0
  90. package/dist/types/foundations.js.map +1 -0
  91. package/dist/types/messages.d.ts +30 -0
  92. package/dist/types/messages.d.ts.map +1 -0
  93. package/dist/types/messages.js +2 -0
  94. package/dist/types/messages.js.map +1 -0
  95. package/dist/types/provider.d.ts +22 -0
  96. package/dist/types/provider.d.ts.map +1 -0
  97. package/dist/types/provider.js +2 -0
  98. package/dist/types/provider.js.map +1 -0
  99. package/dist/types/session.d.ts +156 -0
  100. package/dist/types/session.d.ts.map +1 -0
  101. package/dist/types/session.js +2 -0
  102. package/dist/types/session.js.map +1 -0
  103. package/dist/types/usage.d.ts +25 -0
  104. package/dist/types/usage.d.ts.map +1 -0
  105. package/dist/types/usage.js +16 -0
  106. package/dist/types/usage.js.map +1 -0
  107. 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"}