content-agent 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,106 @@
1
+ import { b as OutputFormat } from "./_chunks-dts/types.js";
2
+ import { UIMessage } from "ai";
3
+ import { Application, Context } from "@sanity/agent-types";
4
+ /**
5
+ * Wire shape the Content Agent chat route expects: `{role, content}` where
6
+ * content is a flattened string for text-only turns, or the raw typed parts
7
+ * (tool calls / results) otherwise.
8
+ *
9
+ * @category Messages
10
+ */
11
+ interface WireMessage {
12
+ id: string;
13
+ role: UIMessage['role'];
14
+ content: string | Array<Record<string, unknown>>;
15
+ }
16
+ /**
17
+ * Convert an AI SDK `UIMessage` into the Content Agent wire shape. Text-only
18
+ * messages collapse to a single string; anything with tool parts passes the
19
+ * parts array through.
20
+ *
21
+ * @category Messages
22
+ */
23
+ declare function toWireMessage(message: UIMessage): WireMessage;
24
+ /**
25
+ * Join a message's `text` parts into a single string. Separate text parts are
26
+ * delimited with a blank line so an inline directive followed by prose stays
27
+ * parseable.
28
+ *
29
+ * @category Messages
30
+ */
31
+ declare function uiMessageToText(message: UIMessage): string;
32
+ /**
33
+ * Concatenate the agent's reasoning summary from `data-agent-status` stream
34
+ * parts. Returns `undefined` when the message carries no reasoning.
35
+ *
36
+ * @category Messages
37
+ */
38
+ declare function getReasoningText(message: UIMessage): string | undefined;
39
+ /**
40
+ * A persisted thread turn loaded from `GET /threads/:id`, ready to seed into
41
+ * `chat.messages`.
42
+ *
43
+ * @category Messages
44
+ */
45
+ interface HistoryMessage {
46
+ id: string;
47
+ role: 'user' | 'assistant';
48
+ content: string;
49
+ metadata?: unknown;
50
+ }
51
+ /**
52
+ * Convert persisted thread history into `UIMessage`s for seeding. The directive
53
+ * text is kept as a single text part so {@link uiMessageToText} round-trips it.
54
+ *
55
+ * @category Messages
56
+ */
57
+ declare function historyToUiMessages(messages: HistoryMessage[]): UIMessage[];
58
+ /**
59
+ * Merge persisted history (`seed`, ordered) with the live SDK messages.
60
+ *
61
+ * History and a resumed stream are complementary: after a reload mid-stream the
62
+ * resumed stream carries the assistant turn while only history has the user
63
+ * message. Merging by id keeps both. History order is preserved; for ids in
64
+ * both, the live object is kept (so the SDK keeps writing to the same message
65
+ * reference); live-only messages are appended.
66
+ *
67
+ * @category Messages
68
+ */
69
+ declare function mergeMessagesById<UI_MESSAGE extends UIMessage>(seed: UI_MESSAGE[], live: UI_MESSAGE[]): UI_MESSAGE[];
70
+ /**
71
+ * Options for {@link buildSendBody}.
72
+ *
73
+ * @category Messages
74
+ */
75
+ interface BuildSendBodyOptions {
76
+ /** The conversation messages from `useChat`; only the last is sent. */
77
+ messages: UIMessage[];
78
+ /** Base body the SDK already assembled (id, trigger, etc.) to spread. */
79
+ body?: Record<string, unknown>;
80
+ application?: Application;
81
+ context?: Context;
82
+ format?: OutputFormat;
83
+ clientId?: string;
84
+ /** Defaults to `true` — the route streams over SSE. */
85
+ stream?: boolean;
86
+ }
87
+ /**
88
+ * Build the Content Agent chat request body for `prepareSendMessagesRequest`.
89
+ *
90
+ * Sends only the last turn (the backend persists history and appends it),
91
+ * wire-shaped via {@link toWireMessage}, plus the routing fields the route
92
+ * understands. Empty `context` is omitted so it isn't sent as noise.
93
+ *
94
+ * @category Messages
95
+ */
96
+ declare function buildSendBody({
97
+ messages,
98
+ body,
99
+ application,
100
+ context,
101
+ format,
102
+ clientId,
103
+ stream
104
+ }: BuildSendBodyOptions): Record<string, unknown>;
105
+ export { type BuildSendBodyOptions, type HistoryMessage, type WireMessage, buildSendBody, getReasoningText, historyToUiMessages, mergeMessagesById, toWireMessage, uiMessageToText };
106
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","names":[],"sources":["../src/_internal/messages.ts"],"mappings":";;;;AAWA;;;;;;UAAiB,WAAA;EACf,EAAA;EACA,IAAA,EAAM,SAAA;EACN,OAAA,WAAkB,KAAA,CAAM,MAAA;AAAA;;;;;;AAU1B;;iBAAgB,aAAA,CAAc,OAAA,EAAS,SAAA,GAAY,WAAA;;;;;;;AA0BnD;iBAAgB,eAAA,CAAgB,OAAA,EAAS,SAAA;;;;AAkBzC;;;iBAAgB,gBAAA,CAAiB,OAAA,EAAS,SAAA;;AAiB1C;;;;;UAAiB,cAAA;EACf,EAAA;EACA,IAAA;EACA,OAAA;EACA,QAAA;AAAA;;;;;;;iBASc,mBAAA,CAAoB,QAAA,EAAU,cAAA,KAAmB,SAAA;;AAoBjE;;;;;;;;;;iBAAgB,iBAAA,oBAAqC,SAAA,CAAA,CACnD,IAAA,EAAM,UAAA,IACN,IAAA,EAAM,UAAA,KACL,UAAA;;;;;;UAsBc,oBAAA;EAtBJ;EAwBX,QAAA,EAAU,SAAA;EAFyB;EAInC,IAAA,GAAO,MAAA;EACP,WAAA,GAAc,WAAA;EACd,OAAA,GAAU,OAAA;EACV,MAAA,GAAS,YAAA;EACT,QAAA;EADS;EAGT,MAAA;AAAA;;;;;;;;;;iBAYc,aAAA,CAAA;EACd,QAAA;EACA,IAAA;EACA,WAAA;EACA,OAAA;EACA,MAAA;EACA,QAAA;EACA;AAAA,GACC,oBAAA,GAAuB,MAAA"}
@@ -0,0 +1,79 @@
1
+ function toWireMessage(message) {
2
+ const parts = message.parts ?? [];
3
+ if (!parts.some((p) => p.type !== "text")) {
4
+ const text = parts.filter((p) => p.type === "text").map((p) => p.text).join("");
5
+ return { id: message.id, role: message.role, content: text };
6
+ }
7
+ return {
8
+ id: message.id,
9
+ role: message.role,
10
+ content: parts
11
+ };
12
+ }
13
+ function uiMessageToText(message) {
14
+ const parts = message.parts ?? [];
15
+ let out = "";
16
+ for (const part of parts)
17
+ part.type === "text" && typeof part.text == "string" && (out.length > 0 && !/\s$/.test(out) && !/^\s/.test(part.text) && (out += `
18
+
19
+ `), out += part.text);
20
+ return out;
21
+ }
22
+ function getReasoningText(message) {
23
+ const parts = message.parts ?? [];
24
+ let out = "";
25
+ for (const part of parts) {
26
+ if (part.type !== "data-agent-status") continue;
27
+ const text = part.data?.text;
28
+ typeof text == "string" && (out += text);
29
+ }
30
+ return out === "" ? void 0 : out;
31
+ }
32
+ function historyToUiMessages(messages) {
33
+ return messages.map((message) => ({
34
+ id: message.id,
35
+ role: message.role,
36
+ parts: message.content ? [{ type: "text", text: message.content }] : [],
37
+ ...message.metadata !== void 0 && { metadata: message.metadata }
38
+ }));
39
+ }
40
+ function mergeMessagesById(seed, live) {
41
+ if (live.length === 0) return seed;
42
+ const liveById = new Map(live.map((message) => [message.id, message])), seen = /* @__PURE__ */ new Set(), merged = [];
43
+ for (const message of seed)
44
+ merged.push(liveById.get(message.id) ?? message), seen.add(message.id);
45
+ for (const message of live)
46
+ seen.has(message.id) || merged.push(message);
47
+ return merged;
48
+ }
49
+ function buildSendBody({
50
+ messages,
51
+ body,
52
+ application,
53
+ context,
54
+ format,
55
+ clientId,
56
+ stream = !0
57
+ }) {
58
+ return {
59
+ ...body,
60
+ messages: messages.slice(-1).map(toWireMessage),
61
+ ...application && { application },
62
+ ...context && hasContext(context) && { context },
63
+ ...format && { format },
64
+ ...clientId && { clientId },
65
+ stream
66
+ };
67
+ }
68
+ function hasContext(context) {
69
+ return Object.values(context).some((value) => value != null);
70
+ }
71
+ export {
72
+ buildSendBody,
73
+ getReasoningText,
74
+ historyToUiMessages,
75
+ mergeMessagesById,
76
+ toWireMessage,
77
+ uiMessageToText
78
+ };
79
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sources":["../src/_internal/messages.ts"],"sourcesContent":["import type { Application, Context } from '@sanity/agent-types'\nimport type { UIMessage } from 'ai'\nimport type { OutputFormat } from '../types'\n\n/**\n * Wire shape the Content Agent chat route expects: `{role, content}` where\n * content is a flattened string for text-only turns, or the raw typed parts\n * (tool calls / results) otherwise.\n *\n * @category Messages\n */\nexport interface WireMessage {\n id: string\n role: UIMessage['role']\n content: string | Array<Record<string, unknown>>\n}\n\n/**\n * Convert an AI SDK `UIMessage` into the Content Agent wire shape. Text-only\n * messages collapse to a single string; anything with tool parts passes the\n * parts array through.\n *\n * @category Messages\n */\nexport function toWireMessage(message: UIMessage): WireMessage {\n const parts = message.parts ?? []\n const hasNonText = parts.some((p) => p.type !== 'text')\n\n if (!hasNonText) {\n const text = parts\n .filter((p): p is Extract<UIMessage['parts'][number], { type: 'text' }> => p.type === 'text')\n .map((p) => p.text)\n .join('')\n return { id: message.id, role: message.role, content: text }\n }\n\n return {\n id: message.id,\n role: message.role,\n content: parts as Array<Record<string, unknown>>,\n }\n}\n\n/**\n * Join a message's `text` parts into a single string. Separate text parts are\n * delimited with a blank line so an inline directive followed by prose stays\n * parseable.\n *\n * @category Messages\n */\nexport function uiMessageToText(message: UIMessage): string {\n const parts = message.parts ?? []\n let out = ''\n for (const part of parts) {\n if (part.type === 'text' && typeof part.text === 'string') {\n if (out.length > 0 && !/\\s$/.test(out) && !/^\\s/.test(part.text)) out += '\\n\\n'\n out += part.text\n }\n }\n return out\n}\n\n/**\n * Concatenate the agent's reasoning summary from `data-agent-status` stream\n * parts. Returns `undefined` when the message carries no reasoning.\n *\n * @category Messages\n */\nexport function getReasoningText(message: UIMessage): string | undefined {\n const parts = message.parts ?? []\n let out = ''\n for (const part of parts) {\n if (part.type !== 'data-agent-status') continue\n const text = (part as { data?: { text?: unknown } }).data?.text\n if (typeof text === 'string') out += text\n }\n return out === '' ? undefined : out\n}\n\n/**\n * A persisted thread turn loaded from `GET /threads/:id`, ready to seed into\n * `chat.messages`.\n *\n * @category Messages\n */\nexport interface HistoryMessage {\n id: string\n role: 'user' | 'assistant'\n content: string\n metadata?: unknown\n}\n\n/**\n * Convert persisted thread history into `UIMessage`s for seeding. The directive\n * text is kept as a single text part so {@link uiMessageToText} round-trips it.\n *\n * @category Messages\n */\nexport function historyToUiMessages(messages: HistoryMessage[]): UIMessage[] {\n return messages.map((message) => ({\n id: message.id,\n role: message.role,\n parts: message.content ? [{ type: 'text', text: message.content }] : [],\n ...(message.metadata !== undefined && { metadata: message.metadata }),\n }))\n}\n\n/**\n * Merge persisted history (`seed`, ordered) with the live SDK messages.\n *\n * History and a resumed stream are complementary: after a reload mid-stream the\n * resumed stream carries the assistant turn while only history has the user\n * message. Merging by id keeps both. History order is preserved; for ids in\n * both, the live object is kept (so the SDK keeps writing to the same message\n * reference); live-only messages are appended.\n *\n * @category Messages\n */\nexport function mergeMessagesById<UI_MESSAGE extends UIMessage>(\n seed: UI_MESSAGE[],\n live: UI_MESSAGE[],\n): UI_MESSAGE[] {\n if (live.length === 0) return seed\n\n const liveById = new Map(live.map((message) => [message.id, message]))\n const seen = new Set<string>()\n const merged: UI_MESSAGE[] = []\n\n for (const message of seed) {\n merged.push(liveById.get(message.id) ?? message)\n seen.add(message.id)\n }\n for (const message of live) {\n if (!seen.has(message.id)) merged.push(message)\n }\n return merged\n}\n\n/**\n * Options for {@link buildSendBody}.\n *\n * @category Messages\n */\nexport interface BuildSendBodyOptions {\n /** The conversation messages from `useChat`; only the last is sent. */\n messages: UIMessage[]\n /** Base body the SDK already assembled (id, trigger, etc.) to spread. */\n body?: Record<string, unknown>\n application?: Application\n context?: Context\n format?: OutputFormat\n clientId?: string\n /** Defaults to `true` — the route streams over SSE. */\n stream?: boolean\n}\n\n/**\n * Build the Content Agent chat request body for `prepareSendMessagesRequest`.\n *\n * Sends only the last turn (the backend persists history and appends it),\n * wire-shaped via {@link toWireMessage}, plus the routing fields the route\n * understands. Empty `context` is omitted so it isn't sent as noise.\n *\n * @category Messages\n */\nexport function buildSendBody({\n messages,\n body,\n application,\n context,\n format,\n clientId,\n stream = true,\n}: BuildSendBodyOptions): Record<string, unknown> {\n return {\n ...body,\n messages: messages.slice(-1).map(toWireMessage),\n ...(application && { application }),\n ...(context && hasContext(context) && { context }),\n ...(format && { format }),\n ...(clientId && { clientId }),\n stream,\n }\n}\n\nfunction hasContext(context: Context): boolean {\n return Object.values(context).some((value) => value !== undefined && value !== null)\n}\n"],"names":[],"mappings":"AAwBO,SAAS,cAAc,SAAiC;AAC7D,QAAM,QAAQ,QAAQ,SAAS,CAAA;AAG/B,MAAI,CAFe,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,GAErC;AACf,UAAM,OAAO,MACV,OAAO,CAAC,MAAkE,EAAE,SAAS,MAAM,EAC3F,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,EAAE;AACV,WAAO,EAAE,IAAI,QAAQ,IAAI,MAAM,QAAQ,MAAM,SAAS,KAAA;AAAA,EACxD;AAEA,SAAO;AAAA,IACL,IAAI,QAAQ;AAAA,IACZ,MAAM,QAAQ;AAAA,IACd,SAAS;AAAA,EAAA;AAEb;AASO,SAAS,gBAAgB,SAA4B;AAC1D,QAAM,QAAQ,QAAQ,SAAS,CAAA;AAC/B,MAAI,MAAM;AACV,aAAW,QAAQ;AACb,SAAK,SAAS,UAAU,OAAO,KAAK,QAAS,aAC3C,IAAI,SAAS,KAAK,CAAC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,KAAK,KAAK,IAAI,MAAG,OAAO;AAAA;AAAA,IACzE,OAAO,KAAK;AAGhB,SAAO;AACT;AAQO,SAAS,iBAAiB,SAAwC;AACvE,QAAM,QAAQ,QAAQ,SAAS,CAAA;AAC/B,MAAI,MAAM;AACV,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,oBAAqB;AACvC,UAAM,OAAQ,KAAuC,MAAM;AACvD,WAAO,QAAS,aAAU,OAAO;AAAA,EACvC;AACA,SAAO,QAAQ,KAAK,SAAY;AAClC;AAqBO,SAAS,oBAAoB,UAAyC;AAC3E,SAAO,SAAS,IAAI,CAAC,aAAa;AAAA,IAChC,IAAI,QAAQ;AAAA,IACZ,MAAM,QAAQ;AAAA,IACd,OAAO,QAAQ,UAAU,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,QAAA,CAAS,IAAI,CAAA;AAAA,IACrE,GAAI,QAAQ,aAAa,UAAa,EAAE,UAAU,QAAQ,SAAA;AAAA,EAAS,EACnE;AACJ;AAaO,SAAS,kBACd,MACA,MACc;AACd,MAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,QAAM,WAAW,IAAI,IAAI,KAAK,IAAI,CAAC,YAAY,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC,GAC/D,2BAAW,IAAA,GACX,SAAuB,CAAA;AAE7B,aAAW,WAAW;AACpB,WAAO,KAAK,SAAS,IAAI,QAAQ,EAAE,KAAK,OAAO,GAC/C,KAAK,IAAI,QAAQ,EAAE;AAErB,aAAW,WAAW;AACf,SAAK,IAAI,QAAQ,EAAE,KAAG,OAAO,KAAK,OAAO;AAEhD,SAAO;AACT;AA6BO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AACX,GAAkD;AAChD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAU,SAAS,MAAM,EAAE,EAAE,IAAI,aAAa;AAAA,IAC9C,GAAI,eAAe,EAAE,YAAA;AAAA,IACrB,GAAI,WAAW,WAAW,OAAO,KAAK,EAAE,QAAA;AAAA,IACxC,GAAI,UAAU,EAAE,OAAA;AAAA,IAChB,GAAI,YAAY,EAAE,SAAA;AAAA,IAClB;AAAA,EAAA;AAEJ;AAEA,SAAS,WAAW,SAA2B;AAC7C,SAAO,OAAO,OAAO,OAAO,EAAE,KAAK,CAAC,UAAiC,SAAU,IAAI;AACrF;"}
@@ -0,0 +1,114 @@
1
+ import { b as OutputFormat } from "./_chunks-dts/types.js";
2
+ import { UIMessage } from "ai";
3
+ import { Application, Context } from "@sanity/agent-types";
4
+ import { UseChatHelpers, UseChatOptions } from "@ai-sdk/react";
5
+ /** A value, or a getter resolved at send time (avoids stale closures). */
6
+ type Resolvable<T> = T | (() => T | undefined);
7
+ /** `useChat` options that {@link useContentAgentChat} owns; the rest pass through. */
8
+ type ManagedChatOptions = 'id' | 'transport' | 'resume' | 'messages' | 'onError' | 'onFinish' | 'onData';
9
+ /**
10
+ * Options for {@link useContentAgentChat}.
11
+ *
12
+ * @category React
13
+ */
14
+ interface UseContentAgentChatOptions<UI_MESSAGE extends UIMessage = UIMessage> {
15
+ /** Sanity organization ID. When undefined, no transport is built. */
16
+ organizationId: string | undefined;
17
+ /** Stable thread id. When undefined, no transport is built. */
18
+ threadId: string | undefined;
19
+ /**
20
+ * Base URL for the Sanity API.
21
+ * @default 'https://api.sanity.io'
22
+ */
23
+ baseURL?: string;
24
+ /** API version segment, e.g. `'v2026-01-12'`. */
25
+ apiVersion?: string;
26
+ /** Bearer token, or a getter read at request time. */
27
+ token?: string | (() => string | undefined);
28
+ /** Target application; pass a getter to read it fresh on each turn. */
29
+ application?: Resolvable<Application>;
30
+ /** Per-turn request context; pass a getter to read it fresh on each turn. */
31
+ context?: Resolvable<Context>;
32
+ /** Directive output format (`'directives'` for custom client rendering). */
33
+ format?: OutputFormat;
34
+ /** Identifies the creating client (e.g. `'dashboard'`). */
35
+ clientId?: string;
36
+ /**
37
+ * When true, reconnect to an in-flight stream once per thread (page reload).
38
+ * The SDK's `resume: true` only fires on first mount, so this hook drives
39
+ * resume per (Chat x threadId) pair instead.
40
+ */
41
+ autoResume?: boolean;
42
+ /** Initial messages for a thread's first mount (e.g. server-rendered history). */
43
+ messages?: UI_MESSAGE[];
44
+ onError?: (error: Error) => void;
45
+ onFinish?: () => void;
46
+ onData?: (dataPart: {
47
+ type: string;
48
+ data: unknown;
49
+ }) => void;
50
+ /**
51
+ * Any other `useChat`/`Chat` options to forward (e.g. `onToolCall`,
52
+ * `generateId`, `sendAutomaticallyWhen`). The options this hook manages
53
+ * (transport, id, messages, the callbacks above) take precedence. These are
54
+ * read once when a thread's Chat is created.
55
+ */
56
+ chatOptions?: Omit<UseChatOptions<UI_MESSAGE>, ManagedChatOptions>;
57
+ }
58
+ /**
59
+ * Options for {@link useSanityChatResume}.
60
+ *
61
+ * @category React
62
+ */
63
+ interface UseSanityChatResumeOptions {
64
+ /**
65
+ * When true, reconnect to an in-flight stream once per thread. The SDK's
66
+ * `resume: true` only fires on first mount, so this drives resume per
67
+ * (Chat x threadId) pair instead.
68
+ */
69
+ autoResume?: boolean;
70
+ }
71
+ /**
72
+ * Reconnect to an in-flight stream once per (Chat x threadId), when idle.
73
+ *
74
+ * Does not stop the stream on thread change or unmount: per the AI SDK
75
+ * resumable-stream model, client-side aborts are disconnects that should stay
76
+ * resumable, not cancellations. Stopping is an explicit user action (call
77
+ * `chat.stop()` and/or a server stop endpoint), never route or unmount
78
+ * cleanup. See https://ai-sdk.dev/docs/troubleshooting/abort-breaks-resumable-streams.
79
+ *
80
+ * @category React
81
+ *
82
+ * @example
83
+ * ```tsx
84
+ * const chat = useChat({ chat: myThreadChat })
85
+ * useSanityChatResume(chat, { autoResume: threadExistsOnBackend })
86
+ * ```
87
+ */
88
+ declare function useSanityChatResume<UI_MESSAGE extends UIMessage>(chat: Pick<UseChatHelpers<UI_MESSAGE>, 'id' | 'status' | 'resumeStream'>, options?: UseSanityChatResumeOptions): void;
89
+ /**
90
+ * `useChat` wired to the Sanity Content Agent: bearer auth, per-turn body
91
+ * shaping (application/context/format/clientId), `x-request-id` idempotency,
92
+ * and resume on reload.
93
+ *
94
+ * Holds one `Chat` instance per thread (the AI SDK's recommended pattern for
95
+ * multiple conversations), so switching threads mid-stream and back keeps the
96
+ * thread's messages and its still-running stream instead of rebuilding an empty
97
+ * Chat. Returns the standard `useChat` helpers.
98
+ *
99
+ * @category React
100
+ *
101
+ * @example
102
+ * ```tsx
103
+ * const chat = useContentAgentChat({
104
+ * organizationId,
105
+ * threadId,
106
+ * token: () => client.config().token,
107
+ * application,
108
+ * autoResume: threadExistsOnBackend,
109
+ * })
110
+ * ```
111
+ */
112
+ declare function useContentAgentChat<UI_MESSAGE extends UIMessage = UIMessage>(options: UseContentAgentChatOptions<UI_MESSAGE>): UseChatHelpers<UI_MESSAGE>;
113
+ export { UseContentAgentChatOptions, UseSanityChatResumeOptions, useContentAgentChat, useSanityChatResume };
114
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","names":[],"sources":["../src/_internal/create-thread-chat.ts","../src/react.ts"],"mappings":";;;;AASA;AAAA,KAAY,UAAA,MAAgB,CAAA,UAAW,CAAA;;KAG3B,kBAAA;AAHZ;;;;;AAAA,UCSiB,0BAAA,oBAA8C,SAAA,GAAY,SAAA;EDTpC;ECWrC,cAAA;EDXsC;ECatC,QAAA;EDV4B;;;;ECe5B,OAAA;EATe;EAWf,UAAA;EAXyC;EAazC,KAAA;EAbyE;EAezE,WAAA,GAAc,UAAA,CAAW,WAAA;EAAX;EAEd,OAAA,GAAU,UAAA,CAAW,OAAA;EAAX;EAEV,MAAA,GAAS,YAAA;EAUE;EARX,QAAA;EAkBkC;;;;;EAZlC,UAAA;EA3B0C;EA6B1C,QAAA,GAAW,UAAA;EACX,OAAA,IAAW,KAAA,EAAO,KAAA;EAClB,QAAA;EACA,MAAA,IAAU,QAAA;IAAY,IAAA;IAAc,IAAA;EAAA;EAjBpC;;;;;;EAwBA,WAAA,GAAc,IAAA,CAAK,cAAA,CAAe,UAAA,GAAa,kBAAA;AAAA;;;;;;UAQhC,0BAAA;EAjBJ;;;;;EAuBX,UAAA;AAAA;;;;;;;AANF;;;;;AA0BA;;;;;;iBAAgB,mBAAA,oBAAuC,SAAA,CAAA,CACrD,IAAA,EAAM,IAAA,CAAK,cAAA,CAAe,UAAA,sCAC1B,OAAA,GAAU,0BAAA;;;;;;;;;;;;;;AAsCZ;;;;;;;;;;iBAAgB,mBAAA,oBAAuC,SAAA,GAAY,SAAA,CAAA,CACjE,OAAA,EAAS,0BAAA,CAA2B,UAAA,IACnC,cAAA,CAAe,UAAA"}
package/dist/react.js ADDED
@@ -0,0 +1,130 @@
1
+ import { Chat, useChat } from "@ai-sdk/react";
2
+ import { useRef, useEffect } from "react";
3
+ import { createSanityChatTransport } from "./chat-transport.js";
4
+ import { buildSendBody } from "./messages.js";
5
+ function getOrCreateThreadChat(cache, threadId, create) {
6
+ const existing = cache.get(threadId);
7
+ if (existing)
8
+ return cache.delete(threadId), cache.set(threadId, existing), existing;
9
+ const created = create();
10
+ return cache.set(threadId, created), created;
11
+ }
12
+ function pruneThreadChats(cache, keepId, max = 25) {
13
+ for (const key of [...cache.keys()]) {
14
+ if (cache.size <= max) break;
15
+ if (key === keepId) continue;
16
+ const evicted = cache.get(key);
17
+ cache.delete(key), evicted?.stop().catch(() => {
18
+ });
19
+ }
20
+ }
21
+ function createThreadChat({
22
+ organizationId,
23
+ threadId,
24
+ baseURL,
25
+ apiVersion,
26
+ messages,
27
+ chatOptions,
28
+ latest
29
+ }) {
30
+ const transport = createSanityChatTransport({
31
+ organizationId,
32
+ threadId,
33
+ baseURL,
34
+ apiVersion,
35
+ token: () => resolve(latest.current.token),
36
+ prepareSendMessagesRequest: ({ messages: turnMessages, body, headers }) => {
37
+ const current = latest.current;
38
+ return {
39
+ headers: withRequestId(headers, turnMessages),
40
+ body: buildSendBody({
41
+ messages: turnMessages,
42
+ body,
43
+ application: resolve(current.application),
44
+ context: resolve(current.context),
45
+ format: current.format,
46
+ clientId: current.clientId
47
+ })
48
+ };
49
+ }
50
+ });
51
+ return new Chat({
52
+ ...chatOptions,
53
+ id: threadId,
54
+ transport,
55
+ messages,
56
+ onError: (error) => latest.current.onError?.(error),
57
+ onFinish: () => latest.current.onFinish?.(),
58
+ onData: (dataPart) => latest.current.onData?.(dataPart)
59
+ });
60
+ }
61
+ function resolve(value) {
62
+ return typeof value == "function" ? value() : value;
63
+ }
64
+ function withRequestId(headers, messages) {
65
+ const merged = {};
66
+ new Headers(headers).forEach((value, key) => {
67
+ merged[key] = value;
68
+ });
69
+ const lastUser = [...messages].reverse().find((m) => m.role === "user");
70
+ return lastUser && (merged["x-request-id"] = lastUser.id), merged;
71
+ }
72
+ function useSanityChatResume(chat, options) {
73
+ const { autoResume = !1 } = options ?? {}, { id: threadId, status, resumeStream } = chat, resumeEvaluatedForRef = useRef(void 0);
74
+ useEffect(() => {
75
+ !autoResume || !threadId || status === "ready" && resumeEvaluatedForRef.current !== threadId && (resumeEvaluatedForRef.current = threadId, resumeStream());
76
+ }, [autoResume, threadId, status, resumeStream]);
77
+ }
78
+ function useContentAgentChat(options) {
79
+ const {
80
+ organizationId,
81
+ threadId,
82
+ baseURL,
83
+ apiVersion,
84
+ token,
85
+ application,
86
+ context,
87
+ format,
88
+ clientId,
89
+ autoResume = !1,
90
+ messages,
91
+ onError,
92
+ onFinish,
93
+ onData
94
+ } = options, latest = useRef({
95
+ token,
96
+ application,
97
+ context,
98
+ format,
99
+ clientId,
100
+ onError,
101
+ onFinish,
102
+ onData
103
+ });
104
+ latest.current = { token, application, context, format, clientId, onError, onFinish, onData };
105
+ const chatsRef = useRef(/* @__PURE__ */ new Map()), fallbackRef = useRef(null);
106
+ fallbackRef.current ??= new Chat({});
107
+ const threadChat = organizationId && threadId ? getOrCreateThreadChat(
108
+ chatsRef.current,
109
+ threadId,
110
+ () => createThreadChat({
111
+ organizationId,
112
+ threadId,
113
+ baseURL,
114
+ apiVersion,
115
+ messages,
116
+ chatOptions: options.chatOptions,
117
+ latest
118
+ })
119
+ ) : fallbackRef.current;
120
+ useEffect(() => {
121
+ pruneThreadChats(chatsRef.current, threadId);
122
+ }, [threadId]);
123
+ const chat = useChat({ chat: threadChat });
124
+ return useSanityChatResume(chat, { autoResume }), chat;
125
+ }
126
+ export {
127
+ useContentAgentChat,
128
+ useSanityChatResume
129
+ };
130
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","sources":["../src/_internal/chat-cache.ts","../src/_internal/create-thread-chat.ts","../src/react.ts"],"sourcesContent":["import type { Chat } from '@ai-sdk/react'\nimport type { UIMessage } from 'ai'\n\n/** Cap on cached per-thread Chat instances, to bound per-session memory. */\nexport const MAX_CACHED_CHATS = 25\n\n/**\n * Get the cached Chat for a thread, creating it via `create` on a miss.\n *\n * This is the building block that lets a thread survive being switched away\n * from: `useChat` rebuilds an empty Chat whenever its `id` changes, so the\n * turnkey hook holds one Chat per thread here and hands the same instance back\n * on return, preserving its messages and its still-running stream (SAGE-502).\n *\n * The accessed/created thread becomes most-recently-used (Map preserves\n * insertion order). Render-safe: it never aborts a stream. Call\n * {@link pruneThreadChats} from an effect to bound the cache.\n */\nexport function getOrCreateThreadChat<UI_MESSAGE extends UIMessage>(\n cache: Map<string, Chat<UI_MESSAGE>>,\n threadId: string,\n create: () => Chat<UI_MESSAGE>,\n): Chat<UI_MESSAGE> {\n const existing = cache.get(threadId)\n if (existing) {\n cache.delete(threadId)\n cache.set(threadId, existing)\n return existing\n }\n\n const created = create()\n cache.set(threadId, created)\n return created\n}\n\n/**\n * Evict least-recently-used chats beyond `max`, stopping each to free its\n * connection, while keeping `keepId`.\n *\n * Call this from an effect, never during render: `stop()` aborts a fetch, and\n * render may run speculatively.\n */\nexport function pruneThreadChats<UI_MESSAGE extends UIMessage>(\n cache: Map<string, Chat<UI_MESSAGE>>,\n keepId: string | undefined,\n max: number = MAX_CACHED_CHATS,\n): void {\n for (const key of [...cache.keys()]) {\n if (cache.size <= max) break\n if (key === keepId) continue\n const evicted = cache.get(key)\n cache.delete(key)\n void evicted?.stop().catch(() => {})\n }\n}\n","import { Chat, type UseChatOptions } from '@ai-sdk/react'\nimport type { Application, Context } from '@sanity/agent-types'\nimport type { UIMessage } from 'ai'\nimport type { RefObject } from 'react'\nimport type { OutputFormat } from '../types'\nimport { createSanityChatTransport } from './chat-transport'\nimport { buildSendBody } from './messages'\n\n/** A value, or a getter resolved at send time (avoids stale closures). */\nexport type Resolvable<T> = T | (() => T | undefined)\n\n/** `useChat` options that {@link useContentAgentChat} owns; the rest pass through. */\nexport type ManagedChatOptions =\n | 'id'\n | 'transport'\n | 'resume'\n | 'messages'\n | 'onError'\n | 'onFinish'\n | 'onData'\n\n/**\n * Per-turn config and callbacks read fresh on each send/event via a ref, so a\n * Chat created once per thread still sees the current values rather than the\n * ones captured when it was created.\n */\nexport interface LatestConfig {\n token?: string | (() => string | undefined)\n application?: Resolvable<Application>\n context?: Resolvable<Context>\n format?: OutputFormat\n clientId?: string\n onError?: (error: Error) => void\n onFinish?: () => void\n onData?: (dataPart: { type: string; data: unknown }) => void\n}\n\nexport interface CreateThreadChatArgs<UI_MESSAGE extends UIMessage> {\n organizationId: string\n threadId: string\n baseURL?: string\n apiVersion?: string\n messages?: UI_MESSAGE[]\n chatOptions?: Omit<UseChatOptions<UI_MESSAGE>, ManagedChatOptions>\n latest: RefObject<LatestConfig>\n}\n\n/**\n * Build the `Chat` for one thread: a Sanity transport (bearer auth, per-turn\n * body shaping, `x-request-id` idempotency) plus callbacks that read the latest\n * config. Called once per thread; the instance is then cached and reused.\n */\nexport function createThreadChat<UI_MESSAGE extends UIMessage>({\n organizationId,\n threadId,\n baseURL,\n apiVersion,\n messages,\n chatOptions,\n latest,\n}: CreateThreadChatArgs<UI_MESSAGE>): Chat<UI_MESSAGE> {\n const transport = createSanityChatTransport<UI_MESSAGE>({\n organizationId,\n threadId,\n baseURL,\n apiVersion,\n token: () => resolve(latest.current.token),\n prepareSendMessagesRequest: ({ messages: turnMessages, body, headers }) => {\n const current = latest.current\n return {\n headers: withRequestId(headers, turnMessages),\n body: buildSendBody({\n messages: turnMessages,\n body,\n application: resolve(current.application),\n context: resolve(current.context),\n format: current.format,\n clientId: current.clientId,\n }),\n }\n },\n })\n\n return new Chat<UI_MESSAGE>({\n ...chatOptions,\n id: threadId,\n transport,\n messages,\n onError: (error) => latest.current.onError?.(error),\n onFinish: () => latest.current.onFinish?.(),\n onData: (dataPart) => latest.current.onData?.(dataPart),\n })\n}\n\nfunction resolve<T>(value: Resolvable<T> | undefined): T | undefined {\n return typeof value === 'function' ? (value as () => T | undefined)() : value\n}\n\n/** Spread the SDK's base headers and stamp `x-request-id` from the last user\n * turn so the optimistic SDK message and the server share one id. */\nfunction withRequestId(headers: HeadersInit | undefined, messages: UIMessage[]): HeadersInit {\n const merged: Record<string, string> = {}\n new Headers(headers).forEach((value, key) => {\n merged[key] = value\n })\n const lastUser = [...messages].reverse().find((m) => m.role === 'user')\n if (lastUser) merged['x-request-id'] = lastUser.id\n return merged\n}\n","import { Chat, type UseChatHelpers, type UseChatOptions, useChat } from '@ai-sdk/react'\nimport type { Application, Context } from '@sanity/agent-types'\nimport type { UIMessage } from 'ai'\nimport { useEffect, useRef } from 'react'\nimport { getOrCreateThreadChat, pruneThreadChats } from './_internal/chat-cache'\nimport {\n createThreadChat,\n type LatestConfig,\n type ManagedChatOptions,\n type Resolvable,\n} from './_internal/create-thread-chat'\nimport type { OutputFormat } from './types'\n\n/**\n * Options for {@link useContentAgentChat}.\n *\n * @category React\n */\nexport interface UseContentAgentChatOptions<UI_MESSAGE extends UIMessage = UIMessage> {\n /** Sanity organization ID. When undefined, no transport is built. */\n organizationId: string | undefined\n /** Stable thread id. When undefined, no transport is built. */\n threadId: string | undefined\n /**\n * Base URL for the Sanity API.\n * @default 'https://api.sanity.io'\n */\n baseURL?: string\n /** API version segment, e.g. `'v2026-01-12'`. */\n apiVersion?: string\n /** Bearer token, or a getter read at request time. */\n token?: string | (() => string | undefined)\n /** Target application; pass a getter to read it fresh on each turn. */\n application?: Resolvable<Application>\n /** Per-turn request context; pass a getter to read it fresh on each turn. */\n context?: Resolvable<Context>\n /** Directive output format (`'directives'` for custom client rendering). */\n format?: OutputFormat\n /** Identifies the creating client (e.g. `'dashboard'`). */\n clientId?: string\n /**\n * When true, reconnect to an in-flight stream once per thread (page reload).\n * The SDK's `resume: true` only fires on first mount, so this hook drives\n * resume per (Chat x threadId) pair instead.\n */\n autoResume?: boolean\n /** Initial messages for a thread's first mount (e.g. server-rendered history). */\n messages?: UI_MESSAGE[]\n onError?: (error: Error) => void\n onFinish?: () => void\n onData?: (dataPart: { type: string; data: unknown }) => void\n /**\n * Any other `useChat`/`Chat` options to forward (e.g. `onToolCall`,\n * `generateId`, `sendAutomaticallyWhen`). The options this hook manages\n * (transport, id, messages, the callbacks above) take precedence. These are\n * read once when a thread's Chat is created.\n */\n chatOptions?: Omit<UseChatOptions<UI_MESSAGE>, ManagedChatOptions>\n}\n\n/**\n * Options for {@link useSanityChatResume}.\n *\n * @category React\n */\nexport interface UseSanityChatResumeOptions {\n /**\n * When true, reconnect to an in-flight stream once per thread. The SDK's\n * `resume: true` only fires on first mount, so this drives resume per\n * (Chat x threadId) pair instead.\n */\n autoResume?: boolean\n}\n\n/**\n * Reconnect to an in-flight stream once per (Chat x threadId), when idle.\n *\n * Does not stop the stream on thread change or unmount: per the AI SDK\n * resumable-stream model, client-side aborts are disconnects that should stay\n * resumable, not cancellations. Stopping is an explicit user action (call\n * `chat.stop()` and/or a server stop endpoint), never route or unmount\n * cleanup. See https://ai-sdk.dev/docs/troubleshooting/abort-breaks-resumable-streams.\n *\n * @category React\n *\n * @example\n * ```tsx\n * const chat = useChat({ chat: myThreadChat })\n * useSanityChatResume(chat, { autoResume: threadExistsOnBackend })\n * ```\n */\nexport function useSanityChatResume<UI_MESSAGE extends UIMessage>(\n chat: Pick<UseChatHelpers<UI_MESSAGE>, 'id' | 'status' | 'resumeStream'>,\n options?: UseSanityChatResumeOptions,\n): void {\n const { autoResume = false } = options ?? {}\n const { id: threadId, status, resumeStream } = chat\n\n const resumeEvaluatedForRef = useRef<string | undefined>(undefined)\n useEffect(() => {\n if (!autoResume || !threadId) return\n if (status !== 'ready') return\n if (resumeEvaluatedForRef.current === threadId) return\n resumeEvaluatedForRef.current = threadId\n void resumeStream()\n }, [autoResume, threadId, status, resumeStream])\n}\n\n/**\n * `useChat` wired to the Sanity Content Agent: bearer auth, per-turn body\n * shaping (application/context/format/clientId), `x-request-id` idempotency,\n * and resume on reload.\n *\n * Holds one `Chat` instance per thread (the AI SDK's recommended pattern for\n * multiple conversations), so switching threads mid-stream and back keeps the\n * thread's messages and its still-running stream instead of rebuilding an empty\n * Chat. Returns the standard `useChat` helpers.\n *\n * @category React\n *\n * @example\n * ```tsx\n * const chat = useContentAgentChat({\n * organizationId,\n * threadId,\n * token: () => client.config().token,\n * application,\n * autoResume: threadExistsOnBackend,\n * })\n * ```\n */\nexport function useContentAgentChat<UI_MESSAGE extends UIMessage = UIMessage>(\n options: UseContentAgentChatOptions<UI_MESSAGE>,\n): UseChatHelpers<UI_MESSAGE> {\n const {\n organizationId,\n threadId,\n baseURL,\n apiVersion,\n token,\n application,\n context,\n format,\n clientId,\n autoResume = false,\n messages,\n onError,\n onFinish,\n onData,\n } = options\n\n const latest = useRef<LatestConfig>({\n token,\n application,\n context,\n format,\n clientId,\n onError,\n onFinish,\n onData,\n })\n latest.current = { token, application, context, format, clientId, onError, onFinish, onData }\n\n // One Chat per thread, retained across switches (see getOrCreateThreadChat).\n const chatsRef = useRef(new Map<string, Chat<UI_MESSAGE>>())\n // Stable placeholder used until a thread exists, so the hook's shape holds.\n const fallbackRef = useRef<Chat<UI_MESSAGE> | null>(null)\n fallbackRef.current ??= new Chat<UI_MESSAGE>({})\n\n const threadChat =\n organizationId && threadId\n ? getOrCreateThreadChat(chatsRef.current, threadId, () =>\n createThreadChat<UI_MESSAGE>({\n organizationId,\n threadId,\n baseURL,\n apiVersion,\n messages,\n chatOptions: options.chatOptions,\n latest,\n }),\n )\n : fallbackRef.current\n\n // Bound the cache after commit, not in render: pruning aborts evicted streams.\n useEffect(() => {\n pruneThreadChats(chatsRef.current, threadId)\n }, [threadId])\n\n const chat = useChat<UI_MESSAGE>({ chat: threadChat })\n\n useSanityChatResume(chat, { autoResume })\n\n return chat\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "content-agent",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "description": "Vercel AI SDK provider for Sanity Content Agent API",
5
5
  "keywords": [
6
6
  "sanity",
@@ -23,6 +23,15 @@
23
23
  "./agent": {
24
24
  "default": "./dist/content-agent.js"
25
25
  },
26
+ "./transport": {
27
+ "default": "./dist/chat-transport.js"
28
+ },
29
+ "./messages": {
30
+ "default": "./dist/messages.js"
31
+ },
32
+ "./react": {
33
+ "default": "./dist/react.js"
34
+ },
26
35
  "./package.json": "./package.json"
27
36
  },
28
37
  "types": "./dist/index.d.ts",
@@ -37,22 +46,36 @@
37
46
  "@sanity/agent-types": "0.1.4"
38
47
  },
