@templatical/ai-kit 0.0.0-stage → 0.51.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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +63 -2
  3. package/dist/adapters/anthropic.d.ts +31 -0
  4. package/dist/adapters/anthropic.js +139 -0
  5. package/dist/adapters/anthropic.js.map +1 -0
  6. package/dist/adapters/openai.d.ts +29 -0
  7. package/dist/adapters/openai.js +131 -0
  8. package/dist/adapters/openai.js.map +1 -0
  9. package/dist/adapters/vercel.d.ts +17 -0
  10. package/dist/adapters/vercel.js +137 -0
  11. package/dist/adapters/vercel.js.map +1 -0
  12. package/dist/checks-DvLD3892.js +656 -0
  13. package/dist/checks-DvLD3892.js.map +1 -0
  14. package/dist/client/index.d.ts +24 -0
  15. package/dist/client/index.js +3 -0
  16. package/dist/errors-DWshWx18.js +55 -0
  17. package/dist/errors-DWshWx18.js.map +1 -0
  18. package/dist/http-provider-Cb41NXd5.d.ts +22 -0
  19. package/dist/http-provider-Cx2ZcLRB.js +278 -0
  20. package/dist/http-provider-Cx2ZcLRB.js.map +1 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.js +3 -0
  23. package/dist/model-xJvGTfLB.d.ts +84 -0
  24. package/dist/server/index.d.ts +313 -0
  25. package/dist/server/index.js +355 -0
  26. package/dist/server/index.js.map +1 -0
  27. package/dist/shared-BuhccY6c.js +61 -0
  28. package/dist/shared-BuhccY6c.js.map +1 -0
  29. package/dist/testing/index.d.ts +277 -0
  30. package/dist/testing/index.js +2445 -0
  31. package/dist/testing/index.js.map +1 -0
  32. package/dist/wire-B6AF_UGT.js +132 -0
  33. package/dist/wire-B6AF_UGT.js.map +1 -0
  34. package/dist/wire-Cv7Fk-7n.d.ts +136 -0
  35. package/eval/MANIFEST.sha256 +23 -0
  36. package/eval/cases.json +287 -0
  37. package/eval/designs/newsletter.png +0 -0
  38. package/eval/designs/one-page.pdf +0 -0
  39. package/eval/designs/promo.png +0 -0
  40. package/eval/domain-mismatch.json +25 -0
  41. package/eval/empty.json +11 -0
  42. package/eval/images/banner.png +0 -0
  43. package/eval/images/chart.png +0 -0
  44. package/eval/images/divider.png +0 -0
  45. package/eval/images/probe.png +0 -0
  46. package/eval/images/product.png +0 -0
  47. package/eval/injection.json +13 -0
  48. package/eval/low-text.json +41 -0
  49. package/eval/promo.json +12 -0
  50. package/eval/sources/banner.html +16 -0
  51. package/eval/sources/chart.html +16 -0
  52. package/eval/sources/divider.html +16 -0
  53. package/eval/sources/newsletter.html +16 -0
  54. package/eval/sources/one-page.html +16 -0
  55. package/eval/sources/probe.html +16 -0
  56. package/eval/sources/product.html +16 -0
  57. package/eval/sources/promo.html +16 -0
  58. package/eval/welcome.json +12 -0
  59. package/package.json +99 -3
  60. package/prompts/alt-text.md +7 -0
  61. package/prompts/chat-attachments.md +1 -0
  62. package/prompts/chat.md +2 -0
  63. package/prompts/editing.md +10 -0
  64. package/prompts/fix-rules.json +9 -0
  65. package/prompts/fix.md +8 -0
  66. package/prompts/operations.md +127 -0
  67. package/prompts/rewrite-presets.json +8 -0
  68. package/prompts/rewrite.md +4 -0
  69. package/schema/template-content.schema.json +1884 -0
