content-agent 0.5.3 → 0.7.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.
package/README.md CHANGED
@@ -23,12 +23,10 @@ const contentAgent = createContentAgent({
23
23
 
24
24
  const model = contentAgent.agent("my-thread");
25
25
 
26
- const result = await generateText({
26
+ const { text } = await generateText({
27
27
  model,
28
28
  prompt: "What blog posts do I have?",
29
29
  });
30
-
31
- console.log(result.text);
32
30
  ```
33
31
 
34
32
  ## Streaming
@@ -50,13 +48,12 @@ for await (const text of textStream) {
50
48
 
51
49
  ## Applications
52
50
 
53
- Each application key uniquely identifies a deployed Sanity Studio workspace. Since multiple studios can share the same project ID and dataset, the application key is used to unambiguously target the right one.
51
+ Each application key uniquely identifies a deployed Sanity Studio workspace. Since multiple studios can share the same project ID and dataset, the application key disambiguates which one to target.
54
52
 
55
53
  List available applications for your organization, then target one by its key:
56
54
 
57
55
  ```typescript
58
56
  const apps = await contentAgent.applications();
59
-
60
57
  const app = apps.find((app) => app.title === "My Studio");
61
58
 
62
59
  const model = contentAgent.agent("my-thread", {
@@ -64,51 +61,56 @@ const model = contentAgent.agent("my-thread", {
64
61
  });
65
62
  ```
66
63
 
64
+ You can also set a default application on the provider so every `.agent()` and `.prompt()` call inherits it:
65
+
66
+ ```typescript
67
+ const contentAgent = createContentAgent({
68
+ organizationId: "your-org-id",
69
+ token: "your-token",
70
+ application: resolvedApp,
71
+ });
72
+
73
+ // No need to pass application per-call
74
+ const model = contentAgent.agent("my-thread");
75
+ ```
76
+
67
77
  ## Tools
68
78
 
69
79
  Pass AI SDK tools to `streamText` or `generateText` — tool schemas are forwarded to the agent, and execution happens locally on the client:
70
80
 
71
81
  ```typescript
72
- import { streamText, tool, stepCountIs } from "ai";
82
+ import { streamText, tool } from "ai";
73
83
  import { z } from "zod";
74
84
 
75
85
  const result = streamText({
76
- model: contentAgent.agent("my-thread", { application: { key: "my-studio" } }),
77
- prompt: `Find all blog posts still in draft and submit them for review. Assign them to anna@example.com.`,
86
+ model: contentAgent.agent("my-thread"),
87
+ prompt: "Find all draft blog posts and submit them for review.",
78
88
  tools: {
79
89
  submit_for_review: tool({
80
- description: `Submit a document for editorial review. The document must be in draft state.`,
90
+ description: "Submit a document for editorial review.",
81
91
  inputSchema: z.object({
82
92
  documentId: z.string().describe("The Sanity document _id"),
83
- email: z.string().email().describe("Assign a specific reviewer"),
93
+ email: z.string().email().describe("Reviewer email"),
84
94
  note: z.string().optional().describe("Note for the reviewer"),
85
95
  }),
86
96
  execute: async ({ documentId, email, note }) => {
87
- const res = await fetch(
88
- "https://workflows.internal.example.com/api/review",
89
- {
90
- method: "POST",
91
- body: JSON.stringify({ documentId, email, note }),
92
- },
93
- );
94
-
95
- const { ticketUrl } = await res.json();
96
- return { success: true, documentId, ticketUrl };
97
+ const res = await fetch("https://workflows.example.com/api/review", {
98
+ method: "POST",
99
+ body: JSON.stringify({ documentId, email, note }),
100
+ });
101
+ return res.json();
97
102
  },
98
103
  }),
99
104
  },
100
105
  });
101
106
  ```
102
107
 
103
- The model decides when to call your tools. `stopWhen` controls how many round-trips are allowed between the model and tool execution.
104
-
105
108
  ## Configuration
106
109
 
107
110
  Pass a `config` object to `.agent()` to control behavior:
108
111
 
109
112
  ```typescript
110
113
  const model = contentAgent.agent("my-thread", {
111
- application: { key: "your-application-key" },
112
114
  config: {
113
115
  instruction: "You are a helpful content assistant for our marketing team.",
114
116
  userMessageContext: {
@@ -137,41 +139,80 @@ const model = contentAgent.agent("my-thread", {
137
139
  | `filter` | `object` | GROQ boolean expressions for document access control |
138
140
  | `perspectives` | `object` | Perspective locking for read and write operations |
139
141
 
140
- ### User message context
142
+ ### Capabilities
141
143
 
142
- Each entry in `userMessageContext` is rendered as an XML tag in the user message. This gives the model structured context it can reason about without polluting the conversation.
144
+ Each capability can be `true`, `false`, or a preset object:
143
145
 
144
146
  ```typescript
145
- config: {
146
- userMessageContext: {
147
- "slack-channel": "#marketing",
148
- "image-urls": "https://example.com/hero.png\nhttps://example.com/logo.jpg",
149
- },
150
- }
147
+ // Read-only
148
+ config: { capabilities: { read: true, write: false } }
149
+
150
+ // Minimal write access
151
+ config: { capabilities: { read: true, write: { preset: "minimal" } } }
151
152
  ```
152
153
 
153
- The model sees:
154
+ ## Studio usage
154
155
 
155
- ```xml
156
- <slack-channel>#marketing</slack-channel>
157
- <image-urls>
158
- https://example.com/hero.png
159
- https://example.com/logo.jpg
160
- </image-urls>
156
+ `createStudioAgent` makes the provider work inside Sanity Studio with no token or manual configuration. It derives the API host, organization ID, and application from the Studio context:
157
+
158
+ ```typescript
159
+ import { useMemo } from "react";
160
+ import { createStudioAgent } from "content-agent";
161
+ import { useClient, useWorkspace } from "sanity";
162
+
163
+ function MyComponent() {
164
+ const client = useClient({ apiVersion: "2024-01-01" });
165
+ const { name: workspace } = useWorkspace();
166
+
167
+ const contentAgent = useMemo(
168
+ () => createStudioAgent(client, workspace),
169
+ [client, workspace],
170
+ );
171
+
172
+ // Use contentAgent.agent(threadId) with useChat, generateText, etc.
173
+ }
161
174
  ```
162
175
 
163
- ### Capabilities
176
+ The factory call is synchronous — async setup (org ID fetch, application resolution) runs lazily on the first API call and is cached at the module level. Wrap in `useMemo` so the provider keeps a stable identity across renders.
164
177
 
165
- Each capability can be `true`, `false`, or a preset object:
178
+ Since there is no token in a Studio context, `credentials: 'include'` is set on all fetch calls automatically so the browser sends session cookies. The base URL is derived from the client's `apiHost` config.
166
179
 
167
- ```typescript
168
- // Read-only
169
- config: { capabilities: { read: true, write: false } }
180
+ ### Using with `useChat`
170
181
 
171
- // Minimal write access
172
- config: { capabilities: { read: true, write: { preset: "minimal" } } }
182
+ For a streaming chat UI, pair with `DirectChatTransport` from the AI SDK:
183
+
184
+ ```tsx
185
+ import { useMemo, useState } from "react";
186
+ import { useClient, useWorkspace } from "sanity";
187
+ import { useChat } from "@ai-sdk/react";
188
+ import { DirectChatTransport, ToolLoopAgent } from "ai";
189
+ import { createStudioAgent } from "content-agent";
190
+
191
+ function ChatTool() {
192
+ const client = useClient({ apiVersion: "2024-01-01" });
193
+ const { name: workspace } = useWorkspace();
194
+ const [threadId] = useState(() => `thread-${crypto.randomUUID()}`);
195
+
196
+ const transport = useMemo(() => {
197
+ const contentAgent = createStudioAgent(client, workspace);
198
+ return new DirectChatTransport({
199
+ agent: new ToolLoopAgent({ model: contentAgent.agent(threadId) }),
200
+ });
201
+ }, [client, workspace, threadId]);
202
+
203
+ const { messages, sendMessage, status } = useChat({ transport });
204
+
205
+ // Render messages, input form, etc.
206
+ }
173
207
  ```
174
208
 
209
+ ### Lower-level helpers
210
+
211
+ If you already know the organization ID and need more control:
212
+
213
+ - `fromClient(client, workspace)` — derives `baseURL` and `application` from a Sanity client
214
+ - `contentAgent.resolveApplication(client, workspace)` — fetches applications and matches by resource ID + workspace name
215
+
175
216
  ## License
176
217
 
177
218
  MIT
package/dist/index.d.ts CHANGED
@@ -598,8 +598,20 @@ type UserMessageContext = NonNullable<Config['userMessageContext']>;
598
598
  interface ContentAgentProviderSettings {
599
599
  /**
600
600
  * Your Sanity organization ID.
601
+ *
602
+ * When using {@link createStudioAgent}, this is fetched automatically
603
+ * from the project metadata.
601
604
  */
602
605
  organizationId: string;
606
+ /**
607
+ * Default application for all agent and prompt calls.
608
+ *
609
+ * When set, this application is used unless overridden per-call via
610
+ * {@link AgentSettings.application} or {@link GenerateSettings.application}.
611
+ *
612
+ * Typically set automatically by {@link createStudioAgent}.
613
+ */
614
+ application?: Application;
603
615
  /**
604
616
  * Base URL for the Sanity API.
605
617
  * @default 'https://api.sanity.io'
@@ -776,6 +788,86 @@ interface GenerateResult {
776
788
  */
777
789
  text: string;
778
790
  }
791
+ /**
792
+ * Minimal interface for a Sanity client. Avoids a hard dependency on `@sanity/client` —
793
+ * any object whose `config()` returns `projectId`, `dataset`, and `apiHost` will work.
794
+ *
795
+ * @category Studio Integration
796
+ */
797
+ type SanityClientLike = {
798
+ config(): {
799
+ projectId?: string;
800
+ dataset?: string;
801
+ apiHost?: string;
802
+ };
803
+ };
804
+ /**
805
+ * Configuration derived from a Sanity client for use with {@link createContentAgent}.
806
+ *
807
+ * @category Studio Integration
808
+ */
809
+ type ClientDerivedConfig = {
810
+ /**
811
+ * Project-scoped API base URL derived from the client's `apiHost`.
812
+ *
813
+ * Using a project-scoped host avoids CORS preflight issues when making
814
+ * cookie-authenticated requests from a Studio context.
815
+ */
816
+ baseURL: string;
817
+ /**
818
+ * Application targeting the client's project, dataset, and workspace.
819
+ *
820
+ * Identified by `resource.id` (`projectId.dataset`) and `name` (workspace name),
821
+ * which matches the format the Content Agent API uses internally.
822
+ */
823
+ application: Application;
824
+ };
825
+ /**
826
+ * Derives a project-scoped base URL from the client's configured API host.
827
+ * Inserts `projectId` as a subdomain so cookie-authenticated requests
828
+ * from Studio pass CORS checks.
829
+ *
830
+ * `https://api.sanity.io` → `https://{projectId}.api.sanity.io`
831
+ * `https://api.sanity.work` → `https://{projectId}.api.sanity.work`
832
+ *
833
+ * @category Studio Integration
834
+ */
835
+ declare function deriveBaseUrl(apiHost: string | undefined, projectId: string): string;
836
+ /**
837
+ * Derives Content Agent configuration from a Sanity client and workspace name.
838
+ *
839
+ * Extracts `projectId`, `dataset`, and `apiHost` to build a CORS-compatible
840
+ * `baseURL` and an `application` that targets the correct workspace — no need
841
+ * to know the Studio deployment ID or application key.
842
+ *
843
+ * Designed for Studio / browser contexts where authentication is handled
844
+ * via cookies. Omit the `token` when creating the provider and credentials
845
+ * will be included automatically.
846
+ *
847
+ * @category Studio Integration
848
+ *
849
+ * @example Studio AI Assist action
850
+ * ```ts
851
+ * import { createContentAgent, fromClient } from 'content-agent'
852
+ * import { useClient, useWorkspace } from 'sanity'
853
+ *
854
+ * const client = useClient({ apiVersion: '2024-01-01' })
855
+ * const workspace = useWorkspace()
856
+ * const { baseURL } = fromClient(client, workspace.name)
857
+ *
858
+ * const contentAgent = createContentAgent({
859
+ * organizationId: 'your-org-id',
860
+ * baseURL,
861
+ * })
862
+ *
863
+ * const application = await contentAgent.resolveApplication(client, workspace.name)
864
+ * const model = contentAgent.agent('thread-id', { application })
865
+ * ```
866
+ *
867
+ * @param client - Any object with a `config()` method returning `projectId`, `dataset`, and optionally `apiHost`.
868
+ * @param workspace - The active workspace name (e.g. `'default'`). Available via `useWorkspace().name` in Studio.
869
+ */
870
+ declare function fromClient(client: SanityClientLike, workspace: string): ClientDerivedConfig;
779
871
  /**
780
872
  * @category Model
781
873
  */
@@ -785,6 +877,7 @@ interface ContentAgentModelConfig {
785
877
  apiVersion: string;
786
878
  organizationId: string;
787
879
  headers: () => Record<string, string | undefined>;
880
+ credentials?: RequestCredentials;
788
881
  fetch?: typeof globalThis.fetch;
789
882
  }
790
883
  /**
@@ -915,6 +1008,39 @@ interface ContentAgentProvider {
915
1008
  * ```
916
1009
  */
917
1010
  applications(): Promise<Application[]>;
1011
+ /**
1012
+ * Resolves the full application for a Sanity client by matching its `projectId`
1013
+ * and `dataset` against the organization's application list.
1014
+ *
1015
+ * This is the easiest way to get a valid application in Studio contexts —
1016
+ * pass the client you already have and get back an application with the
1017
+ * correct `key` for the Content Agent API.
1018
+ *
1019
+ * Throws if no matching application is found (e.g. wrong org, or the Studio
1020
+ * hasn't been deployed yet).
1021
+ *
1022
+ * @example
1023
+ * ```ts
1024
+ * import { createContentAgent, fromClient } from 'content-agent'
1025
+ * import { useClient, useWorkspace } from 'sanity'
1026
+ *
1027
+ * const client = useClient({ apiVersion: '2024-01-01' })
1028
+ * const workspace = useWorkspace()
1029
+ * const { baseURL } = fromClient(client, workspace.name)
1030
+ *
1031
+ * const contentAgent = createContentAgent({
1032
+ * organizationId: 'your-org-id',
1033
+ * baseURL,
1034
+ * })
1035
+ *
1036
+ * const application = await contentAgent.resolveApplication(client, workspace.name)
1037
+ * const model = contentAgent.agent('thread-id', { application })
1038
+ * ```
1039
+ *
1040
+ * @param client - Any object with a `config()` method returning `projectId` and `dataset`.
1041
+ * @param workspace - The active workspace name (e.g. `'default'`). Available via `useWorkspace().name` in Studio.
1042
+ */
1043
+ resolveApplication(client: SanityClientLike, workspace: string): Promise<Application>;
918
1044
  /**
919
1045
  * Sends a one-shot prompt to the Content Agent (stateless).
920
1046
  *
@@ -999,6 +1125,74 @@ interface ContentAgentProvider {
999
1125
  * @param options - Provider configuration including organization ID, token, and optional overrides.
1000
1126
  */
1001
1127
  declare function createContentAgent(options: ContentAgentProviderSettings): ContentAgentProvider;
1128
+ /**
1129
+ * Options for {@link createStudioAgent}.
1130
+ *
1131
+ * @category Studio Integration
1132
+ */
1133
+ type StudioAgentOptions = {
1134
+ /**
1135
+ * Custom fetch implementation. Useful for testing.
1136
+ */
1137
+ fetch?: typeof globalThis.fetch;
1138
+ /**
1139
+ * Additional provider settings forwarded to {@link createContentAgent}.
1140
+ * `organizationId`, `baseURL`, and `application` are derived automatically
1141
+ * and cannot be overridden here.
1142
+ */
1143
+ providerOptions?: Omit<ContentAgentProviderSettings, 'organizationId' | 'baseURL' | 'application'>;
1144
+ };
1145
+ /**
1146
+ * Creates a Content Agent provider fully configured for a Studio context.
1147
+ *
1148
+ * This is the simplest way to use Content Agent from inside Sanity Studio.
1149
+ * The call is **synchronous** — safe to use in React components and hooks.
1150
+ * Async setup (fetching the organization ID and resolving the application)
1151
+ * is deferred to the first API call, which is already async.
1152
+ *
1153
+ * Internally handles:
1154
+ * 1. Deriving the project-scoped API URL (for CORS)
1155
+ * 2. Fetching the organization ID from project metadata
1156
+ * 3. Resolving the Studio application by workspace name
1157
+ * 4. Cookie-based auth (no token needed)
1158
+ *
1159
+ * The returned provider works exactly like one from {@link createContentAgent},
1160
+ * but `.agent()` and `.prompt()` automatically target the resolved application
1161
+ * unless explicitly overridden per-call.
1162
+ *
1163
+ * @category Studio Integration
1164
+ *
1165
+ * @example Studio component with memoized provider
1166
+ * ```ts
1167
+ * import { useMemo } from 'react'
1168
+ * import { createStudioAgent } from 'content-agent'
1169
+ * import { useClient, useWorkspace } from 'sanity'
1170
+ * import { generateText } from 'ai'
1171
+ *
1172
+ * function MyComponent() {
1173
+ * const client = useClient({ apiVersion: '2024-01-01' })
1174
+ * const { name: workspace } = useWorkspace()
1175
+ *
1176
+ * const contentAgent = useMemo(
1177
+ * () => createStudioAgent(client, workspace),
1178
+ * [client, workspace],
1179
+ * )
1180
+ *
1181
+ * async function handleSummarize() {
1182
+ * const { text } = await generateText({
1183
+ * model: contentAgent.agent('my-thread'),
1184
+ * prompt: 'Summarize my content',
1185
+ * })
1186
+ * console.log(text)
1187
+ * }
1188
+ * }
1189
+ * ```
1190
+ *
1191
+ * @param client - Any object with a `config()` returning `projectId` and `dataset`.
1192
+ * @param workspace - The active workspace name. Available via `useWorkspace().name` in Studio.
1193
+ * @param options - Optional overrides (custom fetch, additional provider settings).
1194
+ */
1195
+ declare function createStudioAgent(client: SanityClientLike, workspace: string, options?: StudioAgentOptions): ContentAgentProvider;
1002
1196
  /**
1003
1197
  * Builds headers for API requests, filtering out undefined values.
1004
1198
  *
@@ -1025,11 +1219,33 @@ declare class SanityAgentError extends Error {
1025
1219
  constructor(status: number, message: string);
1026
1220
  private static parseBody;
1027
1221
  }
1222
+ /**
1223
+ * Error class for errors received via SSE stream events.
1224
+ * Unlike {@link SanityAgentError} (which is thrown for HTTP-level errors before
1225
+ * streaming starts), this wraps errors received mid-stream as SSE `error` events.
1226
+ *
1227
+ * The {@link code} carries the backend's error classification (e.g. `UPSTREAM_OVERLOADED`)
1228
+ * so clients can take targeted action without parsing the message string.
1229
+ *
1230
+ * @category Utilities
1231
+ */
1232
+ declare class SanityAgentStreamError extends Error {
1233
+ readonly code: string | undefined;
1234
+ constructor(message: string, code?: string);
1235
+ }
1028
1236
  declare const GENERIC_ERROR_MESSAGE = "Sorry, something went wrong. Please try again.";
1029
1237
  type AgentErrorType = {
1030
1238
  type: 'no_applications';
1031
1239
  } | {
1032
1240
  type: 'application_not_found';
1241
+ } | {
1242
+ type: 'upstream_overloaded';
1243
+ } | {
1244
+ type: 'upstream_error';
1245
+ } | {
1246
+ type: 'usage_limit_exceeded';
1247
+ } | {
1248
+ type: 'streaming_error';
1033
1249
  } | {
1034
1250
  type: 'unknown';
1035
1251
  };
@@ -1041,6 +1257,19 @@ type AgentErrorType = {
1041
1257
  * @category Utilities
1042
1258
  */
1043
1259
  declare function classifyAgentError(error: unknown): AgentErrorType;
1260
+ declare function isAppRelatedError(classified: AgentErrorType): boolean;
1261
+ type AgentErrorMessageContext = {
1262
+ orgName?: string | null;
1263
+ };
1264
+ /**
1265
+ * Resolves a user-facing error message for a classified agent error.
1266
+ * For errors that benefit from additional context (e.g. org name), the optional
1267
+ * {@link resolveContext} callback is invoked lazily — only when the error type
1268
+ * needs it. Non-contextual errors return the backend message as-is.
1269
+ *
1270
+ * @category Utilities
1271
+ */
1272
+ declare function resolveAgentErrorMessage(classified: AgentErrorType, error: unknown, resolveContext?: () => Promise<AgentErrorMessageContext>): Promise<string>;
1044
1273
  /**
1045
1274
  * Extracts a user-facing error message from an agent API error.
1046
1275
  * Returns the message sent by the API when available, otherwise a generic fallback.
@@ -1052,6 +1281,7 @@ interface FetchOptions {
1052
1281
  url: string;
1053
1282
  body: unknown;
1054
1283
  headers: Record<string, string>;
1284
+ credentials?: RequestCredentials;
1055
1285
  signal?: AbortSignal;
1056
1286
  fetch?: typeof globalThis.fetch;
1057
1287
  }
@@ -1130,5 +1360,5 @@ declare function extractTextFromStream(responseBody: ReadableStream<Uint8Array>)
1130
1360
  * @category Utilities
1131
1361
  */
1132
1362
  declare function createSSEStream(responseBody: ReadableStream<Uint8Array>, warnings: SharedV3Warning[], onData?: (type: string, data: unknown) => void): ReadableStream<LanguageModelV3StreamPart>;
1133
- export { type AgentErrorType, type AgentSettings, type Application, type ApplicationResource, type Capabilities, type Capability, type CapabilityPreset, type CapabilityPresetValue, type ChatRequest, type ChatResponse, type ClientToolDefinition, type Config, ContentAgentModel, type ContentAgentModelConfig, type ContentAgentProvider, type ContentAgentProviderSettings, type ErrorResponse, type Filter, GENERIC_ERROR_MESSAGE, type GenerateOptions, type GenerateRequest, type GenerateResult, type GenerateSettings, type Message, type MessageRole, type OutputFormat, type ParsedStreamLine, SanityAgentError, type UserMessageContext, type ValidationIssue, buildApiUrl, buildHeaders, classifyAgentError, type components, createContentAgent, createSSEStream, extractTextFromParts, extractTextFromStream, fetchApi, getAgentErrorMessage, mapFinishReason, type operations, parseStreamLine, type paths };
1363
+ export { type AgentErrorMessageContext, type AgentErrorType, type AgentSettings, type Application, type ApplicationResource, type Capabilities, type Capability, type CapabilityPreset, type CapabilityPresetValue, type ChatRequest, type ChatResponse, type ClientDerivedConfig, type ClientToolDefinition, type Config, ContentAgentModel, type ContentAgentModelConfig, type ContentAgentProvider, type ContentAgentProviderSettings, type ErrorResponse, type Filter, GENERIC_ERROR_MESSAGE, type GenerateOptions, type GenerateRequest, type GenerateResult, type GenerateSettings, type Message, type MessageRole, type OutputFormat, type ParsedStreamLine, SanityAgentError, SanityAgentStreamError, type SanityClientLike, type StudioAgentOptions, type UserMessageContext, type ValidationIssue, buildApiUrl, buildHeaders, classifyAgentError, type components, createContentAgent, createSSEStream, createStudioAgent, deriveBaseUrl, extractTextFromParts, extractTextFromStream, fetchApi, fromClient, getAgentErrorMessage, isAppRelatedError, mapFinishReason, type operations, parseStreamLine, type paths, resolveAgentErrorMessage };
1134
1364
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/generated/openapi.ts","../src/types.ts","../src/sanity-agent-language-model.ts","../src/sanity-agent-provider.ts","../src/utils.ts"],"mappings":";;;;;AAKA;KAAY,KAAA;EACV,sCAAA;IACE,UAAA;MACE,KAAA;MACA,MAAA;MACA,IAAA;MACA,MAAA;IAAA;IAEF,GAAA;IACA,GAAA;IAAA;;;;;IAMA,IAAA,EAAM,UAAA;IACN,MAAA;IACA,OAAA;IACA,IAAA;IACA,KAAA;IACA,KAAA;EAAA;EAEF,SAAA;IACE,UAAA;MACE,KAAA;MACA,MAAA;MACA,IAAA;MACA,MAAA;IAAA;IAEF,GAAA;IACA,GAAA;IAUA;;;;AAKJ;IATI,IAAA,EAAM,UAAA;IACN,MAAA;IACA,OAAA;IACA,IAAA;IACA,KAAA;IACA,KAAA;EAAA;AAAA;AAAA,KAIQ,UAAA;EACV,OAAA;IACE,WAAA;MAiJsB,4CA/IpB,QAAA,EAAU,UAAA;MACV,WAAA,GAAc,UAAA;MACd,MAAA,GAAS,UAAA;MA6Ra;;;;MAxRtB,MAAA;MAPA;;;;;;;MAeA,MAAA;IAAA;IAEF,aAAA;MAUE;;;;MALA,cAAA;MAqBF;;;;MAhBE,OAAA;MACA,MAAA,GAAS,UAAA;MAkCT;;;;MA7BA,YAAA;MAiDA;;;;;;;MAzCA,MAAA;IAAA;IAEF,OAAA;MAmEE;;;;MA9DA,IAAA,mCA0EA;MAxEA,OAAA,UAyEA;MAvEA,EAAA,WAwEA;MAtEA,IAAA;IAAA,GAiFA;IA9EF,WAAA;MAsFsB;;;;MAjFpB,GAAA;MACA,QAAA;QAkHF;;;;QA7GI,EAAA;QAmIF;;;;QA9HE,IAAA;MAAA;MA8IJ;;;;;MAvIE,aAAA,WA8JA;MA5JA,aAAA,WA+JA;MA7JA,IAAA,WA6KsB;MA3KtB,KAAA,WAgLA;MA9KA,kBAAA;IAAA,GAwLE;IArLJ,MAAA;MAyLA;;;;MApLE,WAAA;MA+LsB;;;;;;;AAU5B;;MA/LM,kBAAA;QAAA,CACG,GAAA;MAAA;MAEH,YAAA,GAAe,UAAA;MACf,MAAA,GAAS,UAAA;MACT,YAAA,GAAe,UAAA;IAAA;IA6PV;;;;;;;;IAnPP,YAAA;MACE,IAAA,GAAO,UAAA;MACP,KAAA,GAAQ,UAAA;MACR,QAAA,GAAW,UAAA;IAAA;IAgMb;;;;IA1LA,gBAAA;MAiME;;;;MA5LA,SAAA;IAAA;IAmMI;;;;;;IA3LN,UAAA,YAAsB,UAAA;IACtB,gBAAA;MAiMO;;;;;;;;;;MAtLL,MAAA;IAAA,GAuMA;IApMF,MAAA;MAsMM;;;;;MAhMJ,IAAA;MAwMK;;;;;MAlML,KAAA;IAAA;;ACrNN;;;;ID4NI,YAAA;MCvNQ;;;;;AAMZ;;;MD0NM,IAAA;MC1NgC;AAQtC;;;;MDwNM,KAAA;IAAA,GCnNmB;IDsNrB,YAAA;MCtNkC,6CDwNhC,IAAA,WCnNM;MDqNN,cAAA;IAAA;IAEF,aAAA;MCvNoC;AAQxC;;;MDoNM,KAAA;MCpN0B;AAKhC;;;MDoNM,OAAA,WCpN2B;MDsN3B,MAAA,GAAS,UAAA;IAAA;IAEX,eAAA;MCxMgC;;AAKpC;;MDwMM,IAAA;MCxMmD;;AAqCzD;;;;MD0KM,IAAA;MCxKJ;;;;MD6KI,OAAA;IAAA;EAAA;EAGJ,SAAA;ICxImC,2DD0IjC,UAAA;MACE,OAAA;QAAA,CACG,IAAA;MAAA;MAEH,OAAA;QCnIM;;;;;AAKZ;;;;;AAeA;;;;;QD+HQ,kBAAA,EAAoB,UAAA;MAAA;IAAA,GC7GiB;IDiHzC,YAAA;MACE,OAAA;QAAA,CACG,IAAA;MAAA;MAEH,OAAA;QC7FJ;;;;;;QDoGM,kBAAA,EAAoB,UAAA;MAAA;IAAA,GCrEK;IDyE7B,mBAAA;MACE,OAAA;QAAA,CACG,IAAA;MAAA;MAEH,OAAA;QCxBK;;;;;;QD+BH,kBAAA,EAAoB,UAAA;MAAA;IAAA;EAAA;EAI1B,UAAA;EACA,aAAA;EACA,OAAA;EACA,SAAA;AAAA;AAAA,UAGe,UAAA;EACf,IAAA;IACE,UAAA;MACE,KAAA;MACA,MAAA;MACA,IAAA;QCYW;;;;QDPT,cAAA;QC2BS;;;;QDtBT,QAAA;MAAA;MAEF,MAAA;IAAA;IAEF,WAAA;MACE,OAAA;QACE,kBAAA,EAAoB,UAAA;MAAA;IAAA;IAGxB,SAAA;MCwCE,sCDtCA,GAAA;QACE,OAAA;UACE,cAAA;UACA,yBAAA;UAAA,CACC,IAAA;QAAA;QAEH,OAAA;UACE,mBAAA,UEnWR;UFqWQ,kBAAA,EAAoB,UAAA;QAAA;MAAA;MAGxB,GAAA,EAAK,UAAA;MACL,GAAA,EAAK,UAAA;MACL,GAAA,EAAK,UAAA;IAAA;EAAA;EAGT,MAAA;IACE,UAAA;MACE,KAAA;MACA,MAAA;MACA,IAAA;MACA,MAAA;IAAA;IAEF,WAAA;MACE,OAAA;QACE,kBAAA,EAAoB,UAAA;MAAA;IAAA;IAGxB,SAAA;MEnTqD,sCFqTnD,GAAA;QACE,OAAA;UACE,cAAA;UACA,yBAAA;UAAA,CACC,IAAA;QAAA;QAEH,OAAA;UACE,mBAAA;QAAA;MAAA;MAGJ,GAAA,EAAK,UAAA;MACL,GAAA,EAAK,UAAA;MACL,GAAA,EAAK,UAAA;IAAA;EAAA;AAAA;;;;;KCzZC,WAAA,GAAc,UAAA;;;;;KAKd,eAAA,GAAkB,UAAA;;;;;KAMlB,YAAA,GAAe,WAAA;;;;;KAQf,YAAA,GAAe,UAAA;;;;;KAKf,aAAA,GAAgB,UAAA;;;;;KAKhB,eAAA,GAAkB,UAAA;;;;;KAQlB,OAAA,GAAU,UAAA;ADEtB;;;;AAAA,KCGY,WAAA,GAAc,OAAA;;;;;;;;;;;;;KAgBd,WAAA,GAAc,UAAA;;;;;KAKd,mBAAA,GAAsB,WAAA,CAAY,WAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqClC,MAAA,GAAS,UAAA;EDoDA,wKClDnB,YAAA,sBDmDa;ECjDb,sBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsCU,YAAA,GAAe,UAAA;;;;;KAMf,UAAA,GAAa,UAAA;;;;;KAKb,gBAAA,GAAmB,UAAA;;;;;KAKnB,qBAAA,GAAwB,gBAAA;;;;;;ADsLpC;;;;;;;;KCvKY,MAAA,GAAS,UAAA;;;;;;;;;;;;;;;;;KAkBT,kBAAA,GAAqB,WAAA,CAAY,MAAA;;;;;;;;;;;;;;;;;;;UAoB5B,4BAAA;ED+KX;;;EC3KJ,cAAA;EDgLI;;;;EC1KJ,OAAA;EDiLM;;;;;EC1KN,UAAA;EDmLI;;;;;EC5KJ,KAAA;ED8KmB;;;ECzKnB,OAAA,GAAU,MAAA;EAhPW;;;;EAsPrB,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;AA3O5B;;;;;AAQA;;;;;AAKA;;;;;AAKA;;;;;AAQA;;;;;AAKA;;;;;AAgBA;;;;;AAKA;;;UAmOiB,iBAAA;EAnOwC;AAqCzD;;EAkME,WAAA,GAAc,WAAA;EAlMe;;;EAuM7B,MAAA,GAAS,MAAA;EAnMa;;AAsCxB;;;;EAqKE,MAAA,GAAS,YAAA;AAAA;;;;;AA1JX;;;;;AAKA;;;;;AAeA;;;UA0JiB,aAAA,SAAsB,iBAAA;EA1JR;AAkB/B;;;;;EA+IE,YAAA,IAAgB,IAAA,UAAc,IAAA;AAAA;;;;;;;;;;;;;;AA5ChC;;;;;;;UAmEiB,gBAAA,SAAyB,iBAAA;EA/DxC;;;EAmEA,YAAA;AAAA;;;;AAlCF;;;;;;;;;;UAkDiB,eAAA;EApBiB;;;EAwBhC,OAAA;EAJe;;;;EAUf,MAAA;EAAA;;;EAKA,WAAA,GAAc,WAAA;AAAA;AAQhB;;;;;AAAA,UAAiB,cAAA;EClYA;;;EDsYf,IAAA;AAAA;;AD1ZF;;UEoBiB,uBAAA;EACf,QAAA;EACA,OAAA;EACA,UAAA;EACA,cAAA;EACA,OAAA,QAAe,MAAA;EACf,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;AFmB5B;;;;;;cEiDa,iBAAA,YAA6B,eAAA;EAAA,SAC/B,oBAAA;EAAA,SACA,QAAA;EAAA,SACA,OAAA;EAAA,SACA,aAAA,EAAe,MAAA,SAAe,MAAA;EAAA,iBAEtB,MAAA;EAAA,iBACA,QAAA;EAAA,iBACA,QAAA;cAGf,QAAA,UACA,QAAA,EAAU,aAAA,cACV,MAAA,EAAQ,uBAAA;EFuMgB;;;;;;;;;EAAA,QErLlB,uBAAA;EF3EU;;;;EAAA,QEoKV,kBAAA;EAAA,QAiBA,eAAA;EAAA,QAoBA,gBAAA;EAAA,QAeA,kBAAA;EAIF,UAAA,CAAW,OAAA,EAAS,0BAAA,GAA6B,OAAA,CAAQ,6BAAA;EFjMlD;;;;EAAA,QEwOC,wBAAA;EA8CR,QAAA,CAAS,OAAA,EAAS,0BAAA,GAA6B,OAAA,CAAQ,2BAAA;AAAA;;AFnW/D;;;;;;;;UGyBiB,oBAAA;EHnBX;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCN;;;;;;EGcE,KAAA,CAAM,QAAA,UAAkB,QAAA,GAAW,aAAA,GAAgB,eAAA;EHmGhC;;;;;;;;;;;;;;;;EGjFnB,YAAA,IAAgB,OAAA,CAAQ,WAAA;EH3BpB;;;;;;;;;;;;;;;;;;;;;;EGmDJ,MAAA,CAAO,QAAA,EAAU,gBAAA,EAAkB,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,cAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8DxD,kBAAA,CAAmB,OAAA,EAAS,4BAAA,GAA+B,oBAAA;;AHnK3E;;;;iBISgB,YAAA,CACd,aAAA,EAAe,MAAA,8BACf,iBAAA,GAAoB,MAAA,mBACnB,MAAA;;;;;;iBAgBa,WAAA,CAAY,OAAA,UAAiB,UAAA,UAAoB,QAAA;;;;;;;;cAWpD,gBAAA,SAAyB,KAAA;EAAA,SAC3B,MAAA;EAAA,SACA,WAAA;EAAA,SACA,IAAA,EAAM,OAAA,CAAQ,qBAAA;cAEX,MAAA,UAAgB,OAAA;EAAA,eAQb,SAAA;AAAA;AAAA,cASJ,qBAAA;AAAA,KAED,cAAA;EACN,IAAA;AAAA;EACA,IAAA;AAAA;EACA,IAAA;AAAA;;;;AJrBN;;;;iBI8BgB,kBAAA,CAAmB,KAAA,YAAiB,cAAA;;;;;;;iBAqBpC,oBAAA,CAAqB,KAAA;AAAA,UAOpB,YAAA;EACf,GAAA;EACA,IAAA;EACA,OAAA,EAAS,MAAA;EACT,MAAA,GAAS,WAAA;EACT,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;;;;iBASN,QAAA,CAAS,OAAA,EAAS,YAAA,GAAe,OAAA,CAAQ,QAAA;;;;;;iBAuB/C,oBAAA,CACd,OAAA,WAAkB,KAAA;EAAQ,IAAA;EAAc,IAAA;AAAA;;;;;;iBAyC1B,eAAA,CAAgB,MAAA,uBAA6B,2BAAA;AAAA,KAiBjD,gBAAA;EACN,IAAA;EAAc,IAAA,EAAM,yBAAA;AAAA;EACpB,IAAA;EAAgB,YAAA,EAAc,2BAAA;AAAA;EAC9B,IAAA;EAAc,IAAA;EAAc,IAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;iBA0BlB,eAAA,CAAgB,IAAA,UAAc,aAAA,WAAwB,gBAAA;;;;;;;iBAuFhD,qBAAA,CACpB,YAAA,EAAc,cAAA,CAAe,UAAA,IAC5B,OAAA;;;;;;;;;;iBA+Ba,eAAA,CACd,YAAA,EAAc,cAAA,CAAe,UAAA,GAC7B,QAAA,EAAU,eAAA,IACV,MAAA,IAAU,IAAA,UAAc,IAAA,qBACvB,cAAA,CAAe,yBAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/generated/openapi.ts","../src/types.ts","../src/from-client.ts","../src/sanity-agent-language-model.ts","../src/sanity-agent-provider.ts","../src/studio.ts","../src/utils.ts"],"mappings":";;;;;AAKA;KAAY,KAAA;EACV,sCAAA;IACE,UAAA;MACE,KAAA;MACA,MAAA;MACA,IAAA;MACA,MAAA;IAAA;IAEF,GAAA;IACA,GAAA;IAAA;;;;;IAMA,IAAA,EAAM,UAAA;IACN,MAAA;IACA,OAAA;IACA,IAAA;IACA,KAAA;IACA,KAAA;EAAA;EAEF,SAAA;IACE,UAAA;MACE,KAAA;MACA,MAAA;MACA,IAAA;MACA,MAAA;IAAA;IAEF,GAAA;IACA,GAAA;IAUA;;;;AAKJ;IATI,IAAA,EAAM,UAAA;IACN,MAAA;IACA,OAAA;IACA,IAAA;IACA,KAAA;IACA,KAAA;EAAA;AAAA;AAAA,KAIQ,UAAA;EACV,OAAA;IACE,WAAA;MAiJsB,4CA/IpB,QAAA,EAAU,UAAA;MACV,WAAA,GAAc,UAAA;MACd,MAAA,GAAS,UAAA;MA6Ra;;;;MAxRtB,MAAA;MAPA;;;;;;;MAeA,MAAA;IAAA;IAEF,aAAA;MAUE;;;;MALA,cAAA;MAqBF;;;;MAhBE,OAAA;MACA,MAAA,GAAS,UAAA;MAkCT;;;;MA7BA,YAAA;MAiDA;;;;;;;MAzCA,MAAA;IAAA;IAEF,OAAA;MAmEE;;;;MA9DA,IAAA,mCA0EA;MAxEA,OAAA,UAyEA;MAvEA,EAAA,WAwEA;MAtEA,IAAA;IAAA,GAiFA;IA9EF,WAAA;MAsFsB;;;;MAjFpB,GAAA;MACA,QAAA;QAkHF;;;;QA7GI,EAAA;QAmIF;;;;QA9HE,IAAA;MAAA;MA8IJ;;;;;MAvIE,aAAA,WA8JA;MA5JA,aAAA,WA+JA;MA7JA,IAAA,WA6KsB;MA3KtB,KAAA,WAgLA;MA9KA,kBAAA;IAAA,GAwLE;IArLJ,MAAA;MAyLA;;;;MApLE,WAAA;MA+LsB;;;;;;;AAU5B;;MA/LM,kBAAA;QAAA,CACG,GAAA;MAAA;MAEH,YAAA,GAAe,UAAA;MACf,MAAA,GAAS,UAAA;MACT,YAAA,GAAe,UAAA;IAAA;IA6PV;;;;;;;;IAnPP,YAAA;MACE,IAAA,GAAO,UAAA;MACP,KAAA,GAAQ,UAAA;MACR,QAAA,GAAW,UAAA;IAAA;IAgMb;;;;IA1LA,gBAAA;MAiME;;;;MA5LA,SAAA;IAAA;IAmMI;;;;;;IA3LN,UAAA,YAAsB,UAAA;IACtB,gBAAA;MAiMO;;;;;;;;;;MAtLL,MAAA;IAAA,GAuMA;IApMF,MAAA;MAsMM;;;;;MAhMJ,IAAA;MAwMK;;;;;MAlML,KAAA;IAAA;;ACrNN;;;;ID4NI,YAAA;MCvNQ;;;;;AAMZ;;;MD0NM,IAAA;MC1NgC;AAQtC;;;;MDwNM,KAAA;IAAA,GCnNmB;IDsNrB,YAAA;MCtNkC,6CDwNhC,IAAA,WCnNM;MDqNN,cAAA;IAAA;IAEF,aAAA;MCvNoC;AAQxC;;;MDoNM,KAAA;MCpN0B;AAKhC;;;MDoNM,OAAA,WCpN2B;MDsN3B,MAAA,GAAS,UAAA;IAAA;IAEX,eAAA;MCxMgC;;AAKpC;;MDwMM,IAAA;MCxMmD;;AAqCzD;;;;MD0KM,IAAA;MCxKJ;;;;MD6KI,OAAA;IAAA;EAAA;EAGJ,SAAA;ICxImC,2DD0IjC,UAAA;MACE,OAAA;QAAA,CACG,IAAA;MAAA;MAEH,OAAA;QCnIM;;;;;AAKZ;;;;;AAeA;;;;;QD+HQ,kBAAA,EAAoB,UAAA;MAAA;IAAA,GC7GiB;IDiHzC,YAAA;MACE,OAAA;QAAA,CACG,IAAA;MAAA;MAEH,OAAA;QCvDM;;;;;;QD8DJ,kBAAA,EAAoB,UAAA;MAAA;IAAA,GCnE1B;IDuEE,mBAAA;MACE,OAAA;QAAA,CACG,IAAA;MAAA;MAEH,OAAA;QChE2B;;AA4CjC;;;;QD2BQ,kBAAA,EAAoB,UAAA;MAAA;IAAA;EAAA;EAI1B,UAAA;EACA,aAAA;EACA,OAAA;EACA,SAAA;AAAA;AAAA,UAGe,UAAA;EACf,IAAA;IACE,UAAA;MACE,KAAA;MACA,MAAA;MACA,IAAA;QCLiC;;;;QDU/B,cAAA;QCHqC;AAuB7C;;;QDfQ,QAAA;MAAA;MAEF,MAAA;IAAA;IAEF,WAAA;MACE,OAAA;QACE,kBAAA,EAAoB,UAAA;MAAA;IAAA;IAGxB,SAAA;MCyCuB,sCDvCrB,GAAA;QACE,OAAA;UACE,cAAA;UACA,yBAAA;UAAA,CACC,IAAA;QAAA;QAEH,OAAA;UACE,mBAAA,UEtXkB;UFwXlB,kBAAA,EAAoB,UAAA;QAAA;MAAA;MAGxB,GAAA,EAAK,UAAA;MACL,GAAA,EAAK,UAAA;MACL,GAAA,EAAK,UAAA;IAAA;EAAA;EAGT,MAAA;IACE,UAAA;MACE,KAAA;MACA,MAAA;MACA,IAAA;MACA,MAAA;IAAA;IAEF,WAAA;MACE,OAAA;QACE,kBAAA,EAAoB,UAAA;MAAA;IAAA;IAGxB,SAAA;MEvWwE,sCFyWtE,GAAA;QACE,OAAA;UACE,cAAA;UACA,yBAAA;UAAA,CACC,IAAA;QAAA;QAEH,OAAA;UACE,mBAAA;QAAA;MAAA;MAGJ,GAAA,EAAK,UAAA;MACL,GAAA,EAAK,UAAA;MACL,GAAA,EAAK,UAAA;IAAA;EAAA;AAAA;;;;;KCzZC,WAAA,GAAc,UAAA;;;;;KAKd,eAAA,GAAkB,UAAA;;;;;KAMlB,YAAA,GAAe,WAAA;;;;;KAQf,YAAA,GAAe,UAAA;;;;;KAKf,aAAA,GAAgB,UAAA;;;;;KAKhB,eAAA,GAAkB,UAAA;;;;;KAQlB,OAAA,GAAU,UAAA;ADEtB;;;;AAAA,KCGY,WAAA,GAAc,OAAA;;;;;;;;;;;;;KAgBd,WAAA,GAAc,UAAA;;;;;KAKd,mBAAA,GAAsB,WAAA,CAAY,WAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqClC,MAAA,GAAS,UAAA;EDoDA,wKClDnB,YAAA,sBDmDa;ECjDb,sBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsCU,YAAA,GAAe,UAAA;;;;;KAMf,UAAA,GAAa,UAAA;;;;;KAKb,gBAAA,GAAmB,UAAA;;;;;KAKnB,qBAAA,GAAwB,gBAAA;;;;;;ADsLpC;;;;;;;;KCvKY,MAAA,GAAS,UAAA;;;;;;;;;;;;;;;;;KAkBT,kBAAA,GAAqB,WAAA,CAAY,MAAA;;;;;;;;;;;;;;;;;;;UAoB5B,4BAAA;ED+KX;;;;;;ECxKJ,cAAA;EDiLE;;;;;;;;ECvKF,WAAA,GAAc,WAAA;EDmLL;;;;EC7KT,OAAA;ED+KmB;;;ACzZrB;;EAiPE,UAAA;EAjPwB;;AAK1B;;;EAmPE,KAAA;EAnPsC;AAMxC;;EAkPE,OAAA,GAAU,MAAA;EAlPe;;AAQ3B;;EAgPE,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;AA3O5B;;;;;AAKA;;;;;AAQA;;;;;AAKA;;;;;AAgBA;;;;;AAKA;;;;;AAqCA;;;;;;;;;AA0CA;UAiKiB,iBAAA;;;;EAIf,WAAA,GAAc,WAAA;EA/JM;;;EAoKpB,MAAA,GAAS,MAAA;EA/JC;;;;;AAKZ;EAkKE,MAAA,GAAS,YAAA;AAAA;;;AAnJX;;;;;AAkBA;;;;;AAoBA;;;;;UAiIiB,aAAA,SAAsB,iBAAA;EAjFN;;;;;;EAwF/B,YAAA,IAAgB,IAAA,UAAc,IAAA;AAAA;;;;;;;;AA5ChC;;;;;;;;;;;;;UAmEiB,gBAAA,SAAyB,iBAAA;EAlDnB;;AAoBvB;EAkCE,YAAA;AAAA;;;;;;;;AAJF;;;;;AAoBA;UAAiB,eAAA;;;;EAIf,OAAA;EAWA;;;;EALA,MAAA;EAa6B;;;EAR7B,WAAA,GAAc,WAAA;AAAA;ACtZhB;;;;;AAAA,UD8ZiB,cAAA;EC7ZiB;;;EDiahC,IAAA;AAAA;;;ADvaF;;;;KEKY,gBAAA;EACV,MAAA;IAAY,SAAA;IAAoB,OAAA;IAAkB,OAAA;EAAA;AAAA;;;;;;KAQxC,mBAAA;EFKR;;;;;;EEEF,OAAA;EFMI;;;;;;EEEJ,WAAA,EAAa,WAAA;AAAA;;;;;AFgBf;;;;;;iBEHgB,aAAA,CAAc,OAAA,sBAA6B,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwC3C,UAAA,CAAW,MAAA,EAAQ,gBAAA,EAAkB,SAAA,WAAoB,mBAAA;;AFlFzE;;UGoBiB,uBAAA;EACf,QAAA;EACA,OAAA;EACA,UAAA;EACA,cAAA;EACA,OAAA,QAAe,MAAA;EACf,WAAA,GAAc,kBAAA;EACd,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;AHkB5B;;;;;;;cGkDa,iBAAA,YAA6B,eAAA;EAAA,SAC/B,oBAAA;EAAA,SACA,QAAA;EAAA,SACA,OAAA;EAAA,SACA,aAAA,EAAe,MAAA,SAAe,MAAA;EAAA,iBAEtB,MAAA;EAAA,iBACA,QAAA;EAAA,iBACA,QAAA;cAGf,QAAA,UACA,QAAA,EAAU,aAAA,cACV,MAAA,EAAQ,uBAAA;EHqNgB;;;;;;;;;EAAA,QGnMlB,uBAAA;EH3EJ;;;;EAAA,QGoKI,kBAAA;EAAA,QAiBA,eAAA;EAAA,QAoBA,gBAAA;EAAA,QAeA,kBAAA;EAIF,UAAA,CAAW,OAAA,EAAS,0BAAA,GAA6B,OAAA,CAAQ,6BAAA;EH7L3D;;;;EAAA,QGqOU,wBAAA;EA8CR,QAAA,CAAS,OAAA,EAAS,0BAAA,GAA6B,OAAA,CAAQ,2BAAA;AAAA;AHrW/D;;;;;;;;;AAAA,UI0BiB,oBAAA;EJlBb;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCJ;;;;;;;EIeE,KAAA,CAAM,QAAA,UAAkB,QAAA,GAAW,aAAA,GAAgB,eAAA;EJmGtC;;;;;;;;;;;;;;;;EIjFb,YAAA,IAAgB,OAAA,CAAQ,WAAA;EJ5BN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EI8DlB,kBAAA,CAAmB,MAAA,EAAQ,gBAAA,EAAkB,SAAA,WAAoB,OAAA,CAAQ,WAAA;EJ+CrE;;;;;;;;;;;;;;;;;;;;;;EIvBJ,MAAA,CAAO,QAAA,EAAU,gBAAA,EAAkB,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,cAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AJkNxE;;;;;;;;;;;;;;;;;;;;;;;iBIpJgB,kBAAA,CAAmB,OAAA,EAAS,4BAAA,GAA+B,oBAAA;AJtM3E;;;;;AAAA,KKqBY,kBAAA;ELlBN;;;EKsBJ,KAAA,UAAe,UAAA,CAAW,KAAA;ELjBxB;;;;;EKwBF,eAAA,GAAkB,IAAA,CAAK,4BAAA;AAAA;;;;;;;;;;;;;;;;;;;;ALazB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBKiKgB,iBAAA,CACd,MAAA,EAAQ,gBAAA,EACR,SAAA,UACA,OAAA,GAAU,kBAAA,GACT,oBAAA;;ALlNH;;;;iBMSgB,YAAA,CACd,aAAA,EAAe,MAAA,8BACf,iBAAA,GAAoB,MAAA,mBACnB,MAAA;;;;;;iBAgBa,WAAA,CAAY,OAAA,UAAiB,UAAA,UAAoB,QAAA;;;;;;;;cAWpD,gBAAA,SAAyB,KAAA;EAAA,SAC3B,MAAA;EAAA,SACA,WAAA;EAAA,SACA,IAAA,EAAM,OAAA,CAAQ,qBAAA;cAEX,MAAA,UAAgB,OAAA;EAAA,eAQb,SAAA;AAAA;;;;;;;;;;;cAmBJ,sBAAA,SAA+B,KAAA;EAAA,SACjC,IAAA;cAEG,OAAA,UAAiB,IAAA;AAAA;AAAA,cAOlB,qBAAA;AAAA,KAED,cAAA;EACN,IAAA;AAAA;EACA,IAAA;AAAA;EACA,IAAA;AAAA;EACA,IAAA;AAAA;EACA,IAAA;AAAA;EACA,IAAA;AAAA;EACA,IAAA;AAAA;;;;;;;;iBA4BU,kBAAA,CAAmB,KAAA,YAAiB,cAAA;AAAA,iBAiBpC,iBAAA,CAAkB,UAAA,EAAY,cAAA;AAAA,KAIlC,wBAAA;EACV,OAAA;AAAA;;;;;;;;;iBAWoB,wBAAA,CACpB,UAAA,EAAY,cAAA,EACZ,KAAA,WACA,cAAA,SAAuB,OAAA,CAAQ,wBAAA,IAC9B,OAAA;;;;;;;iBAwBa,oBAAA,CAAqB,KAAA;AAAA,UAUpB,YAAA;EACf,GAAA;EACA,IAAA;EACA,OAAA,EAAS,MAAA;EACT,WAAA,GAAc,kBAAA;EACd,MAAA,GAAS,WAAA;EACT,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;;;;iBASN,QAAA,CAAS,OAAA,EAAS,YAAA,GAAe,OAAA,CAAQ,QAAA;;;;;;iBAwB/C,oBAAA,CACd,OAAA,WAAkB,KAAA;EAAQ,IAAA;EAAc,IAAA;AAAA;;;;;;iBAyC1B,eAAA,CAAgB,MAAA,uBAA6B,2BAAA;AAAA,KAiBjD,gBAAA;EACN,IAAA;EAAc,IAAA,EAAM,yBAAA;AAAA;EACpB,IAAA;EAAgB,YAAA,EAAc,2BAAA;AAAA;EAC9B,IAAA;EAAc,IAAA;EAAc,IAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;iBA0BlB,eAAA,CAAgB,IAAA,UAAc,aAAA,WAAwB,gBAAA;;;;;;;iBAyFhD,qBAAA,CACpB,YAAA,EAAc,cAAA,CAAe,UAAA,IAC5B,OAAA;;;;;;;;;;iBA+Ba,eAAA,CACd,YAAA,EAAc,cAAA,CAAe,UAAA,GAC7B,QAAA,EAAU,eAAA,IACV,MAAA,IAAU,IAAA,UAAc,IAAA,qBACvB,cAAA,CAAe,yBAAA"}
package/dist/index.js CHANGED
@@ -1,5 +1,27 @@
1
1
  import { pickBy, isString, groupBy } from "es-toolkit";
2
2
  import { ERROR_CODES } from "@sanity/agent-types";
3
+ const DEFAULT_API_HOST = "https://api.sanity.io";
4
+ function deriveBaseUrl(apiHost, projectId) {
5
+ const url = new URL(apiHost || DEFAULT_API_HOST);
6
+ return url.hostname = `${projectId}.${url.hostname}`, url.origin;
7
+ }
8
+ function fromClient(client, workspace) {
9
+ const { projectId, dataset, apiHost } = client.config();
10
+ if (!projectId)
11
+ throw new Error("fromClient: client is missing `projectId` in its config");
12
+ if (!dataset)
13
+ throw new Error("fromClient: client is missing `dataset` in its config");
14
+ return {
15
+ baseURL: deriveBaseUrl(apiHost, projectId),
16
+ application: {
17
+ name: workspace,
18
+ resource: {
19
+ id: `${projectId}.${dataset}`,
20
+ type: "dataset"
21
+ }
22
+ }
23
+ };
24
+ }
3
25
  function buildHeaders(configHeaders, additionalHeaders) {
4
26
  return pickBy(
5
27
  {
@@ -28,28 +50,61 @@ class SanityAgentError extends Error {
28
50
  }
29
51
  }
30
52
  }
53
+ class SanityAgentStreamError extends Error {
54
+ code;
55
+ constructor(message, code) {
56
+ super(message), this.name = "SanityAgentStreamError", this.code = code;
57
+ }
58
+ }
31
59
  const GENERIC_ERROR_MESSAGE = "Sorry, something went wrong. Please try again.";
32
- function classifyAgentError(error) {
33
- if (!(error instanceof SanityAgentError) || error.status !== 400)
34
- return { type: "unknown" };
35
- switch (error.body.code) {
60
+ function mapErrorCode(code) {
61
+ switch (code) {
36
62
  case ERROR_CODES.NO_COMPATIBLE_APPLICATIONS:
37
63
  return { type: "no_applications" };
38
64
  case ERROR_CODES.APPLICATION_NOT_FOUND:
39
65
  return { type: "application_not_found" };
66
+ case ERROR_CODES.UPSTREAM_OVERLOADED:
67
+ return { type: "upstream_overloaded" };
68
+ case ERROR_CODES.UPSTREAM_ERROR:
69
+ return { type: "upstream_error" };
70
+ case ERROR_CODES.AI_USAGE_LIMIT_EXCEEDED:
71
+ return { type: "usage_limit_exceeded" };
72
+ case ERROR_CODES.STREAMING_ERROR:
73
+ return { type: "streaming_error" };
74
+ default:
75
+ return null;
76
+ }
77
+ }
78
+ function classifyAgentError(error) {
79
+ return error instanceof SanityAgentStreamError && error.code ? mapErrorCode(error.code) ?? { type: "unknown" } : error instanceof SanityAgentError ? error.status !== 400 ? { type: "unknown" } : mapErrorCode(error.body.code) ?? { type: "unknown" } : { type: "unknown" };
80
+ }
81
+ function isAppRelatedError(classified) {
82
+ return classified.type === "no_applications" || classified.type === "application_not_found";
83
+ }
84
+ async function resolveAgentErrorMessage(classified, error, resolveContext) {
85
+ const fallback = getAgentErrorMessage(error);
86
+ if (!resolveContext || !isAppRelatedError(classified)) return fallback;
87
+ const ctx = await resolveContext();
88
+ if (!ctx.orgName) return fallback;
89
+ switch (classified.type) {
90
+ case "no_applications":
91
+ return `Studio action required: To use the Content Agent in "${ctx.orgName}", you must have at least one Sanity Studio running version 5.1.0 or above. After upgrading, open your studio to connect it to the agent.`;
92
+ case "application_not_found":
93
+ return `The requested studio is not available in "${ctx.orgName}". You may not have access, or it may belong to a different organization.`;
40
94
  default:
41
- return { type: "unknown" };
95
+ return fallback;
42
96
  }
43
97
  }
44
98
  function getAgentErrorMessage(error) {
45
- return error instanceof SanityAgentError && error.body.message ? error.body.message : GENERIC_ERROR_MESSAGE;
99
+ return error instanceof SanityAgentStreamError ? error.message : error instanceof SanityAgentError && error.body.message ? error.body.message : GENERIC_ERROR_MESSAGE;
46
100
  }
47
101
  async function fetchApi(options) {
48
102
  const response = await (options.fetch ?? globalThis.fetch)(options.url, {
49
103
  method: "POST",
50
104
  headers: options.headers,
51
105
  body: JSON.stringify(options.body),
52
- signal: options.signal
106
+ signal: options.signal,
107
+ ...options.credentials && { credentials: options.credentials }
53
108
  });
54
109
  if (!response.ok) {
55
110
  const errorText = await response.text();
@@ -127,14 +182,16 @@ function parseStreamLine(line, textContentId) {
127
182
  }
128
183
  };
129
184
  }
130
- case "error":
185
+ case "error": {
186
+ const errorText = part.errorText ?? "Unknown error", errorCode = part.errorCode;
131
187
  return {
132
188
  kind: "part",
133
189
  part: {
134
190
  type: "error",
135
- error: new Error(part.errorText ?? "Unknown error")
191
+ error: new SanityAgentStreamError(errorText, errorCode)
136
192
  }
137
193
  };
194
+ }
138
195
  case "abort":
139
196
  return { kind: "data", type: "abort", data: { reason: part.reason } };
140
197
  case "finish":
@@ -320,6 +377,7 @@ class ContentAgentModel {
320
377
  ),
321
378
  body,
322
379
  headers: buildHeaders(this.config.headers()),
380
+ credentials: this.config.credentials,
323
381
  signal: options.abortSignal,
324
382
  fetch: this.config.fetch
325
383
  });
@@ -377,6 +435,7 @@ class ContentAgentModel {
377
435
  ),
378
436
  body,
379
437
  headers: buildHeaders(this.config.headers()),
438
+ credentials: this.config.credentials,
380
439
  signal: options.abortSignal,
381
440
  fetch: this.config.fetch
382
441
  });
@@ -394,27 +453,58 @@ function createContentAgent(options) {
394
453
  const baseURL = options.baseURL?.replace(/\/$/, "") ?? DEFAULT_BASE_URL, apiVersion = options.apiVersion ?? DEFAULT_API_VERSION, { organizationId } = options, getHeaders = () => ({
395
454
  ...options.token && { Authorization: `Bearer ${options.token}` },
396
455
  ...options.headers
397
- }), config = {
456
+ }), credentials = options.token ? void 0 : "include", config = {
398
457
  provider: "content-agent",
399
458
  baseURL,
400
459
  apiVersion,
401
460
  organizationId,
402
461
  headers: getHeaders,
462
+ credentials,
403
463
  fetch: options.fetch
404
- };
405
- return { agent: (threadId, settings) => new ContentAgentModel(threadId, settings, config), applications: async () => {
406
- const fetchFn = options.fetch ?? globalThis.fetch, url = buildApiUrl(baseURL, apiVersion, `/${organizationId}/applications`), headers = buildHeaders(getHeaders()), response = await fetchFn(url, { method: "GET", headers });
464
+ }, agent = (threadId, settings) => new ContentAgentModel(
465
+ threadId,
466
+ {
467
+ ...settings,
468
+ application: settings?.application ?? options.application
469
+ },
470
+ config
471
+ );
472
+ let applicationsPromise = null;
473
+ const applications = () => (applicationsPromise || (applicationsPromise = (async () => {
474
+ const fetchFn = options.fetch ?? globalThis.fetch, url = buildApiUrl(baseURL, apiVersion, `/${organizationId}/applications`), headers = buildHeaders(getHeaders()), response = await fetchFn(url, {
475
+ method: "GET",
476
+ headers,
477
+ ...credentials && { credentials }
478
+ });
407
479
  if (!response.ok) {
480
+ applicationsPromise = null;
408
481
  const errorText = await response.text();
409
482
  throw new SanityAgentError(response.status, errorText);
410
483
  }
411
484
  return (await response.json()).applications ?? [];
485
+ })()), applicationsPromise);
486
+ return { agent, applications, resolveApplication: async (client, workspace) => {
487
+ const { projectId, dataset } = client.config();
488
+ if (!projectId || !dataset)
489
+ throw new Error(
490
+ "resolveApplication: client is missing `projectId` or `dataset` in its config"
491
+ );
492
+ const resourceId = `${projectId}.${dataset}`, match = (await applications()).find((app) => app.resource?.id === resourceId && app.name === workspace);
493
+ if (!match)
494
+ throw new SanityAgentError(
495
+ 400,
496
+ JSON.stringify({
497
+ code: "APPLICATION_NOT_FOUND",
498
+ message: `No application found for resource "${resourceId}" with workspace "${workspace}". Make sure the Studio has been deployed and belongs to this organization.`
499
+ })
500
+ );
501
+ return match;
412
502
  }, prompt: async (settings, generateOptions) => {
413
- const body = {
503
+ const effectiveApplication = settings.application ?? options.application, body = {
414
504
  organizationId,
415
505
  message: generateOptions.message,
416
506
  stream: generateOptions.stream ?? !1,
417
- ...settings.application && { application: settings.application },
507
+ ...effectiveApplication && { application: effectiveApplication },
418
508
  ...settings.config && { config: settings.config },
419
509
  ...settings.instructions && { instructions: settings.instructions },
420
510
  ...settings.format && { format: settings.format }
@@ -422,6 +512,7 @@ function createContentAgent(options) {
422
512
  url: buildApiUrl(baseURL, apiVersion, "/prompt"),
423
513
  body,
424
514
  headers: buildHeaders(getHeaders()),
515
+ credentials,
425
516
  signal: generateOptions.abortSignal,
426
517
  fetch: options.fetch
427
518
  });
@@ -433,20 +524,130 @@ function createContentAgent(options) {
433
524
  return { text: (await response.json()).text ?? "" };
434
525
  } };
435
526
  }
527
+ const PROJECTS_API_VERSION = "v2024-01-01", providerCache = /* @__PURE__ */ new Map();
528
+ async function fetchOrganizationId(apiHost, projectId, fetchFn) {
529
+ const url = `${apiHost}/${PROJECTS_API_VERSION}/projects/${projectId}`, response = await fetchFn(url, {
530
+ method: "GET",
531
+ headers: buildHeaders({}),
532
+ credentials: "include"
533
+ });
534
+ if (!response.ok) {
535
+ const errorText = await response.text();
536
+ throw new SanityAgentError(
537
+ response.status,
538
+ JSON.stringify({
539
+ code: "PROJECT_FETCH_FAILED",
540
+ message: `Failed to fetch project "${projectId}": ${errorText}`
541
+ })
542
+ );
543
+ }
544
+ const project = await response.json();
545
+ if (!project.organizationId)
546
+ throw new SanityAgentError(
547
+ 400,
548
+ JSON.stringify({
549
+ code: "NO_ORGANIZATION",
550
+ message: `Project "${projectId}" is not assigned to an organization. Content Agent requires an organization-level project.`
551
+ })
552
+ );
553
+ return project.organizationId;
554
+ }
555
+ function initProvider(projectId, dataset, workspace, apiHost, baseURL, fetchFn, providerOptions) {
556
+ return fetchOrganizationId(apiHost, projectId, fetchFn).then(async (organizationId) => {
557
+ const tempProvider = createContentAgent({
558
+ organizationId,
559
+ baseURL,
560
+ fetch: fetchFn
561
+ }), client = { config: () => ({ projectId, dataset }) }, application = await tempProvider.resolveApplication(client, workspace);
562
+ return createContentAgent({
563
+ ...providerOptions,
564
+ organizationId,
565
+ baseURL,
566
+ application
567
+ });
568
+ });
569
+ }
570
+ class LazyContentAgentModel {
571
+ specificationVersion = "v3";
572
+ provider = "content-agent";
573
+ modelId;
574
+ supportedUrls = {};
575
+ providerPromise;
576
+ threadId;
577
+ settings;
578
+ resolvedModel = null;
579
+ constructor(threadId, settings, providerPromise) {
580
+ this.threadId = threadId, this.settings = settings, this.modelId = `content-agent:${threadId}`, this.providerPromise = providerPromise;
581
+ }
582
+ async getModel() {
583
+ if (!this.resolvedModel) {
584
+ const provider = await this.providerPromise;
585
+ this.resolvedModel = provider.agent(this.threadId, this.settings);
586
+ }
587
+ return this.resolvedModel;
588
+ }
589
+ async doGenerate(options) {
590
+ return (await this.getModel()).doGenerate(options);
591
+ }
592
+ async doStream(options) {
593
+ return (await this.getModel()).doStream(options);
594
+ }
595
+ }
596
+ function createStudioAgent(client, workspace, options) {
597
+ const { projectId, dataset } = client.config();
598
+ if (!projectId)
599
+ throw new Error("createStudioAgent: client is missing `projectId` in its config");
600
+ if (!dataset)
601
+ throw new Error("createStudioAgent: client is missing `dataset` in its config");
602
+ const { apiHost } = client.config(), fetchFn = options?.fetch ?? globalThis.fetch, baseURL = deriveBaseUrl(apiHost, projectId), cacheKey = `${projectId}.${dataset}.${workspace}`, useCache = !options?.fetch && !options?.providerOptions;
603
+ let providerPromise;
604
+ useCache && providerCache.has(cacheKey) ? providerPromise = providerCache.get(cacheKey) : (providerPromise = initProvider(
605
+ projectId,
606
+ dataset,
607
+ workspace,
608
+ apiHost || "https://api.sanity.io",
609
+ baseURL,
610
+ fetchFn,
611
+ options?.providerOptions
612
+ ), useCache && (providerCache.set(cacheKey, providerPromise), providerPromise.catch(() => {
613
+ providerCache.delete(cacheKey);
614
+ })));
615
+ const awaitProvider = async (fn) => fn(await providerPromise);
616
+ return {
617
+ agent(threadId, settings) {
618
+ return new LazyContentAgentModel(threadId, settings, providerPromise);
619
+ },
620
+ applications() {
621
+ return awaitProvider((p) => p.applications());
622
+ },
623
+ resolveApplication(resolveClient, resolveWorkspace) {
624
+ return awaitProvider((p) => p.resolveApplication(resolveClient, resolveWorkspace));
625
+ },
626
+ prompt(settings, generateOptions) {
627
+ return awaitProvider((p) => p.prompt(settings, generateOptions));
628
+ }
629
+ };
630
+ }
436
631
  export {
437
632
  ContentAgentModel,
438
633
  GENERIC_ERROR_MESSAGE,
439
634
  SanityAgentError,
635
+ SanityAgentStreamError,
440
636
  buildApiUrl,
441
637
  buildHeaders,
442
638
  classifyAgentError,
443
639
  createContentAgent,
444
640
  createSSEStream,
641
+ createStudioAgent,
642
+ deriveBaseUrl,
445
643
  extractTextFromParts,
446
644
  extractTextFromStream,
447
645
  fetchApi,
646
+ fromClient,
448
647
  getAgentErrorMessage,
648
+ isAppRelatedError,
449
649
  mapFinishReason,
450
- parseStreamLine
650
+ parseStreamLine,
651
+ resolveAgentErrorMessage
451
652
  };
452
653
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/utils.ts","../src/sanity-agent-language-model.ts","../src/sanity-agent-provider.ts"],"sourcesContent":["import type {\n LanguageModelV3FinishReason,\n LanguageModelV3StreamPart,\n LanguageModelV3Usage,\n SharedV3Warning,\n} from '@ai-sdk/provider'\nimport { ERROR_CODES, type HeadlessErrorResponse } from '@sanity/agent-types'\nimport { isString, pickBy } from 'es-toolkit'\n\n/**\n * Builds headers for API requests, filtering out undefined values.\n *\n * @category Utilities\n */\nexport function buildHeaders(\n configHeaders: Record<string, string | undefined>,\n additionalHeaders?: Record<string, string>,\n): Record<string, string> {\n return pickBy(\n {\n 'Content-Type': 'application/json',\n ...additionalHeaders,\n ...configHeaders,\n },\n isString,\n )\n}\n\n/**\n * Constructs the full API URL for an endpoint.\n *\n * @category Utilities\n */\nexport function buildApiUrl(baseURL: string, apiVersion: string, endpoint: string): string {\n return `${baseURL}/${apiVersion}/agent${endpoint}`\n}\n\n/**\n * Custom error class for Sanity Agent API errors.\n * The {@link body} is parsed from the JSON response and follows the\n * {@link HeadlessErrorResponse} shape defined in `@sanity/agent-types`.\n *\n * @category Utilities\n */\nexport class SanityAgentError extends Error {\n readonly status: number\n readonly isRetryable: boolean\n readonly body: Partial<HeadlessErrorResponse>\n\n constructor(status: number, message: string) {\n super(`Sanity Agent API error: ${status} ${message}`)\n this.name = 'SanityAgentError'\n this.status = status\n this.isRetryable = status >= 500\n this.body = SanityAgentError.parseBody(message)\n }\n\n private static parseBody(message: string): Partial<HeadlessErrorResponse> {\n try {\n return JSON.parse(message)\n } catch {\n return {}\n }\n }\n}\n\nexport const GENERIC_ERROR_MESSAGE = 'Sorry, something went wrong. Please try again.'\n\nexport type AgentErrorType =\n | { type: 'no_applications' }\n | { type: 'application_not_found' }\n | { type: 'unknown' }\n\n/**\n * Classifies a caught error from the Content Agent API into a known error type.\n * Useful for clients that need to take different actions per error (e.g. show\n * resource-selection buttons). For the user-facing message, use {@link getAgentErrorMessage}.\n *\n * @category Utilities\n */\nexport function classifyAgentError(error: unknown): AgentErrorType {\n if (!(error instanceof SanityAgentError) || error.status !== 400) {\n return { type: 'unknown' }\n }\n\n switch (error.body.code) {\n case ERROR_CODES.NO_COMPATIBLE_APPLICATIONS:\n return { type: 'no_applications' }\n case ERROR_CODES.APPLICATION_NOT_FOUND:\n return { type: 'application_not_found' }\n default:\n return { type: 'unknown' }\n }\n}\n\n/**\n * Extracts a user-facing error message from an agent API error.\n * Returns the message sent by the API when available, otherwise a generic fallback.\n *\n * @category Utilities\n */\nexport function getAgentErrorMessage(error: unknown): string {\n if (error instanceof SanityAgentError && error.body.message) {\n return error.body.message\n }\n return GENERIC_ERROR_MESSAGE\n}\n\nexport interface FetchOptions {\n url: string\n body: unknown\n headers: Record<string, string>\n signal?: AbortSignal\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Makes a POST request and returns the response.\n * Throws SanityAgentError if the response is not ok.\n *\n * @category Utilities\n */\nexport async function fetchApi(options: FetchOptions): Promise<Response> {\n const fetchFn = options.fetch ?? globalThis.fetch\n\n const response = await fetchFn(options.url, {\n method: 'POST',\n headers: options.headers,\n body: JSON.stringify(options.body),\n signal: options.signal,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new SanityAgentError(response.status, errorText)\n }\n\n return response\n}\n\n/**\n * Extracts text content from message parts (user or assistant).\n *\n * @category Utilities\n */\nexport function extractTextFromParts(\n content: string | Array<{ type: string; text?: string }>,\n): string {\n if (typeof content === 'string') {\n return content\n }\n\n return content\n .filter(\n (part): part is { type: 'text'; text: string } =>\n part.type === 'text' && typeof part.text === 'string',\n )\n .map((part) => part.text)\n .join('\\n')\n}\n\n/**\n * Creates an empty V3 usage object. Our API does not return token counts.\n *\n * @category Utilities\n */\nexport function createEmptyUsage(): LanguageModelV3Usage {\n return {\n inputTokens: {\n total: 0,\n noCache: undefined,\n cacheRead: undefined,\n cacheWrite: undefined,\n },\n outputTokens: {\n total: 0,\n text: undefined,\n reasoning: undefined,\n },\n }\n}\n\n/**\n * Maps API finish reasons to LanguageModelV3FinishReason.\n *\n * @category Utilities\n */\nexport function mapFinishReason(reason: string | undefined): LanguageModelV3FinishReason {\n const unified = (() => {\n switch (reason) {\n case 'stop':\n case 'length':\n case 'content-filter':\n case 'tool-calls':\n case 'error':\n return reason\n default:\n return 'other' as const\n }\n })()\n\n return { unified, raw: reason }\n}\n\nexport type ParsedStreamLine =\n | { kind: 'part'; part: LanguageModelV3StreamPart }\n | { kind: 'finish'; finishReason: LanguageModelV3FinishReason }\n | { kind: 'data'; type: string; data: unknown }\n\n/**\n * Parses a single SSE line from the AI SDK v6 UI Message Stream protocol.\n * Returns null if the line cannot be parsed or should be ignored.\n *\n * Format: `data: <json>\\n`\n *\n * Supported types:\n * text-start – Text block start (forwarded as-is)\n * text-delta – Text chunk\n * text-end – Text block end (forwarded as-is)\n * tool-input-available – Tool call (client tools only, without providerExecuted)\n * tool-output-available – Tool result (informational, skipped)\n * finish – Finish event with reason\n * error – Error event\n * start – Stream start (skipped)\n * [DONE] – Stream termination (skipped)\n *\n * @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol\n *\n * @param line A single line from the SSE byte stream.\n * @param textContentId Fallback ID for text parts that lack an explicit id.\n *\n * @category Utilities\n */\nexport function parseStreamLine(line: string, textContentId: string): ParsedStreamLine | null {\n const trimmed = line.trim()\n if (!trimmed.startsWith('data: ')) return null\n\n const payload = trimmed.slice(6)\n if (payload === '[DONE]') return null\n\n let part: Record<string, unknown>\n try {\n part = JSON.parse(payload) as Record<string, unknown>\n } catch {\n return null\n }\n\n const type = part.type as string | undefined\n if (!type) return null\n\n switch (type) {\n case 'text-start': {\n const id = (part.id as string) || textContentId\n return { kind: 'part', part: { type: 'text-start', id } }\n }\n\n case 'text-delta': {\n const id = (part.id as string) || textContentId\n const delta = part.delta as string\n if (typeof delta !== 'string') return null\n return { kind: 'part', part: { type: 'text-delta', id, delta } }\n }\n\n case 'text-end': {\n const id = (part.id as string) || textContentId\n return { kind: 'part', part: { type: 'text-end', id } }\n }\n\n case 'tool-input-available': {\n // Skip server-executed tools — only forward client tools for local execution.\n if (part.providerExecuted) return null\n\n const input = part.input\n return {\n kind: 'part',\n part: {\n type: 'tool-call',\n toolCallId: part.toolCallId as string,\n toolName: part.toolName as string,\n input: typeof input === 'string' ? input : JSON.stringify(input),\n },\n }\n }\n\n case 'error': {\n return {\n kind: 'part',\n part: {\n type: 'error',\n error: new Error((part.errorText as string) ?? 'Unknown error'),\n },\n }\n }\n\n case 'abort': {\n return { kind: 'data', type: 'abort', data: { reason: part.reason } }\n }\n\n case 'finish': {\n return {\n kind: 'finish',\n finishReason: mapFinishReason(part.finishReason as string | undefined),\n }\n }\n\n default: {\n if (type.startsWith('data-')) {\n return { kind: 'data', type: type.slice(5), data: part.data }\n }\n return null\n }\n }\n}\n\n/**\n * Extracts accumulated text from a streaming response body.\n * Used for simple streaming cases where only the final text is needed.\n *\n * @category Utilities\n */\nexport async function extractTextFromStream(\n responseBody: ReadableStream<Uint8Array>,\n): Promise<string> {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\n const textContentId = 'extract'\n let text = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n for (const line of chunk.split('\\n')) {\n const parsed = parseStreamLine(line, textContentId)\n if (parsed?.kind === 'part' && parsed.part.type === 'text-delta') {\n text += parsed.part.delta\n }\n }\n }\n\n return text\n}\n\n/**\n * Creates a ReadableStream that parses AI SDK v6 UI Message Stream SSE data\n * from a response body and emits LanguageModelV3 stream parts.\n *\n * Text lifecycle events (text-start / text-end) are forwarded from the server.\n * Tool calls are tracked to ensure the finish reason is set correctly.\n *\n * @category Utilities\n */\nexport function createSSEStream(\n responseBody: ReadableStream<Uint8Array>,\n warnings: SharedV3Warning[],\n onData?: (type: string, data: unknown) => void,\n): ReadableStream<LanguageModelV3StreamPart> {\n let finishReason: LanguageModelV3FinishReason = { unified: 'other', raw: undefined }\n const fallbackTextId = crypto.randomUUID()\n let hasToolCalls = false\n\n return new ReadableStream<LanguageModelV3StreamPart>({\n async start(controller) {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n controller.enqueue({ type: 'stream-start', warnings })\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n\n for (const line of lines) {\n const parsed = parseStreamLine(line, fallbackTextId)\n if (parsed?.kind === 'part') {\n if (parsed.part.type === 'tool-call') {\n hasToolCalls = true\n }\n controller.enqueue(parsed.part)\n } else if (parsed?.kind === 'finish') {\n finishReason = parsed.finishReason\n } else if (parsed?.kind === 'data') {\n onData?.(parsed.type, parsed.data)\n }\n }\n }\n\n if (buffer.trim()) {\n const parsed = parseStreamLine(buffer, fallbackTextId)\n if (parsed?.kind === 'part') {\n if (parsed.part.type === 'tool-call') {\n hasToolCalls = true\n }\n controller.enqueue(parsed.part)\n } else if (parsed?.kind === 'finish') {\n finishReason = parsed.finishReason\n } else if (parsed?.kind === 'data') {\n onData?.(parsed.type, parsed.data)\n }\n }\n\n // If tool calls were emitted, override finish reason so streamText\n // knows to execute tools and continue with the next step.\n if (hasToolCalls && finishReason.unified !== 'tool-calls') {\n finishReason = { unified: 'tool-calls', raw: finishReason.raw ?? 'tool-calls' }\n }\n\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage: createEmptyUsage(),\n })\n } catch (error) {\n controller.enqueue({\n type: 'error',\n error: error instanceof Error ? error : new Error(String(error)),\n })\n } finally {\n controller.close()\n }\n },\n })\n}\n","import type {\n LanguageModelV3,\n LanguageModelV3CallOptions,\n LanguageModelV3Content,\n LanguageModelV3GenerateResult,\n LanguageModelV3Prompt,\n LanguageModelV3StreamResult,\n SharedV3Warning,\n} from '@ai-sdk/provider'\nimport type { ClientToolDefinition } from '@sanity/agent-types'\nimport { groupBy } from 'es-toolkit'\nimport type { AgentSettings, Message } from './types'\nimport {\n buildApiUrl,\n buildHeaders,\n createEmptyUsage,\n createSSEStream,\n extractTextFromParts,\n fetchApi,\n parseStreamLine,\n} from './utils'\n\n/**\n * @category Model\n */\nexport interface ContentAgentModelConfig {\n provider: string\n baseURL: string\n apiVersion: string\n organizationId: string\n headers: () => Record<string, string | undefined>\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Extended message type for the wire format that supports tool calls and tool results\n * in addition to plain text messages.\n */\ntype WireMessage =\n | Message\n | {\n role: 'assistant'\n content: Array<\n | { type: 'text'; text: string }\n | { type: 'tool-call'; toolCallId: string; toolName: string; input: string }\n >\n }\n | {\n role: 'tool'\n content: Array<{\n type: 'tool-result'\n toolCallId: string\n toolName: string\n output: unknown\n }>\n }\n\nconst UNSUPPORTED_SETTINGS = [\n 'maxOutputTokens',\n 'temperature',\n 'topP',\n 'topK',\n 'frequencyPenalty',\n 'presencePenalty',\n 'seed',\n] as const\n\n/**\n * Vercel AI SDK `LanguageModelV1` implementation that communicates with the\n * Sanity Content Agent API via a conversation thread.\n *\n * Typically you don't construct this directly — use\n * {@link createContentAgent | createContentAgent().agent(threadId)} instead.\n *\n * @category Model\n *\n * @example\n * ```ts\n * import { createContentAgent } from 'content-agent'\n * import { streamText } from 'ai'\n *\n * const contentAgent = createContentAgent({\n * organizationId: 'your-org-id',\n * token: 'your-sanity-token',\n * })\n *\n * const model = contentAgent.agent('my-thread-id', {\n * application: { key: 'projectId.datasetName' },\n * config: {\n * capabilities: { read: true, write: false },\n * },\n * })\n *\n * const { textStream } = await streamText({ model, prompt: 'Summarize my content' })\n * for await (const chunk of textStream) {\n * process.stdout.write(chunk)\n * }\n * ```\n */\nexport class ContentAgentModel implements LanguageModelV3 {\n readonly specificationVersion = 'v3' as const\n readonly provider: string\n readonly modelId: string\n readonly supportedUrls: Record<string, RegExp[]> = {}\n\n private readonly config: ContentAgentModelConfig\n private readonly threadId: string\n private readonly settings: AgentSettings\n\n constructor(\n threadId: string,\n settings: AgentSettings | undefined,\n config: ContentAgentModelConfig,\n ) {\n this.threadId = threadId\n this.modelId = `content-agent:${threadId}`\n this.provider = config.provider\n this.settings = settings ?? {}\n this.config = config\n }\n\n /**\n * Converts a LanguageModelV3Prompt into wire messages for the agent API.\n *\n * Handles all message roles:\n * - system: plain text system messages\n * - user: extracts text from content parts\n * - assistant: extracts text and/or tool-call parts\n * - tool: converts tool-result parts for the API\n */\n private convertPromptToMessages(prompt: LanguageModelV3Prompt): WireMessage[] {\n const messages: WireMessage[] = []\n\n for (const message of prompt) {\n if (message.role === 'system') {\n if (message.content) {\n messages.push({ role: 'system', content: message.content })\n }\n continue\n }\n\n if (message.role === 'tool') {\n const toolResults = message.content\n .filter((part) => part.type === 'tool-result')\n .map((part) => {\n const p = part as {\n toolCallId: string\n toolName: string\n output: { type: string; value: unknown } | unknown\n }\n return {\n type: 'tool-result' as const,\n toolCallId: p.toolCallId,\n toolName: p.toolName,\n output:\n p.output && typeof p.output === 'object' && 'value' in p.output\n ? (p.output as { value: unknown }).value\n : p.output,\n }\n })\n\n if (toolResults.length > 0) {\n messages.push({ role: 'tool', content: toolResults })\n }\n continue\n }\n\n if (message.role === 'assistant') {\n const content = message.content as Array<{\n type: string\n text?: string\n toolCallId?: string\n toolName?: string\n input?: string\n }>\n\n const grouped = groupBy(content, (p) => p.type)\n const toolCalls = grouped['tool-call'] ?? []\n const textParts = grouped.text ?? []\n\n if (toolCalls.length > 0) {\n const parts = [\n ...textParts\n .filter((p) => p.text)\n .map((p) => ({ type: 'text' as const, text: p.text! })),\n ...toolCalls.map((tc) => ({\n type: 'tool-call' as const,\n toolCallId: tc.toolCallId!,\n toolName: tc.toolName!,\n input: tc.input!,\n })),\n ]\n\n if (parts.length > 0) {\n messages.push({ role: 'assistant', content: parts })\n }\n } else {\n const text = extractTextFromParts(content as Array<{ type: string; text?: string }>)\n if (text) {\n messages.push({ role: 'assistant', content: text })\n }\n }\n continue\n }\n\n // user messages\n const text = extractTextFromParts(message.content as Array<{ type: string; text?: string }>)\n if (text) {\n messages.push({ role: message.role, content: text })\n }\n }\n\n return messages\n }\n\n /**\n * Extracts client tool definitions from the model call options.\n * Only the schemas are sent — execute functions stay on the client.\n */\n private extractClientTools(\n options: LanguageModelV3CallOptions,\n ): ClientToolDefinition[] | undefined {\n if (!options.tools?.length) return undefined\n\n const clientTools = options.tools\n .filter((t) => t.type === 'function')\n .map((t) => ({\n type: 'function' as const,\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema as Record<string, unknown>,\n }))\n\n return clientTools.length > 0 ? clientTools : undefined\n }\n\n private collectWarnings(options: LanguageModelV3CallOptions): SharedV3Warning[] {\n const warnings: SharedV3Warning[] = []\n\n for (const setting of UNSUPPORTED_SETTINGS) {\n if (options[setting] !== undefined) {\n warnings.push({ type: 'unsupported', feature: setting })\n }\n }\n\n if (options.stopSequences?.length) {\n warnings.push({ type: 'unsupported', feature: 'stopSequences' })\n }\n\n if (options.responseFormat && options.responseFormat.type !== 'text') {\n warnings.push({ type: 'unsupported', feature: 'responseFormat' })\n }\n\n return warnings\n }\n\n private buildRequestBody(options: LanguageModelV3CallOptions, stream: boolean) {\n const clientTools = this.extractClientTools(options)\n const toolChoice = options.toolChoice\n\n return {\n messages: this.convertPromptToMessages(options.prompt),\n stream,\n ...(clientTools && { clientTools }),\n ...(toolChoice && { toolChoice }),\n ...(this.settings.application && { application: this.settings.application }),\n ...(this.settings.config && { config: this.settings.config }),\n ...(this.settings.format && { format: this.settings.format }),\n }\n }\n\n private getResponseHeaders(response: Response): Record<string, string> {\n return Object.fromEntries(response.headers.entries())\n }\n\n async doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult> {\n // Always request a stream from the backend and buffer the result.\n // This keeps the HTTP connection alive with incremental data, avoiding\n // 504 gateway timeouts on long-running agent requests.\n const body = this.buildRequestBody(options, true)\n const warnings = this.collectWarnings(options)\n\n const response = await fetchApi({\n url: buildApiUrl(\n this.config.baseURL,\n this.config.apiVersion,\n `/${this.config.organizationId}/threads/${this.threadId}`,\n ),\n body,\n headers: buildHeaders(this.config.headers()),\n signal: options.abortSignal,\n fetch: this.config.fetch,\n })\n\n if (!response.body) {\n throw new Error('No response body for generate request')\n }\n\n const { content, finishReason } = await this.extractContentFromStream(response.body)\n\n return {\n content,\n finishReason,\n usage: createEmptyUsage(),\n request: { body },\n response: { headers: this.getResponseHeaders(response) },\n warnings,\n }\n }\n\n /**\n * Parses a streamed response body into content parts (text and tool calls)\n * and a finish reason. Used by doGenerate to buffer the full response.\n */\n private async extractContentFromStream(responseBody: ReadableStream<Uint8Array>): Promise<{\n content: LanguageModelV3Content[]\n finishReason: LanguageModelV3GenerateResult['finishReason']\n }> {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\n const textContentId = 'generate'\n let text = ''\n let hasToolCalls = false\n const content: LanguageModelV3Content[] = []\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n for (const line of chunk.split('\\n')) {\n const parsed = parseStreamLine(line, textContentId)\n if (parsed?.kind === 'part') {\n if (parsed.part.type === 'text-delta') {\n text += parsed.part.delta\n } else if (parsed.part.type === 'tool-call') {\n hasToolCalls = true\n const tc = parsed.part as { toolCallId: string; toolName: string; input: string }\n content.push({\n type: 'tool-call',\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n input: tc.input,\n })\n }\n }\n }\n }\n\n if (text) {\n content.unshift({ type: 'text', text })\n }\n\n const finishReason = hasToolCalls\n ? { unified: 'tool-calls' as const, raw: 'tool-calls' }\n : { unified: 'stop' as const, raw: undefined }\n\n return { content, finishReason }\n }\n\n async doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult> {\n const body = this.buildRequestBody(options, true)\n const warnings = this.collectWarnings(options)\n\n const response = await fetchApi({\n url: buildApiUrl(\n this.config.baseURL,\n this.config.apiVersion,\n `/${this.config.organizationId}/threads/${this.threadId}`,\n ),\n body,\n headers: buildHeaders(this.config.headers()),\n signal: options.abortSignal,\n fetch: this.config.fetch,\n })\n\n if (!response.body) {\n throw new Error('No response body for streaming request')\n }\n\n return {\n stream: createSSEStream(response.body, warnings, this.settings.onStreamData),\n request: { body },\n response: { headers: this.getResponseHeaders(response) },\n }\n }\n}\n","import type { LanguageModelV3 } from '@ai-sdk/provider'\nimport { ContentAgentModel, type ContentAgentModelConfig } from './sanity-agent-language-model'\nimport type {\n AgentSettings,\n Application,\n ContentAgentProviderSettings,\n GenerateOptions,\n GenerateResult,\n GenerateSettings,\n} from './types'\nimport {\n buildApiUrl,\n buildHeaders,\n extractTextFromStream,\n fetchApi,\n SanityAgentError,\n} from './utils'\n\nconst DEFAULT_BASE_URL = 'https://api.sanity.io'\nconst DEFAULT_API_VERSION = 'v2026-01-01'\n\n/**\n * A Content Agent provider instance returned by {@link createContentAgent}.\n *\n * Provides two modes of interaction:\n * - **Conversation threads** via {@link ContentAgentProvider.agent | .agent()} — stateful, multi-turn conversations with server-side message history.\n * - **One-shot prompts** via {@link ContentAgentProvider.prompt | .prompt()} — stateless, single-turn interactions.\n *\n * @category Provider\n */\nexport interface ContentAgentProvider {\n /**\n * Creates a Vercel AI SDK {@link https://sdk.vercel.ai/docs/ai-sdk-core | LanguageModelV1} for a conversation thread.\n *\n * The thread ID identifies the conversation and maintains message history server-side.\n * If a thread with that ID already exists, the conversation continues. If not, a new\n * thread is automatically created.\n *\n * Use the returned model with `generateText` or `streamText` from the `ai` package.\n *\n * @example\n * ```ts\n * import { generateText, streamText } from 'ai'\n *\n * const model = contentAgent.agent('my-thread-id', {\n * application: { key: 'projectId.datasetName' },\n * config: {\n * capabilities: { read: true, write: false },\n * },\n * })\n *\n * // Non-streaming\n * const { text } = await generateText({ model, prompt: 'What blog posts do I have?' })\n *\n * // Streaming\n * const { textStream } = await streamText({ model, prompt: 'Summarize my content' })\n * for await (const chunk of textStream) {\n * process.stdout.write(chunk)\n * }\n * ```\n *\n * @param threadId - Unique identifier for the conversation thread.\n * @param settings - Optional agent settings (application, capabilities, filters, etc.).\n */\n agent(threadId: string, settings?: AgentSettings): LanguageModelV3\n\n /**\n * Lists available applications for the organization.\n *\n * Returns all Sanity Studio applications the authenticated user has access to.\n * Use the `key` from a returned application to target it when creating an agent.\n *\n * @example\n * ```ts\n * const apps = await contentAgent.applications()\n * const app = apps.find((app) => app.title === \"My Studio\")\n *\n * const model = contentAgent.agent(\"my-thread\", {\n * application: { key: app.key },\n * })\n * ```\n */\n applications(): Promise<Application[]>\n\n /**\n * Sends a one-shot prompt to the Content Agent (stateless).\n *\n * Unlike {@link ContentAgentProvider.agent | .agent()}, this does not create or use a conversation thread.\n * Each call is independent with no message history or persistence.\n * Ideal for simple, single-turn interactions.\n *\n * @example\n * ```ts\n * const { text } = await contentAgent.prompt(\n * {\n * application: { key: 'projectId.datasetName' },\n * config: { capabilities: { read: true, write: false } },\n * instructions: 'Be concise',\n * },\n * { message: 'List my 5 most recent posts' },\n * )\n * ```\n *\n * @param settings - Generation settings (application, capabilities, instructions, etc.).\n * @param options - The prompt message and request options.\n */\n prompt(settings: GenerateSettings, options: GenerateOptions): Promise<GenerateResult>\n}\n\n/**\n * Creates a Content Agent provider instance.\n *\n * The provider is the main entry point for interacting with the Sanity Content Agent API.\n * It returns an object with methods for conversation threads and one-shot prompts.\n *\n * @category Provider\n *\n * @example Basic setup\n * ```ts\n * import { createContentAgent } from 'content-agent'\n *\n * const contentAgent = createContentAgent({\n * organizationId: 'your-org-id',\n * token: 'your-sanity-token',\n * })\n * ```\n *\n * @example Using with Vercel AI SDK for conversation threads\n * ```ts\n * import { createContentAgent } from 'content-agent'\n * import { generateText, streamText } from 'ai'\n *\n * const contentAgent = createContentAgent({\n * organizationId: 'your-org-id',\n * token: 'your-sanity-token',\n * })\n *\n * const model = contentAgent.agent('my-thread-id', {\n * application: { key: 'projectId.datasetName' },\n * config: {\n * capabilities: { read: true, write: false },\n * },\n * })\n *\n * // Non-streaming\n * const { text } = await generateText({ model, prompt: 'What blog posts do I have?' })\n *\n * // Streaming\n * const { textStream } = await streamText({ model, prompt: 'Summarize my content' })\n * for await (const chunk of textStream) {\n * process.stdout.write(chunk)\n * }\n * ```\n *\n * @example One-shot generation (stateless, no thread)\n * ```ts\n * const { text } = await contentAgent.prompt(\n * {\n * application: { key: 'projectId.datasetName' },\n * config: { capabilities: { read: true, write: false } },\n * instructions: 'Be concise',\n * },\n * { message: 'List my 5 most recent posts' },\n * )\n * ```\n *\n * @param options - Provider configuration including organization ID, token, and optional overrides.\n */\nexport function createContentAgent(options: ContentAgentProviderSettings): ContentAgentProvider {\n const baseURL = options.baseURL?.replace(/\\/$/, '') ?? DEFAULT_BASE_URL\n const apiVersion = options.apiVersion ?? DEFAULT_API_VERSION\n const { organizationId } = options\n\n const getHeaders = (): Record<string, string | undefined> => ({\n ...(options.token && { Authorization: `Bearer ${options.token}` }),\n ...options.headers,\n })\n\n const config: ContentAgentModelConfig = {\n provider: 'content-agent',\n baseURL,\n apiVersion,\n organizationId,\n headers: getHeaders,\n fetch: options.fetch,\n }\n\n const agent = (threadId: string, settings?: AgentSettings): LanguageModelV3 => {\n return new ContentAgentModel(threadId, settings, config)\n }\n\n const applications = async (): Promise<Application[]> => {\n const fetchFn = options.fetch ?? globalThis.fetch\n const url = buildApiUrl(baseURL, apiVersion, `/${organizationId}/applications`)\n const headers = buildHeaders(getHeaders())\n\n const response = await fetchFn(url, { method: 'GET', headers })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new SanityAgentError(response.status, errorText)\n }\n\n const json = (await response.json()) as { applications?: Application[] }\n return json.applications ?? []\n }\n\n const prompt = async (\n settings: GenerateSettings,\n generateOptions: GenerateOptions,\n ): Promise<GenerateResult> => {\n const body = {\n organizationId,\n message: generateOptions.message,\n stream: generateOptions.stream ?? false,\n ...(settings.application && { application: settings.application }),\n ...(settings.config && { config: settings.config }),\n ...(settings.instructions && { instructions: settings.instructions }),\n ...(settings.format && { format: settings.format }),\n }\n\n const response = await fetchApi({\n url: buildApiUrl(baseURL, apiVersion, '/prompt'),\n body,\n headers: buildHeaders(getHeaders()),\n signal: generateOptions.abortSignal,\n fetch: options.fetch,\n })\n\n if (body.stream) {\n if (!response.body) {\n throw new SanityAgentError(500, 'No response body')\n }\n return { text: await extractTextFromStream(response.body) }\n }\n\n const json = (await response.json()) as { text?: string }\n return { text: json.text ?? '' }\n }\n\n return { agent, applications, prompt }\n}\n"],"names":["text"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/from-client.ts","../src/utils.ts","../src/sanity-agent-language-model.ts","../src/sanity-agent-provider.ts","../src/studio.ts"],"sourcesContent":["import type { Application } from './types'\n\nconst DEFAULT_API_HOST = 'https://api.sanity.io'\n\n/**\n * Minimal interface for a Sanity client. Avoids a hard dependency on `@sanity/client` —\n * any object whose `config()` returns `projectId`, `dataset`, and `apiHost` will work.\n *\n * @category Studio Integration\n */\nexport type SanityClientLike = {\n config(): { projectId?: string; dataset?: string; apiHost?: string }\n}\n\n/**\n * Configuration derived from a Sanity client for use with {@link createContentAgent}.\n *\n * @category Studio Integration\n */\nexport type ClientDerivedConfig = {\n /**\n * Project-scoped API base URL derived from the client's `apiHost`.\n *\n * Using a project-scoped host avoids CORS preflight issues when making\n * cookie-authenticated requests from a Studio context.\n */\n baseURL: string\n\n /**\n * Application targeting the client's project, dataset, and workspace.\n *\n * Identified by `resource.id` (`projectId.dataset`) and `name` (workspace name),\n * which matches the format the Content Agent API uses internally.\n */\n application: Application\n}\n\n/**\n * Derives a project-scoped base URL from the client's configured API host.\n * Inserts `projectId` as a subdomain so cookie-authenticated requests\n * from Studio pass CORS checks.\n *\n * `https://api.sanity.io` → `https://{projectId}.api.sanity.io`\n * `https://api.sanity.work` → `https://{projectId}.api.sanity.work`\n *\n * @category Studio Integration\n */\nexport function deriveBaseUrl(apiHost: string | undefined, projectId: string): string {\n const url = new URL(apiHost || DEFAULT_API_HOST)\n url.hostname = `${projectId}.${url.hostname}`\n return url.origin\n}\n\n/**\n * Derives Content Agent configuration from a Sanity client and workspace name.\n *\n * Extracts `projectId`, `dataset`, and `apiHost` to build a CORS-compatible\n * `baseURL` and an `application` that targets the correct workspace — no need\n * to know the Studio deployment ID or application key.\n *\n * Designed for Studio / browser contexts where authentication is handled\n * via cookies. Omit the `token` when creating the provider and credentials\n * will be included automatically.\n *\n * @category Studio Integration\n *\n * @example Studio AI Assist action\n * ```ts\n * import { createContentAgent, fromClient } from 'content-agent'\n * import { useClient, useWorkspace } from 'sanity'\n *\n * const client = useClient({ apiVersion: '2024-01-01' })\n * const workspace = useWorkspace()\n * const { baseURL } = fromClient(client, workspace.name)\n *\n * const contentAgent = createContentAgent({\n * organizationId: 'your-org-id',\n * baseURL,\n * })\n *\n * const application = await contentAgent.resolveApplication(client, workspace.name)\n * const model = contentAgent.agent('thread-id', { application })\n * ```\n *\n * @param client - Any object with a `config()` method returning `projectId`, `dataset`, and optionally `apiHost`.\n * @param workspace - The active workspace name (e.g. `'default'`). Available via `useWorkspace().name` in Studio.\n */\nexport function fromClient(client: SanityClientLike, workspace: string): ClientDerivedConfig {\n const { projectId, dataset, apiHost } = client.config()\n\n if (!projectId) {\n throw new Error('fromClient: client is missing `projectId` in its config')\n }\n if (!dataset) {\n throw new Error('fromClient: client is missing `dataset` in its config')\n }\n\n return {\n baseURL: deriveBaseUrl(apiHost, projectId),\n application: {\n name: workspace,\n resource: {\n id: `${projectId}.${dataset}`,\n type: 'dataset',\n },\n },\n }\n}\n","import type {\n LanguageModelV3FinishReason,\n LanguageModelV3StreamPart,\n LanguageModelV3Usage,\n SharedV3Warning,\n} from '@ai-sdk/provider'\nimport { ERROR_CODES, type HeadlessErrorResponse } from '@sanity/agent-types'\nimport { isString, pickBy } from 'es-toolkit'\n\n/**\n * Builds headers for API requests, filtering out undefined values.\n *\n * @category Utilities\n */\nexport function buildHeaders(\n configHeaders: Record<string, string | undefined>,\n additionalHeaders?: Record<string, string>,\n): Record<string, string> {\n return pickBy(\n {\n 'Content-Type': 'application/json',\n ...additionalHeaders,\n ...configHeaders,\n },\n isString,\n )\n}\n\n/**\n * Constructs the full API URL for an endpoint.\n *\n * @category Utilities\n */\nexport function buildApiUrl(baseURL: string, apiVersion: string, endpoint: string): string {\n return `${baseURL}/${apiVersion}/agent${endpoint}`\n}\n\n/**\n * Custom error class for Sanity Agent API errors.\n * The {@link body} is parsed from the JSON response and follows the\n * {@link HeadlessErrorResponse} shape defined in `@sanity/agent-types`.\n *\n * @category Utilities\n */\nexport class SanityAgentError extends Error {\n readonly status: number\n readonly isRetryable: boolean\n readonly body: Partial<HeadlessErrorResponse>\n\n constructor(status: number, message: string) {\n super(`Sanity Agent API error: ${status} ${message}`)\n this.name = 'SanityAgentError'\n this.status = status\n this.isRetryable = status >= 500\n this.body = SanityAgentError.parseBody(message)\n }\n\n private static parseBody(message: string): Partial<HeadlessErrorResponse> {\n try {\n return JSON.parse(message)\n } catch {\n return {}\n }\n }\n}\n\n/**\n * Error class for errors received via SSE stream events.\n * Unlike {@link SanityAgentError} (which is thrown for HTTP-level errors before\n * streaming starts), this wraps errors received mid-stream as SSE `error` events.\n *\n * The {@link code} carries the backend's error classification (e.g. `UPSTREAM_OVERLOADED`)\n * so clients can take targeted action without parsing the message string.\n *\n * @category Utilities\n */\nexport class SanityAgentStreamError extends Error {\n readonly code: string | undefined\n\n constructor(message: string, code?: string) {\n super(message)\n this.name = 'SanityAgentStreamError'\n this.code = code\n }\n}\n\nexport const GENERIC_ERROR_MESSAGE = 'Sorry, something went wrong. Please try again.'\n\nexport type AgentErrorType =\n | { type: 'no_applications' }\n | { type: 'application_not_found' }\n | { type: 'upstream_overloaded' }\n | { type: 'upstream_error' }\n | { type: 'usage_limit_exceeded' }\n | { type: 'streaming_error' }\n | { type: 'unknown' }\n\nfunction mapErrorCode(code: string | undefined): AgentErrorType | null {\n switch (code) {\n case ERROR_CODES.NO_COMPATIBLE_APPLICATIONS:\n return { type: 'no_applications' }\n case ERROR_CODES.APPLICATION_NOT_FOUND:\n return { type: 'application_not_found' }\n case ERROR_CODES.UPSTREAM_OVERLOADED:\n return { type: 'upstream_overloaded' }\n case ERROR_CODES.UPSTREAM_ERROR:\n return { type: 'upstream_error' }\n case ERROR_CODES.AI_USAGE_LIMIT_EXCEEDED:\n return { type: 'usage_limit_exceeded' }\n case ERROR_CODES.STREAMING_ERROR:\n return { type: 'streaming_error' }\n default:\n return null\n }\n}\n\n/**\n * Classifies a caught error from the Content Agent API into a known error type.\n * Useful for clients that need to take different actions per error (e.g. show\n * resource-selection buttons). For the user-facing message, use {@link getAgentErrorMessage}.\n *\n * @category Utilities\n */\nexport function classifyAgentError(error: unknown): AgentErrorType {\n // Handle SSE stream errors (from parseStreamLine)\n if (error instanceof SanityAgentStreamError && error.code) {\n return mapErrorCode(error.code) ?? { type: 'unknown' }\n }\n\n // Handle HTTP-level errors (from fetchApi)\n if (error instanceof SanityAgentError) {\n if (error.status !== 400) {\n return { type: 'unknown' }\n }\n return mapErrorCode(error.body.code) ?? { type: 'unknown' }\n }\n\n return { type: 'unknown' }\n}\n\nexport function isAppRelatedError(classified: AgentErrorType): boolean {\n return classified.type === 'no_applications' || classified.type === 'application_not_found'\n}\n\nexport type AgentErrorMessageContext = {\n orgName?: string | null\n}\n\n/**\n * Resolves a user-facing error message for a classified agent error.\n * For errors that benefit from additional context (e.g. org name), the optional\n * {@link resolveContext} callback is invoked lazily — only when the error type\n * needs it. Non-contextual errors return the backend message as-is.\n *\n * @category Utilities\n */\nexport async function resolveAgentErrorMessage(\n classified: AgentErrorType,\n error: unknown,\n resolveContext?: () => Promise<AgentErrorMessageContext>,\n): Promise<string> {\n const fallback = getAgentErrorMessage(error)\n\n if (!resolveContext || !isAppRelatedError(classified)) return fallback\n\n const ctx = await resolveContext()\n if (!ctx.orgName) return fallback\n\n switch (classified.type) {\n case 'no_applications':\n return `Studio action required: To use the Content Agent in \"${ctx.orgName}\", you must have at least one Sanity Studio running version 5.1.0 or above. After upgrading, open your studio to connect it to the agent.`\n case 'application_not_found':\n return `The requested studio is not available in \"${ctx.orgName}\". You may not have access, or it may belong to a different organization.`\n default:\n return fallback\n }\n}\n\n/**\n * Extracts a user-facing error message from an agent API error.\n * Returns the message sent by the API when available, otherwise a generic fallback.\n *\n * @category Utilities\n */\nexport function getAgentErrorMessage(error: unknown): string {\n if (error instanceof SanityAgentStreamError) {\n return error.message\n }\n if (error instanceof SanityAgentError && error.body.message) {\n return error.body.message\n }\n return GENERIC_ERROR_MESSAGE\n}\n\nexport interface FetchOptions {\n url: string\n body: unknown\n headers: Record<string, string>\n credentials?: RequestCredentials\n signal?: AbortSignal\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Makes a POST request and returns the response.\n * Throws SanityAgentError if the response is not ok.\n *\n * @category Utilities\n */\nexport async function fetchApi(options: FetchOptions): Promise<Response> {\n const fetchFn = options.fetch ?? globalThis.fetch\n\n const response = await fetchFn(options.url, {\n method: 'POST',\n headers: options.headers,\n body: JSON.stringify(options.body),\n signal: options.signal,\n ...(options.credentials && { credentials: options.credentials }),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new SanityAgentError(response.status, errorText)\n }\n\n return response\n}\n\n/**\n * Extracts text content from message parts (user or assistant).\n *\n * @category Utilities\n */\nexport function extractTextFromParts(\n content: string | Array<{ type: string; text?: string }>,\n): string {\n if (typeof content === 'string') {\n return content\n }\n\n return content\n .filter(\n (part): part is { type: 'text'; text: string } =>\n part.type === 'text' && typeof part.text === 'string',\n )\n .map((part) => part.text)\n .join('\\n')\n}\n\n/**\n * Creates an empty V3 usage object. Our API does not return token counts.\n *\n * @category Utilities\n */\nexport function createEmptyUsage(): LanguageModelV3Usage {\n return {\n inputTokens: {\n total: 0,\n noCache: undefined,\n cacheRead: undefined,\n cacheWrite: undefined,\n },\n outputTokens: {\n total: 0,\n text: undefined,\n reasoning: undefined,\n },\n }\n}\n\n/**\n * Maps API finish reasons to LanguageModelV3FinishReason.\n *\n * @category Utilities\n */\nexport function mapFinishReason(reason: string | undefined): LanguageModelV3FinishReason {\n const unified = (() => {\n switch (reason) {\n case 'stop':\n case 'length':\n case 'content-filter':\n case 'tool-calls':\n case 'error':\n return reason\n default:\n return 'other' as const\n }\n })()\n\n return { unified, raw: reason }\n}\n\nexport type ParsedStreamLine =\n | { kind: 'part'; part: LanguageModelV3StreamPart }\n | { kind: 'finish'; finishReason: LanguageModelV3FinishReason }\n | { kind: 'data'; type: string; data: unknown }\n\n/**\n * Parses a single SSE line from the AI SDK v6 UI Message Stream protocol.\n * Returns null if the line cannot be parsed or should be ignored.\n *\n * Format: `data: <json>\\n`\n *\n * Supported types:\n * text-start – Text block start (forwarded as-is)\n * text-delta – Text chunk\n * text-end – Text block end (forwarded as-is)\n * tool-input-available – Tool call (client tools only, without providerExecuted)\n * tool-output-available – Tool result (informational, skipped)\n * finish – Finish event with reason\n * error – Error event\n * start – Stream start (skipped)\n * [DONE] – Stream termination (skipped)\n *\n * @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol\n *\n * @param line A single line from the SSE byte stream.\n * @param textContentId Fallback ID for text parts that lack an explicit id.\n *\n * @category Utilities\n */\nexport function parseStreamLine(line: string, textContentId: string): ParsedStreamLine | null {\n const trimmed = line.trim()\n if (!trimmed.startsWith('data: ')) return null\n\n const payload = trimmed.slice(6)\n if (payload === '[DONE]') return null\n\n let part: Record<string, unknown>\n try {\n part = JSON.parse(payload) as Record<string, unknown>\n } catch {\n return null\n }\n\n const type = part.type as string | undefined\n if (!type) return null\n\n switch (type) {\n case 'text-start': {\n const id = (part.id as string) || textContentId\n return { kind: 'part', part: { type: 'text-start', id } }\n }\n\n case 'text-delta': {\n const id = (part.id as string) || textContentId\n const delta = part.delta as string\n if (typeof delta !== 'string') return null\n return { kind: 'part', part: { type: 'text-delta', id, delta } }\n }\n\n case 'text-end': {\n const id = (part.id as string) || textContentId\n return { kind: 'part', part: { type: 'text-end', id } }\n }\n\n case 'tool-input-available': {\n // Skip server-executed tools — only forward client tools for local execution.\n if (part.providerExecuted) return null\n\n const input = part.input\n return {\n kind: 'part',\n part: {\n type: 'tool-call',\n toolCallId: part.toolCallId as string,\n toolName: part.toolName as string,\n input: typeof input === 'string' ? input : JSON.stringify(input),\n },\n }\n }\n\n case 'error': {\n const errorText = (part.errorText as string) ?? 'Unknown error'\n const errorCode = part.errorCode as string | undefined\n return {\n kind: 'part',\n part: {\n type: 'error',\n error: new SanityAgentStreamError(errorText, errorCode),\n },\n }\n }\n\n case 'abort': {\n return { kind: 'data', type: 'abort', data: { reason: part.reason } }\n }\n\n case 'finish': {\n return {\n kind: 'finish',\n finishReason: mapFinishReason(part.finishReason as string | undefined),\n }\n }\n\n default: {\n if (type.startsWith('data-')) {\n return { kind: 'data', type: type.slice(5), data: part.data }\n }\n return null\n }\n }\n}\n\n/**\n * Extracts accumulated text from a streaming response body.\n * Used for simple streaming cases where only the final text is needed.\n *\n * @category Utilities\n */\nexport async function extractTextFromStream(\n responseBody: ReadableStream<Uint8Array>,\n): Promise<string> {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\n const textContentId = 'extract'\n let text = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n for (const line of chunk.split('\\n')) {\n const parsed = parseStreamLine(line, textContentId)\n if (parsed?.kind === 'part' && parsed.part.type === 'text-delta') {\n text += parsed.part.delta\n }\n }\n }\n\n return text\n}\n\n/**\n * Creates a ReadableStream that parses AI SDK v6 UI Message Stream SSE data\n * from a response body and emits LanguageModelV3 stream parts.\n *\n * Text lifecycle events (text-start / text-end) are forwarded from the server.\n * Tool calls are tracked to ensure the finish reason is set correctly.\n *\n * @category Utilities\n */\nexport function createSSEStream(\n responseBody: ReadableStream<Uint8Array>,\n warnings: SharedV3Warning[],\n onData?: (type: string, data: unknown) => void,\n): ReadableStream<LanguageModelV3StreamPart> {\n let finishReason: LanguageModelV3FinishReason = { unified: 'other', raw: undefined }\n const fallbackTextId = crypto.randomUUID()\n let hasToolCalls = false\n\n return new ReadableStream<LanguageModelV3StreamPart>({\n async start(controller) {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n controller.enqueue({ type: 'stream-start', warnings })\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n\n for (const line of lines) {\n const parsed = parseStreamLine(line, fallbackTextId)\n if (parsed?.kind === 'part') {\n if (parsed.part.type === 'tool-call') {\n hasToolCalls = true\n }\n controller.enqueue(parsed.part)\n } else if (parsed?.kind === 'finish') {\n finishReason = parsed.finishReason\n } else if (parsed?.kind === 'data') {\n onData?.(parsed.type, parsed.data)\n }\n }\n }\n\n if (buffer.trim()) {\n const parsed = parseStreamLine(buffer, fallbackTextId)\n if (parsed?.kind === 'part') {\n if (parsed.part.type === 'tool-call') {\n hasToolCalls = true\n }\n controller.enqueue(parsed.part)\n } else if (parsed?.kind === 'finish') {\n finishReason = parsed.finishReason\n } else if (parsed?.kind === 'data') {\n onData?.(parsed.type, parsed.data)\n }\n }\n\n // If tool calls were emitted, override finish reason so streamText\n // knows to execute tools and continue with the next step.\n if (hasToolCalls && finishReason.unified !== 'tool-calls') {\n finishReason = { unified: 'tool-calls', raw: finishReason.raw ?? 'tool-calls' }\n }\n\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage: createEmptyUsage(),\n })\n } catch (error) {\n controller.enqueue({\n type: 'error',\n error: error instanceof Error ? error : new Error(String(error)),\n })\n } finally {\n controller.close()\n }\n },\n })\n}\n","import type {\n LanguageModelV3,\n LanguageModelV3CallOptions,\n LanguageModelV3Content,\n LanguageModelV3GenerateResult,\n LanguageModelV3Prompt,\n LanguageModelV3StreamResult,\n SharedV3Warning,\n} from '@ai-sdk/provider'\nimport type { ClientToolDefinition } from '@sanity/agent-types'\nimport { groupBy } from 'es-toolkit'\nimport type { AgentSettings, Message } from './types'\nimport {\n buildApiUrl,\n buildHeaders,\n createEmptyUsage,\n createSSEStream,\n extractTextFromParts,\n fetchApi,\n parseStreamLine,\n} from './utils'\n\n/**\n * @category Model\n */\nexport interface ContentAgentModelConfig {\n provider: string\n baseURL: string\n apiVersion: string\n organizationId: string\n headers: () => Record<string, string | undefined>\n credentials?: RequestCredentials\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Extended message type for the wire format that supports tool calls and tool results\n * in addition to plain text messages.\n */\ntype WireMessage =\n | Message\n | {\n role: 'assistant'\n content: Array<\n | { type: 'text'; text: string }\n | { type: 'tool-call'; toolCallId: string; toolName: string; input: string }\n >\n }\n | {\n role: 'tool'\n content: Array<{\n type: 'tool-result'\n toolCallId: string\n toolName: string\n output: unknown\n }>\n }\n\nconst UNSUPPORTED_SETTINGS = [\n 'maxOutputTokens',\n 'temperature',\n 'topP',\n 'topK',\n 'frequencyPenalty',\n 'presencePenalty',\n 'seed',\n] as const\n\n/**\n * Vercel AI SDK `LanguageModelV1` implementation that communicates with the\n * Sanity Content Agent API via a conversation thread.\n *\n * Typically you don't construct this directly — use\n * {@link createContentAgent | createContentAgent().agent(threadId)} instead.\n *\n * @category Model\n *\n * @example\n * ```ts\n * import { createContentAgent } from 'content-agent'\n * import { streamText } from 'ai'\n *\n * const contentAgent = createContentAgent({\n * organizationId: 'your-org-id',\n * token: 'your-sanity-token',\n * })\n *\n * const model = contentAgent.agent('my-thread-id', {\n * application: { key: 'projectId.datasetName' },\n * config: {\n * capabilities: { read: true, write: false },\n * },\n * })\n *\n * const { textStream } = await streamText({ model, prompt: 'Summarize my content' })\n * for await (const chunk of textStream) {\n * process.stdout.write(chunk)\n * }\n * ```\n */\nexport class ContentAgentModel implements LanguageModelV3 {\n readonly specificationVersion = 'v3' as const\n readonly provider: string\n readonly modelId: string\n readonly supportedUrls: Record<string, RegExp[]> = {}\n\n private readonly config: ContentAgentModelConfig\n private readonly threadId: string\n private readonly settings: AgentSettings\n\n constructor(\n threadId: string,\n settings: AgentSettings | undefined,\n config: ContentAgentModelConfig,\n ) {\n this.threadId = threadId\n this.modelId = `content-agent:${threadId}`\n this.provider = config.provider\n this.settings = settings ?? {}\n this.config = config\n }\n\n /**\n * Converts a LanguageModelV3Prompt into wire messages for the agent API.\n *\n * Handles all message roles:\n * - system: plain text system messages\n * - user: extracts text from content parts\n * - assistant: extracts text and/or tool-call parts\n * - tool: converts tool-result parts for the API\n */\n private convertPromptToMessages(prompt: LanguageModelV3Prompt): WireMessage[] {\n const messages: WireMessage[] = []\n\n for (const message of prompt) {\n if (message.role === 'system') {\n if (message.content) {\n messages.push({ role: 'system', content: message.content })\n }\n continue\n }\n\n if (message.role === 'tool') {\n const toolResults = message.content\n .filter((part) => part.type === 'tool-result')\n .map((part) => {\n const p = part as {\n toolCallId: string\n toolName: string\n output: { type: string; value: unknown } | unknown\n }\n return {\n type: 'tool-result' as const,\n toolCallId: p.toolCallId,\n toolName: p.toolName,\n output:\n p.output && typeof p.output === 'object' && 'value' in p.output\n ? (p.output as { value: unknown }).value\n : p.output,\n }\n })\n\n if (toolResults.length > 0) {\n messages.push({ role: 'tool', content: toolResults })\n }\n continue\n }\n\n if (message.role === 'assistant') {\n const content = message.content as Array<{\n type: string\n text?: string\n toolCallId?: string\n toolName?: string\n input?: string\n }>\n\n const grouped = groupBy(content, (p) => p.type)\n const toolCalls = grouped['tool-call'] ?? []\n const textParts = grouped.text ?? []\n\n if (toolCalls.length > 0) {\n const parts = [\n ...textParts\n .filter((p) => p.text)\n .map((p) => ({ type: 'text' as const, text: p.text! })),\n ...toolCalls.map((tc) => ({\n type: 'tool-call' as const,\n toolCallId: tc.toolCallId!,\n toolName: tc.toolName!,\n input: tc.input!,\n })),\n ]\n\n if (parts.length > 0) {\n messages.push({ role: 'assistant', content: parts })\n }\n } else {\n const text = extractTextFromParts(content as Array<{ type: string; text?: string }>)\n if (text) {\n messages.push({ role: 'assistant', content: text })\n }\n }\n continue\n }\n\n // user messages\n const text = extractTextFromParts(message.content as Array<{ type: string; text?: string }>)\n if (text) {\n messages.push({ role: message.role, content: text })\n }\n }\n\n return messages\n }\n\n /**\n * Extracts client tool definitions from the model call options.\n * Only the schemas are sent — execute functions stay on the client.\n */\n private extractClientTools(\n options: LanguageModelV3CallOptions,\n ): ClientToolDefinition[] | undefined {\n if (!options.tools?.length) return undefined\n\n const clientTools = options.tools\n .filter((t) => t.type === 'function')\n .map((t) => ({\n type: 'function' as const,\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema as Record<string, unknown>,\n }))\n\n return clientTools.length > 0 ? clientTools : undefined\n }\n\n private collectWarnings(options: LanguageModelV3CallOptions): SharedV3Warning[] {\n const warnings: SharedV3Warning[] = []\n\n for (const setting of UNSUPPORTED_SETTINGS) {\n if (options[setting] !== undefined) {\n warnings.push({ type: 'unsupported', feature: setting })\n }\n }\n\n if (options.stopSequences?.length) {\n warnings.push({ type: 'unsupported', feature: 'stopSequences' })\n }\n\n if (options.responseFormat && options.responseFormat.type !== 'text') {\n warnings.push({ type: 'unsupported', feature: 'responseFormat' })\n }\n\n return warnings\n }\n\n private buildRequestBody(options: LanguageModelV3CallOptions, stream: boolean) {\n const clientTools = this.extractClientTools(options)\n const toolChoice = options.toolChoice\n\n return {\n messages: this.convertPromptToMessages(options.prompt),\n stream,\n ...(clientTools && { clientTools }),\n ...(toolChoice && { toolChoice }),\n ...(this.settings.application && { application: this.settings.application }),\n ...(this.settings.config && { config: this.settings.config }),\n ...(this.settings.format && { format: this.settings.format }),\n }\n }\n\n private getResponseHeaders(response: Response): Record<string, string> {\n return Object.fromEntries(response.headers.entries())\n }\n\n async doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult> {\n // Always request a stream from the backend and buffer the result.\n // This keeps the HTTP connection alive with incremental data, avoiding\n // 504 gateway timeouts on long-running agent requests.\n const body = this.buildRequestBody(options, true)\n const warnings = this.collectWarnings(options)\n\n const response = await fetchApi({\n url: buildApiUrl(\n this.config.baseURL,\n this.config.apiVersion,\n `/${this.config.organizationId}/threads/${this.threadId}`,\n ),\n body,\n headers: buildHeaders(this.config.headers()),\n credentials: this.config.credentials,\n signal: options.abortSignal,\n fetch: this.config.fetch,\n })\n\n if (!response.body) {\n throw new Error('No response body for generate request')\n }\n\n const { content, finishReason } = await this.extractContentFromStream(response.body)\n\n return {\n content,\n finishReason,\n usage: createEmptyUsage(),\n request: { body },\n response: { headers: this.getResponseHeaders(response) },\n warnings,\n }\n }\n\n /**\n * Parses a streamed response body into content parts (text and tool calls)\n * and a finish reason. Used by doGenerate to buffer the full response.\n */\n private async extractContentFromStream(responseBody: ReadableStream<Uint8Array>): Promise<{\n content: LanguageModelV3Content[]\n finishReason: LanguageModelV3GenerateResult['finishReason']\n }> {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\n const textContentId = 'generate'\n let text = ''\n let hasToolCalls = false\n const content: LanguageModelV3Content[] = []\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n for (const line of chunk.split('\\n')) {\n const parsed = parseStreamLine(line, textContentId)\n if (parsed?.kind === 'part') {\n if (parsed.part.type === 'text-delta') {\n text += parsed.part.delta\n } else if (parsed.part.type === 'tool-call') {\n hasToolCalls = true\n const tc = parsed.part as { toolCallId: string; toolName: string; input: string }\n content.push({\n type: 'tool-call',\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n input: tc.input,\n })\n }\n }\n }\n }\n\n if (text) {\n content.unshift({ type: 'text', text })\n }\n\n const finishReason = hasToolCalls\n ? { unified: 'tool-calls' as const, raw: 'tool-calls' }\n : { unified: 'stop' as const, raw: undefined }\n\n return { content, finishReason }\n }\n\n async doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult> {\n const body = this.buildRequestBody(options, true)\n const warnings = this.collectWarnings(options)\n\n const response = await fetchApi({\n url: buildApiUrl(\n this.config.baseURL,\n this.config.apiVersion,\n `/${this.config.organizationId}/threads/${this.threadId}`,\n ),\n body,\n headers: buildHeaders(this.config.headers()),\n credentials: this.config.credentials,\n signal: options.abortSignal,\n fetch: this.config.fetch,\n })\n\n if (!response.body) {\n throw new Error('No response body for streaming request')\n }\n\n return {\n stream: createSSEStream(response.body, warnings, this.settings.onStreamData),\n request: { body },\n response: { headers: this.getResponseHeaders(response) },\n }\n }\n}\n","import type { LanguageModelV3 } from '@ai-sdk/provider'\nimport type { SanityClientLike } from './from-client'\nimport { ContentAgentModel, type ContentAgentModelConfig } from './sanity-agent-language-model'\nimport type {\n AgentSettings,\n Application,\n ContentAgentProviderSettings,\n GenerateOptions,\n GenerateResult,\n GenerateSettings,\n} from './types'\nimport {\n buildApiUrl,\n buildHeaders,\n extractTextFromStream,\n fetchApi,\n SanityAgentError,\n} from './utils'\n\nconst DEFAULT_BASE_URL = 'https://api.sanity.io'\nconst DEFAULT_API_VERSION = 'v2026-01-01'\n\n/**\n * A Content Agent provider instance returned by {@link createContentAgent}.\n *\n * Provides two modes of interaction:\n * - **Conversation threads** via {@link ContentAgentProvider.agent | .agent()} — stateful, multi-turn conversations with server-side message history.\n * - **One-shot prompts** via {@link ContentAgentProvider.prompt | .prompt()} — stateless, single-turn interactions.\n *\n * @category Provider\n */\nexport interface ContentAgentProvider {\n /**\n * Creates a Vercel AI SDK {@link https://sdk.vercel.ai/docs/ai-sdk-core | LanguageModelV1} for a conversation thread.\n *\n * The thread ID identifies the conversation and maintains message history server-side.\n * If a thread with that ID already exists, the conversation continues. If not, a new\n * thread is automatically created.\n *\n * Use the returned model with `generateText` or `streamText` from the `ai` package.\n *\n * @example\n * ```ts\n * import { generateText, streamText } from 'ai'\n *\n * const model = contentAgent.agent('my-thread-id', {\n * application: { key: 'projectId.datasetName' },\n * config: {\n * capabilities: { read: true, write: false },\n * },\n * })\n *\n * // Non-streaming\n * const { text } = await generateText({ model, prompt: 'What blog posts do I have?' })\n *\n * // Streaming\n * const { textStream } = await streamText({ model, prompt: 'Summarize my content' })\n * for await (const chunk of textStream) {\n * process.stdout.write(chunk)\n * }\n * ```\n *\n * @param threadId - Unique identifier for the conversation thread.\n * @param settings - Optional agent settings (application, capabilities, filters, etc.).\n */\n agent(threadId: string, settings?: AgentSettings): LanguageModelV3\n\n /**\n * Lists available applications for the organization.\n *\n * Returns all Sanity Studio applications the authenticated user has access to.\n * Use the `key` from a returned application to target it when creating an agent.\n *\n * @example\n * ```ts\n * const apps = await contentAgent.applications()\n * const app = apps.find((app) => app.title === \"My Studio\")\n *\n * const model = contentAgent.agent(\"my-thread\", {\n * application: { key: app.key },\n * })\n * ```\n */\n applications(): Promise<Application[]>\n\n /**\n * Resolves the full application for a Sanity client by matching its `projectId`\n * and `dataset` against the organization's application list.\n *\n * This is the easiest way to get a valid application in Studio contexts —\n * pass the client you already have and get back an application with the\n * correct `key` for the Content Agent API.\n *\n * Throws if no matching application is found (e.g. wrong org, or the Studio\n * hasn't been deployed yet).\n *\n * @example\n * ```ts\n * import { createContentAgent, fromClient } from 'content-agent'\n * import { useClient, useWorkspace } from 'sanity'\n *\n * const client = useClient({ apiVersion: '2024-01-01' })\n * const workspace = useWorkspace()\n * const { baseURL } = fromClient(client, workspace.name)\n *\n * const contentAgent = createContentAgent({\n * organizationId: 'your-org-id',\n * baseURL,\n * })\n *\n * const application = await contentAgent.resolveApplication(client, workspace.name)\n * const model = contentAgent.agent('thread-id', { application })\n * ```\n *\n * @param client - Any object with a `config()` method returning `projectId` and `dataset`.\n * @param workspace - The active workspace name (e.g. `'default'`). Available via `useWorkspace().name` in Studio.\n */\n resolveApplication(client: SanityClientLike, workspace: string): Promise<Application>\n\n /**\n * Sends a one-shot prompt to the Content Agent (stateless).\n *\n * Unlike {@link ContentAgentProvider.agent | .agent()}, this does not create or use a conversation thread.\n * Each call is independent with no message history or persistence.\n * Ideal for simple, single-turn interactions.\n *\n * @example\n * ```ts\n * const { text } = await contentAgent.prompt(\n * {\n * application: { key: 'projectId.datasetName' },\n * config: { capabilities: { read: true, write: false } },\n * instructions: 'Be concise',\n * },\n * { message: 'List my 5 most recent posts' },\n * )\n * ```\n *\n * @param settings - Generation settings (application, capabilities, instructions, etc.).\n * @param options - The prompt message and request options.\n */\n prompt(settings: GenerateSettings, options: GenerateOptions): Promise<GenerateResult>\n}\n\n/**\n * Creates a Content Agent provider instance.\n *\n * The provider is the main entry point for interacting with the Sanity Content Agent API.\n * It returns an object with methods for conversation threads and one-shot prompts.\n *\n * @category Provider\n *\n * @example Basic setup\n * ```ts\n * import { createContentAgent } from 'content-agent'\n *\n * const contentAgent = createContentAgent({\n * organizationId: 'your-org-id',\n * token: 'your-sanity-token',\n * })\n * ```\n *\n * @example Using with Vercel AI SDK for conversation threads\n * ```ts\n * import { createContentAgent } from 'content-agent'\n * import { generateText, streamText } from 'ai'\n *\n * const contentAgent = createContentAgent({\n * organizationId: 'your-org-id',\n * token: 'your-sanity-token',\n * })\n *\n * const model = contentAgent.agent('my-thread-id', {\n * application: { key: 'projectId.datasetName' },\n * config: {\n * capabilities: { read: true, write: false },\n * },\n * })\n *\n * // Non-streaming\n * const { text } = await generateText({ model, prompt: 'What blog posts do I have?' })\n *\n * // Streaming\n * const { textStream } = await streamText({ model, prompt: 'Summarize my content' })\n * for await (const chunk of textStream) {\n * process.stdout.write(chunk)\n * }\n * ```\n *\n * @example One-shot generation (stateless, no thread)\n * ```ts\n * const { text } = await contentAgent.prompt(\n * {\n * application: { key: 'projectId.datasetName' },\n * config: { capabilities: { read: true, write: false } },\n * instructions: 'Be concise',\n * },\n * { message: 'List my 5 most recent posts' },\n * )\n * ```\n *\n * @param options - Provider configuration including organization ID, token, and optional overrides.\n */\nexport function createContentAgent(options: ContentAgentProviderSettings): ContentAgentProvider {\n const baseURL = options.baseURL?.replace(/\\/$/, '') ?? DEFAULT_BASE_URL\n const apiVersion = options.apiVersion ?? DEFAULT_API_VERSION\n const { organizationId } = options\n\n const getHeaders = (): Record<string, string | undefined> => ({\n ...(options.token && { Authorization: `Bearer ${options.token}` }),\n ...options.headers,\n })\n\n // When no token is provided, include credentials so the browser sends\n // cookies automatically — this is the Studio / browser auth path.\n const credentials: RequestCredentials | undefined = options.token ? undefined : 'include'\n\n const config: ContentAgentModelConfig = {\n provider: 'content-agent',\n baseURL,\n apiVersion,\n organizationId,\n headers: getHeaders,\n credentials,\n fetch: options.fetch,\n }\n\n const agent = (threadId: string, settings?: AgentSettings): LanguageModelV3 => {\n return new ContentAgentModel(\n threadId,\n {\n ...settings,\n application: settings?.application ?? options.application,\n },\n config,\n )\n }\n\n let applicationsPromise: Promise<Application[]> | null = null\n\n const applications = (): Promise<Application[]> => {\n if (!applicationsPromise) {\n applicationsPromise = (async () => {\n const fetchFn = options.fetch ?? globalThis.fetch\n const url = buildApiUrl(baseURL, apiVersion, `/${organizationId}/applications`)\n const headers = buildHeaders(getHeaders())\n\n const response = await fetchFn(url, {\n method: 'GET',\n headers,\n ...(credentials && { credentials }),\n })\n\n if (!response.ok) {\n applicationsPromise = null\n const errorText = await response.text()\n throw new SanityAgentError(response.status, errorText)\n }\n\n const json = (await response.json()) as { applications?: Application[] }\n return json.applications ?? []\n })()\n }\n\n return applicationsPromise\n }\n\n const prompt = async (\n settings: GenerateSettings,\n generateOptions: GenerateOptions,\n ): Promise<GenerateResult> => {\n const effectiveApplication = settings.application ?? options.application\n\n const body = {\n organizationId,\n message: generateOptions.message,\n stream: generateOptions.stream ?? false,\n ...(effectiveApplication && { application: effectiveApplication }),\n ...(settings.config && { config: settings.config }),\n ...(settings.instructions && { instructions: settings.instructions }),\n ...(settings.format && { format: settings.format }),\n }\n\n const response = await fetchApi({\n url: buildApiUrl(baseURL, apiVersion, '/prompt'),\n body,\n headers: buildHeaders(getHeaders()),\n credentials,\n signal: generateOptions.abortSignal,\n fetch: options.fetch,\n })\n\n if (body.stream) {\n if (!response.body) {\n throw new SanityAgentError(500, 'No response body')\n }\n return { text: await extractTextFromStream(response.body) }\n }\n\n const json = (await response.json()) as { text?: string }\n return { text: json.text ?? '' }\n }\n\n const resolveApplication = async (\n client: SanityClientLike,\n workspace: string,\n ): Promise<Application> => {\n const { projectId, dataset } = client.config()\n if (!projectId || !dataset) {\n throw new Error(\n 'resolveApplication: client is missing `projectId` or `dataset` in its config',\n )\n }\n\n const resourceId = `${projectId}.${dataset}`\n const apps = await applications()\n const match = apps.find((app) => app.resource?.id === resourceId && app.name === workspace)\n\n if (!match) {\n throw new SanityAgentError(\n 400,\n JSON.stringify({\n code: 'APPLICATION_NOT_FOUND',\n message: `No application found for resource \"${resourceId}\" with workspace \"${workspace}\". Make sure the Studio has been deployed and belongs to this organization.`,\n }),\n )\n }\n\n return match\n }\n\n return { agent, applications, resolveApplication, prompt }\n}\n","import type { LanguageModelV3, LanguageModelV3CallOptions } from '@ai-sdk/provider'\nimport { deriveBaseUrl, type SanityClientLike } from './from-client'\nimport type { ContentAgentProvider } from './sanity-agent-provider'\nimport { createContentAgent } from './sanity-agent-provider'\nimport type { AgentSettings, ContentAgentProviderSettings } from './types'\nimport { buildHeaders, SanityAgentError } from './utils'\n\nconst PROJECTS_API_VERSION = 'v2024-01-01'\n\n/**\n * Module-level cache for setup promises. Keyed by `projectId.dataset.workspace`,\n * so repeated calls to `createStudioAgent` with the same params (e.g. React strict\n * mode double-render, component remounts) reuse the same in-flight or resolved setup.\n */\nconst providerCache = new Map<string, Promise<ContentAgentProvider>>()\n\ntype ProjectResponse = {\n id: string\n organizationId?: string | null\n}\n\n/**\n * Options for {@link createStudioAgent}.\n *\n * @category Studio Integration\n */\nexport type StudioAgentOptions = {\n /**\n * Custom fetch implementation. Useful for testing.\n */\n fetch?: typeof globalThis.fetch\n\n /**\n * Additional provider settings forwarded to {@link createContentAgent}.\n * `organizationId`, `baseURL`, and `application` are derived automatically\n * and cannot be overridden here.\n */\n providerOptions?: Omit<ContentAgentProviderSettings, 'organizationId' | 'baseURL' | 'application'>\n}\n\nasync function fetchOrganizationId(\n apiHost: string,\n projectId: string,\n fetchFn: typeof globalThis.fetch,\n): Promise<string> {\n const url = `${apiHost}/${PROJECTS_API_VERSION}/projects/${projectId}`\n\n const response = await fetchFn(url, {\n method: 'GET',\n headers: buildHeaders({}),\n credentials: 'include',\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new SanityAgentError(\n response.status,\n JSON.stringify({\n code: 'PROJECT_FETCH_FAILED',\n message: `Failed to fetch project \"${projectId}\": ${errorText}`,\n }),\n )\n }\n\n const project = (await response.json()) as ProjectResponse\n\n if (!project.organizationId) {\n throw new SanityAgentError(\n 400,\n JSON.stringify({\n code: 'NO_ORGANIZATION',\n message: `Project \"${projectId}\" is not assigned to an organization. Content Agent requires an organization-level project.`,\n }),\n )\n }\n\n return project.organizationId\n}\n\n/**\n * Resolves the full provider by fetching org ID and application. The returned\n * promise is cached so the setup only runs once regardless of how many calls\n * go through the lazy wrapper.\n */\nfunction initProvider(\n projectId: string,\n dataset: string,\n workspace: string,\n apiHost: string,\n baseURL: string,\n fetchFn: typeof globalThis.fetch,\n providerOptions?: StudioAgentOptions['providerOptions'],\n): Promise<ContentAgentProvider> {\n return fetchOrganizationId(apiHost, projectId, fetchFn).then(async (organizationId) => {\n const tempProvider = createContentAgent({\n organizationId,\n baseURL,\n fetch: fetchFn,\n })\n\n // Reuse the provider's own resolveApplication logic — no duplicated matching\n const client: SanityClientLike = { config: () => ({ projectId, dataset }) }\n const application = await tempProvider.resolveApplication(client, workspace)\n\n return createContentAgent({\n ...providerOptions,\n organizationId,\n baseURL,\n application,\n })\n })\n}\n\n/**\n * A {@link LanguageModelV3} that defers to a lazily-resolved provider.\n *\n * The first call to `doGenerate` or `doStream` awaits the setup promise,\n * then delegates to the real model. The resolved model is cached for\n * subsequent calls.\n */\nclass LazyContentAgentModel implements LanguageModelV3 {\n readonly specificationVersion = 'v3' as const\n readonly provider = 'content-agent'\n readonly modelId: string\n readonly supportedUrls: Record<string, RegExp[]> = {}\n\n private readonly providerPromise: Promise<ContentAgentProvider>\n private readonly threadId: string\n private readonly settings: AgentSettings | undefined\n private resolvedModel: LanguageModelV3 | null = null\n\n constructor(\n threadId: string,\n settings: AgentSettings | undefined,\n providerPromise: Promise<ContentAgentProvider>,\n ) {\n this.threadId = threadId\n this.settings = settings\n this.modelId = `content-agent:${threadId}`\n this.providerPromise = providerPromise\n }\n\n private async getModel(): Promise<LanguageModelV3> {\n if (!this.resolvedModel) {\n const provider = await this.providerPromise\n this.resolvedModel = provider.agent(this.threadId, this.settings)\n }\n return this.resolvedModel\n }\n\n async doGenerate(options: LanguageModelV3CallOptions) {\n const model = await this.getModel()\n return model.doGenerate(options)\n }\n\n async doStream(options: LanguageModelV3CallOptions) {\n const model = await this.getModel()\n return model.doStream(options)\n }\n}\n\n/**\n * Creates a Content Agent provider fully configured for a Studio context.\n *\n * This is the simplest way to use Content Agent from inside Sanity Studio.\n * The call is **synchronous** — safe to use in React components and hooks.\n * Async setup (fetching the organization ID and resolving the application)\n * is deferred to the first API call, which is already async.\n *\n * Internally handles:\n * 1. Deriving the project-scoped API URL (for CORS)\n * 2. Fetching the organization ID from project metadata\n * 3. Resolving the Studio application by workspace name\n * 4. Cookie-based auth (no token needed)\n *\n * The returned provider works exactly like one from {@link createContentAgent},\n * but `.agent()` and `.prompt()` automatically target the resolved application\n * unless explicitly overridden per-call.\n *\n * @category Studio Integration\n *\n * @example Studio component with memoized provider\n * ```ts\n * import { useMemo } from 'react'\n * import { createStudioAgent } from 'content-agent'\n * import { useClient, useWorkspace } from 'sanity'\n * import { generateText } from 'ai'\n *\n * function MyComponent() {\n * const client = useClient({ apiVersion: '2024-01-01' })\n * const { name: workspace } = useWorkspace()\n *\n * const contentAgent = useMemo(\n * () => createStudioAgent(client, workspace),\n * [client, workspace],\n * )\n *\n * async function handleSummarize() {\n * const { text } = await generateText({\n * model: contentAgent.agent('my-thread'),\n * prompt: 'Summarize my content',\n * })\n * console.log(text)\n * }\n * }\n * ```\n *\n * @param client - Any object with a `config()` returning `projectId` and `dataset`.\n * @param workspace - The active workspace name. Available via `useWorkspace().name` in Studio.\n * @param options - Optional overrides (custom fetch, additional provider settings).\n */\nexport function createStudioAgent(\n client: SanityClientLike,\n workspace: string,\n options?: StudioAgentOptions,\n): ContentAgentProvider {\n const { projectId, dataset } = client.config()\n\n if (!projectId) {\n throw new Error('createStudioAgent: client is missing `projectId` in its config')\n }\n if (!dataset) {\n throw new Error('createStudioAgent: client is missing `dataset` in its config')\n }\n\n const { apiHost } = client.config()\n const fetchFn = options?.fetch ?? globalThis.fetch\n const baseURL = deriveBaseUrl(apiHost, projectId)\n const cacheKey = `${projectId}.${dataset}.${workspace}`\n\n // Reuse an existing setup promise for the same project/dataset/workspace,\n // or start a new one. Custom fetch or providerOptions bypass the cache\n // since they indicate a non-default configuration (e.g. tests).\n const useCache = !options?.fetch && !options?.providerOptions\n\n let providerPromise: Promise<ContentAgentProvider>\n\n if (useCache && providerCache.has(cacheKey)) {\n providerPromise = providerCache.get(cacheKey)!\n } else {\n providerPromise = initProvider(\n projectId,\n dataset,\n workspace,\n apiHost || 'https://api.sanity.io',\n baseURL,\n fetchFn,\n options?.providerOptions,\n )\n\n if (useCache) {\n providerCache.set(cacheKey, providerPromise)\n\n // Evict on failure so a transient error doesn't stick forever\n providerPromise.catch(() => {\n providerCache.delete(cacheKey)\n })\n }\n }\n\n const awaitProvider = async <T>(fn: (provider: ContentAgentProvider) => Promise<T>): Promise<T> =>\n fn(await providerPromise)\n\n return {\n agent(threadId: string, settings?: AgentSettings): LanguageModelV3 {\n return new LazyContentAgentModel(threadId, settings, providerPromise)\n },\n\n applications() {\n return awaitProvider((p) => p.applications())\n },\n\n resolveApplication(resolveClient: SanityClientLike, resolveWorkspace: string) {\n return awaitProvider((p) => p.resolveApplication(resolveClient, resolveWorkspace))\n },\n\n prompt(settings, generateOptions) {\n return awaitProvider((p) => p.prompt(settings, generateOptions))\n },\n }\n}\n"],"names":["text"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "content-agent",
3
- "version": "0.5.3",
3
+ "version": "0.7.0",
4
4
  "description": "Vercel AI SDK provider for Sanity Content Agent API",
5
5
  "keywords": [
6
6
  "sanity",