39
48
  "devDependencies": {
49
+ "@ai-sdk/react": "^3.0.0",
40
50
  "@sanity/pkg-utils": "^10.4.1",
51
+ "@testing-library/react": "^16.0.0",
41
52
  "@types/node": "^22.19.7",
53
+ "@types/react": "^19.0.0",
42
54
  "ai": "^6.0.168",
55
+ "jsdom": "^26.0.0",
43
56
  "openapi-typescript": "^7.10.1",
57
+ "react": "^19.0.0",
58
+ "react-dom": "^19.0.0",
44
59
  "typedoc": "^0.28.17",
45
60
  "typescript": "^5.9.3",
46
61
  "vitest": "^4.0.18",
47
- "@repo/package.config": "0.0.0",
48
- "@repo/tsconfig": "0.0.0"
62
+ "@repo/tsconfig": "0.0.0",
63
+ "@repo/package.config": "0.0.0"
49
64
  },
50
65
  "peerDependencies": {
51
- "ai": ">=6.0.0"
66
+ "@ai-sdk/react": ">=3.0.0",
67
+ "ai": ">=6.0.0",
68
+ "react": "^18.0.0 || ^19.0.0"
52
69
  },
53
70
  "peerDependenciesMeta": {
71
+ "@ai-sdk/react": {
72
+ "optional": true
73
+ },
54
74
  "ai": {
55
75
  "optional": true
76
+ },
77
+ "react": {
78
+ "optional": true
56
79
  }
57
80
  },
58
81
  "publishConfig": {