@@ -0,0 +1,278 @@
1
+ import { a as AI_ROUTES, l as aiRoutePath, o as AI_SESSION_HEADER, r as AI_GENERATE_FIELDS, s as AI_WIRE_HEADER } from "./wire-B6AF_UGT.js";
2
+ import { a as providerFailure, n as errorFromEvent, r as errorFromResponse, t as AI_TEMPLATE_CHANGED_MESSAGE } from "./errors-DWshWx18.js";
3
+ import { CollaborationConflict, SdkError } from "@templatical/types";
4
+ //#region src/client/sse.ts
5
+ const TYPES = /* @__PURE__ */ new Set([
6
+ "text",
7
+ "operations",
8
+ "applied",
9
+ "done",
10
+ "error"
11
+ ]);
12
+ function parse(data) {
13
+ try {
14
+ const event = JSON.parse(data);
15
+ return typeof event === "object" && event !== null && typeof event.type === "string" && TYPES.has(event.type) ? event : null;
16
+ } catch {
17
+ return null;
18
+ }
19
+ }
20
+ /**
21
+ * The wire's events from an SSE body: `data:` lines, joined per event and
22
+ * dispatched at a blank line or the end; comments (`: ping`), other fields,
23
+ * unparseable data and unknown types are skipped. Cancelling the generator
24
+ * cancels the body.
25
+ */
26
+ async function* readSse(body) {
27
+ const reader = body.getReader();
28
+ const decoder = new TextDecoder();
29
+ let buffer = "";
30
+ let data = [];
31
+ function* dispatch() {
32
+ if (data.length === 0) return;
33
+ const event = parse(data.join("\n"));
34
+ data = [];
35
+ if (event) yield event;
36
+ }
37
+ function* lines(text) {
38
+ for (const raw of text.split("\n")) {
39
+ const line = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
40
+ if (line === "") yield* dispatch();
41
+ else if (line.startsWith("data:")) data.push(line.slice(line.startsWith("data: ") ? 6 : 5));
42
+ }
43
+ }
44
+ try {
45
+ for (;;) {
46
+ const { done, value } = await reader.read();
47
+ if (done) break;
48
+ buffer += decoder.decode(value, { stream: true });
49
+ const end = buffer.lastIndexOf("\n");
50
+ if (end === -1) continue;
51
+ const complete = buffer.slice(0, end);
52
+ buffer = buffer.slice(end + 1);
53
+ yield* lines(complete);
54
+ }
55
+ buffer += decoder.decode();
56
+ if (buffer !== "") yield* lines(buffer);
57
+ yield* dispatch();
58
+ } finally {
59
+ reader.cancel().catch(() => {});
60
+ }
61
+ }
62
+ //#endregion
63
+ //#region src/client/http-provider.ts
64
+ function abortError(signal) {
65
+ const reason = signal.reason;
66
+ return reason instanceof Error && reason.name === "AbortError" ? reason : new DOMException("The AI request was stopped.", "AbortError");
67
+ }
68
+ function isRecord(value) {
69
+ return typeof value === "object" && value !== null && !Array.isArray(value);
70
+ }
71
+ /**
72
+ * An `AiProvider` over the wire (A1 §4): JSON or multipart requests, SSE
73
+ * answers for turns and rewrite, JSON for history.
74
+ * Errors are `SdkError`s; stopping a call rejects with an `AbortError`.
75
+ */
76
+ function createHttpAiProvider(options) {
77
+ return createHttpAiProviderWithFetch(options, (input, init) => fetch(input, init));
78
+ }
79
+ /** @internal A per-instance transport for wire conformance; not a package export. */
80
+ function createHttpAiProviderWithFetch(options, fetchRequest) {
81
+ const base = options.baseUrl.replace(/\/+$/, "");
82
+ const on = (feature) => options.features?.[feature] !== false;
83
+ async function request(route, params, init) {
84
+ init.signal?.throwIfAborted();
85
+ const own = typeof options.headers === "function" ? await options.headers() : options.headers ?? {};
86
+ const headers = new Headers(own);
87
+ headers.set(AI_WIRE_HEADER, "1");
88
+ headers.set("Accept", init.stream ? "text/event-stream" : "application/json");
89
+ if (init.session) headers.set(AI_SESSION_HEADER, init.session);
90
+ let body;
91
+ if (init.form) body = init.form;
92
+ else if (init.json !== void 0) {
93
+ headers.set("Content-Type", "application/json");
94
+ body = JSON.stringify(init.json);
95
+ }
96
+ let response;
97
+ try {
98
+ init.signal?.throwIfAborted();
99
+ response = await fetchRequest(`${base}${aiRoutePath(route, params)}`, {
100
+ method: AI_ROUTES[route].method,
101
+ headers,
102
+ body,
103
+ ...options.credentials ? { credentials: options.credentials } : {},
104
+ signal: init.signal
105
+ });
106
+ } catch (error) {
107
+ if (init.signal?.aborted) throw abortError(init.signal);
108
+ throw error instanceof SdkError ? error : providerFailure();
109
+ }
110
+ if (!response.ok) throw await errorFromResponse(response);
111
+ return response;
112
+ }
113
+ /**
114
+ * One streamed call. `each` handles every event before `done`; it may
115
+ * throw to end the call (a refusal, the editor's own error), which aborts
116
+ * the request.
117
+ */
118
+ async function streamed(route, template, init, signal, each, done) {
119
+ const controller = new AbortController();
120
+ const stop = () => controller.abort(signal.reason);
121
+ if (signal.aborted) stop();
122
+ signal.addEventListener("abort", stop, { once: true });
123
+ try {
124
+ const response = await request(route, { template }, {
125
+ ...init,
126
+ stream: true,
127
+ signal: controller.signal
128
+ });
129
+ if (!response.body) throw providerFailure();
130
+ for await (const event of readSse(response.body)) {
131
+ if (signal.aborted) {
132
+ if (event.type === "applied") await each(event);
133
+ if (event.type === "done" || event.type === "error") throw abortError(signal);
134
+ continue;
135
+ }
136
+ if (event.type === "error") throw errorFromEvent(event);
137
+ if (event.type === "done") {
138
+ const value = done(event);
139
+ if (value === void 0) throw providerFailure();
140
+ return value;
141
+ }
142
+ await each(event);
143
+ }
144
+ throw providerFailure();
145
+ } catch (error) {
146
+ if (signal.aborted) throw abortError(signal);
147
+ controller.abort();
148
+ if (error instanceof SdkError) throw error;
149
+ if (error instanceof Error && error.name === "AbortError") throw error;
150
+ if (error instanceof Error && !(error instanceof TypeError)) throw error;
151
+ throw providerFailure();
152
+ } finally {
153
+ signal.removeEventListener("abort", stop);
154
+ }
155
+ }
156
+ function turn(route, req, init, handlers, signal) {
157
+ let text = "";
158
+ return streamed(route, req.templateId, {
159
+ ...init,
160
+ session: req.sessionId
161
+ }, signal, async (event) => {
162
+ if (event.type === "text") {
163
+ text += event.text;
164
+ handlers.onText(event.text);
165
+ } else if (event.type === "operations") {
166
+ const result = await handlers.onOperations(event.ops);
167
+ if (!result.applied) throw new CollaborationConflict(AI_TEMPLATE_CHANGED_MESSAGE, {
168
+ code: result.code,
169
+ opIndex: result.opIndex
170
+ });
171
+ } else if (event.type === "applied") handlers.onApplied({
172
+ batchId: event.batchId,
173
+ revision: event.revision,
174
+ operationCount: event.operationCount
175
+ });
176
+ }, (done) => typeof done.messageId === "string" || done.messageId === null ? {
177
+ messageId: done.messageId,
178
+ text
179
+ } : void 0);
180
+ }
181
+ async function json(response) {
182
+ try {
183
+ return await response.json();
184
+ } catch {
185
+ throw providerFailure();
186
+ }
187
+ }
188
+ async function replay(route, templateId, messageId, sessionId) {
189
+ const body = await json(await request(route, {
190
+ template: templateId,
191
+ message: messageId
192
+ }, { session: sessionId }));
193
+ if (!isRecord(body)) throw providerFailure();
194
+ const data = body.data ?? {};
195
+ if (Array.isArray(data.operations) && typeof data.replayId === "string" && data.replayId !== "") return {
196
+ operations: data.operations,
197
+ replayId: data.replayId
198
+ };
199
+ if (typeof data.batchId === "string" && typeof data.revision === "number") return { applied: {
200
+ batchId: data.batchId,
201
+ revision: data.revision
202
+ } };
203
+ throw providerFailure();
204
+ }
205
+ return {
206
+ chatAttachments: on("chat") && on("chatAttachments"),
207
+ chat: on("chat") ? (req, handlers, signal) => {
208
+ const body = {
209
+ message: req.message,
210
+ selectedBlockId: req.selectedBlockId,
211
+ mergeTags: req.mergeTags,
212
+ content: req.content,
213
+ revision: req.revision
214
+ };
215
+ if (req.attachments.length === 0) return turn("generate", req, { json: body }, handlers, signal);
216
+ const form = new FormData();
217
+ form.set(AI_GENERATE_FIELDS.message, req.message);
218
+ if (req.selectedBlockId !== null) form.set(AI_GENERATE_FIELDS.selectedBlockId, req.selectedBlockId);
219
+ form.set(AI_GENERATE_FIELDS.mergeTags, JSON.stringify(req.mergeTags));
220
+ form.set(AI_GENERATE_FIELDS.content, JSON.stringify(req.content));
221
+ if (req.revision !== null) form.set(AI_GENERATE_FIELDS.revision, String(req.revision));
222
+ for (const attachment of req.attachments) form.append(AI_GENERATE_FIELDS.attachment, attachment.file, attachment.name);
223
+ return turn("generate", req, { form }, handlers, signal);
224
+ } : false,
225
+ fixFinding: on("fixFinding") ? (req, handlers, signal) => turn("fixFinding", req, { json: {
226
+ finding: req.finding,
227
+ mergeTags: req.mergeTags,
228
+ content: req.content,
229
+ revision: req.revision
230
+ } }, handlers, signal) : false,
231
+ rewrite: on("rewrite") ? (req, handlers, signal) => streamed("rewriteText", req.templateId, { json: {
232
+ html: req.html,
233
+ preset: req.preset,
234
+ language: req.language,
235
+ instruction: req.instruction,
236
+ mergeTags: req.mergeTags
237
+ } }, signal, (event) => {
238
+ if (event.type === "text") handlers.onText(event.text);
239
+ }, (done) => typeof done.html === "string" ? { html: done.html } : void 0) : false,
240
+ altText: on("altText") ? (req, signal) => {
241
+ const { templateId, sessionId, ...body } = req;
242
+ return streamed("altText", templateId, {
243
+ json: body,
244
+ session: sessionId
245
+ }, signal, () => {}, (done) => typeof done.alt === "string" ? { alt: done.alt } : void 0);
246
+ } : false,
247
+ ...on("conversation") ? { conversation: {
248
+ settleReplay: async (templateId, messageId, outcome) => {
249
+ await request("settleReplay", {
250
+ template: templateId,
251
+ message: messageId,
252
+ replayId: outcome.replayId
253
+ }, {
254
+ session: outcome.sessionId,
255
+ json: {
256
+ direction: outcome.direction,
257
+ applied: outcome.applied
258
+ }
259
+ });
260
+ },
261
+ list: async (templateId) => {
262
+ const body = await json(await request("conversationMessages", { template: templateId }, {}));
263
+ if (!isRecord(body)) throw providerFailure();
264
+ if (!Array.isArray(body.data)) throw providerFailure();
265
+ return body.data;
266
+ },
267
+ clear: async (templateId) => {
268
+ await request("clearConversation", { template: templateId }, {});
269
+ },
270
+ undo: (templateId, messageId, context) => replay("undoMessage", templateId, messageId, context.sessionId),
271
+ redo: (templateId, messageId, context) => replay("redoMessage", templateId, messageId, context.sessionId)
272
+ } } : {}
273
+ };
274
+ }
275
+ //#endregion
276
+ export { createHttpAiProviderWithFetch as n, readSse as r, createHttpAiProvider as t };
277
+
278
+ //# sourceMappingURL=http-provider-Cx2ZcLRB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-provider-Cx2ZcLRB.js","names":[],"sources":["../src/client/sse.ts","../src/client/http-provider.ts"],"sourcesContent":["import type { AiWireEvent } from \"../wire\";\n\nconst TYPES = new Set([\"text\", \"operations\", \"applied\", \"done\", \"error\"]);\n\nfunction parse(data: string): AiWireEvent | null {\n try {\n const event = JSON.parse(data) as { type?: unknown };\n return typeof event === \"object\" &&\n event !== null &&\n typeof event.type === \"string\" &&\n TYPES.has(event.type)\n ? (event as AiWireEvent)\n : null;\n } catch {\n return null;\n }\n}\n\n/**\n * The wire's events from an SSE body: `data:` lines, joined per event and\n * dispatched at a blank line or the end; comments (`: ping`), other fields,\n * unparseable data and unknown types are skipped. Cancelling the generator\n * cancels the body.\n */\nexport async function* readSse(\n body: ReadableStream<Uint8Array>,\n): AsyncGenerator<AiWireEvent> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let data: string[] = [];\n\n function* dispatch(): Generator<AiWireEvent> {\n if (data.length === 0) return;\n const event = parse(data.join(\"\\n\"));\n data = [];\n if (event) yield event;\n }\n\n function* lines(text: string): Generator<AiWireEvent> {\n for (const raw of text.split(\"\\n\")) {\n const line = raw.endsWith(\"\\r\") ? raw.slice(0, -1) : raw;\n if (line === \"\") {\n yield* dispatch();\n } else if (line.startsWith(\"data:\")) {\n data.push(line.slice(line.startsWith(\"data: \") ? 6 : 5));\n }\n }\n }\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const end = buffer.lastIndexOf(\"\\n\");\n if (end === -1) continue;\n const complete = buffer.slice(0, end);\n buffer = buffer.slice(end + 1);\n yield* lines(complete);\n }\n buffer += decoder.decode();\n if (buffer !== \"\") yield* lines(buffer);\n yield* dispatch();\n } finally {\n reader.cancel().catch(() => {});\n }\n}\n","import type {\n AiFeatureName,\n AiProvider,\n AiReplay,\n AiReplayOutcome,\n AiRequestBase,\n AiTurnHandlers,\n AiTurnResult,\n} from \"@templatical/types\";\nimport { CollaborationConflict, SdkError } from \"@templatical/types\";\nimport {\n AI_GENERATE_FIELDS,\n AI_ROUTES,\n AI_SESSION_HEADER,\n AI_WIRE_HEADER,\n AI_WIRE_VERSION,\n aiRoutePath,\n type AiDoneEvent,\n type AiRouteName,\n type AiWireEvent,\n} from \"../wire\";\nimport {\n AI_TEMPLATE_CHANGED_MESSAGE,\n errorFromEvent,\n errorFromResponse,\n providerFailure,\n} from \"./errors\";\nimport { readSse } from \"./sse\";\n\nexport type HttpAiFeatures = Partial<\n Record<AiFeatureName | \"conversation\", boolean>\n>;\n\nexport interface HttpAiProviderOptions {\n /** Where the wire's routes live: `{baseUrl}/templates/{t}/ai/…`. */\n baseUrl: string;\n /** Your auth headers, or a function (async for a token refresh) called per request. */\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n /** `fetch`'s `credentials`, for cookie auth. */\n credentials?: RequestCredentials;\n /** `false` turns a feature off, `conversation` included. Everything else is on. */\n features?: HttpAiFeatures;\n}\n\nfunction abortError(signal: AbortSignal): Error {\n const reason = signal.reason as unknown;\n return reason instanceof Error && reason.name === \"AbortError\"\n ? reason\n : new DOMException(\"The AI request was stopped.\", \"AbortError\");\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * An `AiProvider` over the wire (A1 §4): JSON or multipart requests, SSE\n * answers for turns and rewrite, JSON for history.\n * Errors are `SdkError`s; stopping a call rejects with an `AbortError`.\n */\nexport function createHttpAiProvider(\n options: HttpAiProviderOptions,\n): AiProvider {\n return createHttpAiProviderWithFetch(options, (input, init) =>\n fetch(input, init),\n );\n}\n\n/** @internal A per-instance transport for wire conformance; not a package export. */\nexport function createHttpAiProviderWithFetch(\n options: HttpAiProviderOptions,\n fetchRequest: typeof fetch,\n): AiProvider {\n const base = options.baseUrl.replace(/\\/+$/, \"\");\n const on = (feature: AiFeatureName | \"conversation\") =>\n options.features?.[feature] !== false;\n\n async function request(\n route: AiRouteName,\n params: { template: string; message?: string; replayId?: string },\n init: {\n json?: unknown;\n form?: FormData;\n session?: string;\n stream?: boolean;\n signal?: AbortSignal;\n },\n ): Promise<Response> {\n init.signal?.throwIfAborted();\n const own =\n typeof options.headers === \"function\"\n ? await options.headers()\n : (options.headers ?? {});\n const headers = new Headers(own);\n headers.set(AI_WIRE_HEADER, AI_WIRE_VERSION);\n headers.set(\n \"Accept\",\n init.stream ? \"text/event-stream\" : \"application/json\",\n );\n if (init.session) headers.set(AI_SESSION_HEADER, init.session);\n let body: BodyInit | undefined;\n if (init.form) {\n body = init.form;\n } else if (init.json !== undefined) {\n headers.set(\"Content-Type\", \"application/json\");\n body = JSON.stringify(init.json);\n }\n let response: Response;\n try {\n init.signal?.throwIfAborted();\n response = await fetchRequest(`${base}${aiRoutePath(route, params)}`, {\n method: AI_ROUTES[route].method,\n headers,\n body,\n ...(options.credentials ? { credentials: options.credentials } : {}),\n signal: init.signal,\n });\n } catch (error) {\n if (init.signal?.aborted) throw abortError(init.signal);\n throw error instanceof SdkError ? error : providerFailure();\n }\n if (!response.ok) throw await errorFromResponse(response);\n return response;\n }\n\n /**\n * One streamed call. `each` handles every event before `done`; it may\n * throw to end the call (a refusal, the editor's own error), which aborts\n * the request.\n */\n async function streamed<T>(\n route: AiRouteName,\n template: string,\n init: { json?: unknown; form?: FormData; session?: string },\n signal: AbortSignal,\n // Never called with `done` or `error`: those end the call first.\n each: (event: AiWireEvent) => Promise<void> | void,\n done: (event: AiDoneEvent) => T | undefined,\n ): Promise<T> {\n const controller = new AbortController();\n const stop = () => controller.abort(signal.reason);\n if (signal.aborted) stop();\n signal.addEventListener(\"abort\", stop, { once: true });\n try {\n const response = await request(\n route,\n { template },\n {\n ...init,\n stream: true,\n signal: controller.signal,\n },\n );\n if (!response.body) throw providerFailure();\n for await (const event of readSse(response.body)) {\n if (signal.aborted) {\n // Already received server edits still need reconciliation after Stop.\n if (event.type === \"applied\") await each(event);\n if (event.type === \"done\" || event.type === \"error\")\n throw abortError(signal);\n continue;\n }\n if (event.type === \"error\") throw errorFromEvent(event);\n if (event.type === \"done\") {\n const value = done(event);\n if (value === undefined) throw providerFailure();\n return value;\n }\n await each(event);\n }\n throw providerFailure();\n } catch (error) {\n if (signal.aborted) throw abortError(signal);\n controller.abort();\n if (error instanceof SdkError) throw error;\n if (error instanceof Error && error.name === \"AbortError\") throw error;\n if (error instanceof Error && !(error instanceof TypeError)) throw error;\n throw providerFailure();\n } finally {\n signal.removeEventListener(\"abort\", stop);\n }\n }\n\n function turn(\n route: \"generate\" | \"fixFinding\",\n req: AiRequestBase,\n init: { json?: unknown; form?: FormData },\n handlers: AiTurnHandlers,\n signal: AbortSignal,\n ): Promise<AiTurnResult> {\n let text = \"\";\n return streamed(\n route,\n req.templateId,\n { ...init, session: req.sessionId },\n signal,\n async (event) => {\n if (event.type === \"text\") {\n text += event.text;\n handlers.onText(event.text);\n } else if (event.type === \"operations\") {\n const result = await handlers.onOperations(event.ops);\n if (!result.applied) {\n // SSE is one-way: the backend can't be told mid-turn, so the\n // request ends here with the operation's own code (§4).\n throw new CollaborationConflict(AI_TEMPLATE_CHANGED_MESSAGE, {\n code: result.code,\n opIndex: result.opIndex,\n });\n }\n } else if (event.type === \"applied\") {\n handlers.onApplied({\n batchId: event.batchId,\n revision: event.revision,\n operationCount: event.operationCount,\n });\n }\n },\n (done) =>\n typeof done.messageId === \"string\" || done.messageId === null\n ? { messageId: done.messageId, text }\n : undefined,\n );\n }\n\n async function json<T>(response: Response): Promise<T> {\n try {\n return (await response.json()) as T;\n } catch {\n throw providerFailure();\n }\n }\n\n async function replay(\n route: \"undoMessage\" | \"redoMessage\",\n templateId: string,\n messageId: string,\n sessionId: string,\n ): Promise<AiReplay> {\n const response = await request(\n route,\n { template: templateId, message: messageId },\n { session: sessionId },\n );\n const body = await json<{\n data?: {\n operations?: unknown;\n replayId?: unknown;\n batchId?: unknown;\n revision?: unknown;\n };\n }>(response);\n if (!isRecord(body)) throw providerFailure();\n const data = body.data ?? {};\n if (\n Array.isArray(data.operations) &&\n typeof data.replayId === \"string\" &&\n data.replayId !== \"\"\n )\n return { operations: data.operations, replayId: data.replayId };\n if (typeof data.batchId === \"string\" && typeof data.revision === \"number\") {\n return { applied: { batchId: data.batchId, revision: data.revision } };\n }\n throw providerFailure();\n }\n\n return {\n chatAttachments: on(\"chat\") && on(\"chatAttachments\"),\n chat: on(\"chat\")\n ? (req, handlers, signal) => {\n const body = {\n message: req.message,\n selectedBlockId: req.selectedBlockId,\n mergeTags: req.mergeTags,\n content: req.content,\n revision: req.revision,\n };\n if (req.attachments.length === 0)\n return turn(\"generate\", req, { json: body }, handlers, signal);\n const form = new FormData();\n form.set(AI_GENERATE_FIELDS.message, req.message);\n if (req.selectedBlockId !== null)\n form.set(AI_GENERATE_FIELDS.selectedBlockId, req.selectedBlockId);\n form.set(AI_GENERATE_FIELDS.mergeTags, JSON.stringify(req.mergeTags));\n form.set(AI_GENERATE_FIELDS.content, JSON.stringify(req.content));\n if (req.revision !== null)\n form.set(AI_GENERATE_FIELDS.revision, String(req.revision));\n for (const attachment of req.attachments)\n form.append(\n AI_GENERATE_FIELDS.attachment,\n attachment.file,\n attachment.name,\n );\n return turn(\"generate\", req, { form }, handlers, signal);\n }\n : false,\n fixFinding: on(\"fixFinding\")\n ? (req, handlers, signal) =>\n turn(\n \"fixFinding\",\n req,\n {\n json: {\n finding: req.finding,\n mergeTags: req.mergeTags,\n content: req.content,\n revision: req.revision,\n },\n },\n handlers,\n signal,\n )\n : false,\n rewrite: on(\"rewrite\")\n ? (req, handlers, signal) =>\n streamed(\n \"rewriteText\",\n req.templateId,\n {\n json: {\n html: req.html,\n preset: req.preset,\n language: req.language,\n instruction: req.instruction,\n mergeTags: req.mergeTags,\n },\n },\n signal,\n (event) => {\n if (event.type === \"text\") handlers.onText(event.text);\n },\n (done) =>\n typeof done.html === \"string\" ? { html: done.html } : undefined,\n )\n : false,\n altText: on(\"altText\")\n ? (req, signal) => {\n const { templateId, sessionId, ...body } = req;\n return streamed(\n \"altText\",\n templateId,\n { json: body, session: sessionId },\n signal,\n () => {},\n (done) =>\n typeof done.alt === \"string\" ? { alt: done.alt } : undefined,\n );\n }\n : false,\n ...(on(\"conversation\")\n ? {\n conversation: {\n settleReplay: async (\n templateId: string,\n messageId: string,\n outcome: AiReplayOutcome,\n ) => {\n await request(\n \"settleReplay\",\n {\n template: templateId,\n message: messageId,\n replayId: outcome.replayId,\n },\n {\n session: outcome.sessionId,\n json: {\n direction: outcome.direction,\n applied: outcome.applied,\n },\n },\n );\n },\n list: async (templateId: string) => {\n const response = await request(\n \"conversationMessages\",\n { template: templateId },\n {},\n );\n const body = await json<{ data?: unknown }>(response);\n if (!isRecord(body)) throw providerFailure();\n if (!Array.isArray(body.data)) throw providerFailure();\n return body.data;\n },\n clear: async (templateId: string) => {\n await request(\"clearConversation\", { template: templateId }, {});\n },\n undo: (\n templateId: string,\n messageId: string,\n context: { sessionId: string },\n ) =>\n replay(\"undoMessage\", templateId, messageId, context.sessionId),\n redo: (\n templateId: string,\n messageId: string,\n context: { sessionId: string },\n ) =>\n replay(\"redoMessage\", templateId, messageId, context.sessionId),\n },\n }\n : {}),\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { C as AiWireEvent, S as AiTextEvent, T as matchAiRoute, _ as AiReplayResponse, a as AI_ROUTES, b as AiRouteMatch, c as AI_WIRE_VERSION, d as AiConversationResponse, f as AiDoneEvent, g as AiOperationsEvent, h as AiGenerateBody, i as AI_LIMITS, l as AiAltTextBody, m as AiFixFindingBody, n as AI_ERROR_STATUS, o as AI_SESSION_HEADER, p as AiErrorEvent, r as AI_GENERATE_FIELDS, s as AI_WIRE_HEADER, t as AI_ERROR_MESSAGES, u as AiAppliedEvent, v as AiRewriteBody, w as aiRoutePath, x as AiRouteName, y as AiRoute } from "./wire-Cv7Fk-7n.js";
2
+ import { AiAltTextRequest, AiAppliedBatch, AiChatAttachment, AiChatMessage, AiChatRequest, AiConversationProvider, AiErrorCode, AiFeatureName, AiFixFinding, AiFixRequest, AiLimitDetails, AiMergeTag, AiMergeTagSyntax, AiMergeTags, AiMessageBatch, AiMessageKind, AiOperationsResult, AiProvider, AiReplay, AiReplayContext, AiReplayOutcome, AiRequestBase, AiRewriteHandlers, AiRewritePreset, AiRewriteRequest, AiTurnHandlers, AiTurnResult, CollaborationConflict, Operation, SdkError, TemplateContent, ThrottledError } from "@templatical/types";
3
+ export { AI_ERROR_MESSAGES, AI_ERROR_STATUS, AI_GENERATE_FIELDS, AI_LIMITS, AI_ROUTES, AI_SESSION_HEADER, AI_WIRE_HEADER, AI_WIRE_VERSION, AiAltTextBody, type AiAltTextRequest, type AiAppliedBatch, AiAppliedEvent, type AiChatAttachment, type AiChatMessage, type AiChatRequest, type AiConversationProvider, AiConversationResponse, AiDoneEvent, type AiErrorCode, AiErrorEvent, type AiFeatureName, type AiFixFinding, AiFixFindingBody, type AiFixRequest, AiGenerateBody, type AiLimitDetails, type AiMergeTag, type AiMergeTagSyntax, type AiMergeTags, type AiMessageBatch, type AiMessageKind, AiOperationsEvent, type AiOperationsResult, type AiProvider, type AiReplay, type AiReplayContext, type AiReplayOutcome, AiReplayResponse, type AiRequestBase, AiRewriteBody, type AiRewriteHandlers, type AiRewritePreset, type AiRewriteRequest, AiRoute, AiRouteMatch, AiRouteName, AiTextEvent, type AiTurnHandlers, type AiTurnResult, AiWireEvent, CollaborationConflict, type Operation, SdkError, type TemplateContent, ThrottledError, aiRoutePath, matchAiRoute };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { a as AI_ROUTES, c as AI_WIRE_VERSION, i as AI_LIMITS, l as aiRoutePath, n as AI_ERROR_STATUS, o as AI_SESSION_HEADER, r as AI_GENERATE_FIELDS, s as AI_WIRE_HEADER, t as AI_ERROR_MESSAGES, u as matchAiRoute } from "./wire-B6AF_UGT.js";
2
+ import { CollaborationConflict, SdkError, ThrottledError } from "@templatical/types";
3
+ export { AI_ERROR_MESSAGES, AI_ERROR_STATUS, AI_GENERATE_FIELDS, AI_LIMITS, AI_ROUTES, AI_SESSION_HEADER, AI_WIRE_HEADER, AI_WIRE_VERSION, CollaborationConflict, SdkError, ThrottledError, aiRoutePath, matchAiRoute };
@@ -0,0 +1,84 @@
1
+ //#region src/server/tool.d.ts
2
+ /** A tool in neutral JSON-schema form; adapters map it to their SDK's shape. */
3
+ interface AiToolDefinition {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: Record<string, unknown>;
7
+ }
8
+ /**
9
+ * The editing turns' one tool (S7 A4). `ops` is a JSON **string**: several
10
+ * SDKs turn tool arguments into maps that lose `{}` (S7 D8), and a string
11
+ * survives every one of them.
12
+ */
13
+ declare const applyOperationsTool: AiToolDefinition;
14
+ //#endregion
15
+ //#region src/server/model.d.ts
16
+ /** A design file or an image URL attached to a user message. */
17
+ type AiModelAttachment = {
18
+ kind: "image" | "pdf";
19
+ mediaType: string;
20
+ data: Blob;
21
+ } | {
22
+ kind: "image-url";
23
+ url: string;
24
+ };
25
+ interface AiModelToolCall {
26
+ id: string;
27
+ name: string;
28
+ /** The tool's arguments: a JSON string of the arguments object, or the object. */
29
+ input: string | Record<string, unknown>;
30
+ }
31
+ type AiModelMessage = {
32
+ role: "user";
33
+ content: string;
34
+ attachments?: AiModelAttachment[];
35
+ } | {
36
+ role: "assistant";
37
+ content: string;
38
+ toolCalls?: AiModelToolCall[];
39
+ /** What the adapter yielded as `state` for this step; it replays its own. */
40
+ state?: unknown;
41
+ } | {
42
+ role: "tool";
43
+ toolCallId: string;
44
+ name: string;
45
+ content: string;
46
+ };
47
+ interface AiUsage {
48
+ /** Input tokens billed at the full rate: not read from or written to a cache. */
49
+ inputTokens: number;
50
+ outputTokens: number;
51
+ /** Input tokens read from the provider's prompt cache, when it reports them. */
52
+ cacheReadInputTokens?: number;
53
+ /** Input tokens written to the provider's prompt cache, when it reports them. */
54
+ cacheWriteInputTokens?: number;
55
+ }
56
+ type AiModelPart = {
57
+ type: "text";
58
+ text: string;
59
+ } | ({
60
+ type: "tool-call";
61
+ } & AiModelToolCall) |
62
+ /** Opaque to the kit: the adapter's own record of the step (e.g. thinking), JSON-safe. */
63
+ {
64
+ type: "state";
65
+ state: unknown;
66
+ } | ({
67
+ type: "usage";
68
+ } & AiUsage);
69
+ /**
70
+ * Your model, behind one method: stream a reply to `messages` with `system` as
71
+ * the system prompt and `tools` offered. `@templatical/ai-kit/adapters/*`
72
+ * implements it for Anthropic, OpenAI and the Vercel AI SDK. Honour `signal`.
73
+ */
74
+ interface AiModelAdapter {
75
+ stream(input: {
76
+ system: string;
77
+ messages: AiModelMessage[];
78
+ tools: AiToolDefinition[];
79
+ signal?: AbortSignal;
80
+ }): AsyncIterable<AiModelPart>;
81
+ }
82
+ //#endregion
83
+ export { AiModelToolCall as a, applyOperationsTool as c, AiModelPart as i, AiModelAttachment as n, AiUsage as o, AiModelMessage as r, AiToolDefinition as s, AiModelAdapter as t };
84
+ //# sourceMappingURL=model-xJvGTfLB.d.ts.map