content-agent 0.1.1 → 0.2.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 +19 -5
- package/dist/index.d.ts +107 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -8
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ Use `streamText` from the AI SDK for streaming responses:
|
|
|
38
38
|
```typescript
|
|
39
39
|
import { streamText } from "ai";
|
|
40
40
|
|
|
41
|
-
const { textStream } =
|
|
41
|
+
const { textStream } = streamText({
|
|
42
42
|
model: contentAgent.agent("my-thread"),
|
|
43
43
|
prompt: "Summarize my latest content",
|
|
44
44
|
});
|
|
@@ -48,15 +48,29 @@ for await (const text of textStream) {
|
|
|
48
48
|
}
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
## Applications
|
|
52
|
+
|
|
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.
|
|
54
|
+
|
|
55
|
+
List available applications for your organization, then target one by its key:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
const apps = await contentAgent.applications();
|
|
59
|
+
|
|
60
|
+
const app = apps.find((app) => app.title === "My Studio");
|
|
61
|
+
|
|
62
|
+
const model = contentAgent.agent("my-thread", {
|
|
63
|
+
application: { key: app.key },
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
51
67
|
## Configuration
|
|
52
68
|
|
|
53
|
-
Pass settings to `.agent()` to configure capabilities
|
|
69
|
+
Pass settings to `.agent()` to configure capabilities:
|
|
54
70
|
|
|
55
71
|
```typescript
|
|
56
72
|
const model = contentAgent.agent("my-thread", {
|
|
57
|
-
application: {
|
|
58
|
-
key: "projectId.datasetName",
|
|
59
|
-
},
|
|
73
|
+
application: { key: "your-application-key" },
|
|
60
74
|
config: {
|
|
61
75
|
capabilities: {
|
|
62
76
|
read: true,
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { LanguageModelV1, LanguageModelV1CallOptions, LanguageModelV1CallWarning
|
|
|
4
4
|
* Do not make direct changes to the file.
|
|
5
5
|
*/
|
|
6
6
|
type paths = {
|
|
7
|
-
'/
|
|
7
|
+
'/{organizationId}/threads/{threadId}': {
|
|
8
8
|
parameters: {
|
|
9
9
|
query?: never;
|
|
10
10
|
header?: never;
|
|
@@ -25,7 +25,7 @@ type paths = {
|
|
|
25
25
|
patch?: never;
|
|
26
26
|
trace?: never;
|
|
27
27
|
};
|
|
28
|
-
'/
|
|
28
|
+
'/prompt': {
|
|
29
29
|
parameters: {
|
|
30
30
|
query?: never;
|
|
31
31
|
header?: never;
|
|
@@ -35,11 +35,11 @@ type paths = {
|
|
|
35
35
|
get?: never;
|
|
36
36
|
put?: never;
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
39
|
-
* @description Stateless one-shot
|
|
38
|
+
* Send a one-shot prompt
|
|
39
|
+
* @description Stateless one-shot prompt endpoint. No thread management or message persistence.
|
|
40
40
|
* Ideal for simple, single-turn interactions.
|
|
41
41
|
*/
|
|
42
|
-
post: operations['
|
|
42
|
+
post: operations['prompt'];
|
|
43
43
|
delete?: never;
|
|
44
44
|
options?: never;
|
|
45
45
|
head?: never;
|
|
@@ -50,17 +50,7 @@ type paths = {
|
|
|
50
50
|
type components = {
|
|
51
51
|
schemas: {
|
|
52
52
|
ChatRequest: {
|
|
53
|
-
/**
|
|
54
|
-
* @description Your Sanity organization ID
|
|
55
|
-
* @example abc123
|
|
56
|
-
*/
|
|
57
|
-
organizationId: string;
|
|
58
|
-
/**
|
|
59
|
-
* @description Unique identifier for the conversation thread
|
|
60
|
-
* @example my-conversation-thread
|
|
61
|
-
*/
|
|
62
|
-
threadId: string; /** @description Array of message objects */
|
|
63
|
-
messages: components['schemas']['Message'][];
|
|
53
|
+
/** @description Array of message objects */messages: components['schemas']['Message'][];
|
|
64
54
|
application?: components['schemas']['Application'];
|
|
65
55
|
config?: components['schemas']['Config'];
|
|
66
56
|
/**
|
|
@@ -68,8 +58,16 @@ type components = {
|
|
|
68
58
|
* @default true
|
|
69
59
|
*/
|
|
70
60
|
stream: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* @description Controls how directives in the response are formatted.
|
|
63
|
+
* - markdown (default): Directives are resolved server-side into standard markdown (e.g., links with titles).
|
|
64
|
+
* - directives: Raw directive syntax is preserved (e.g., `::document{id="doc-id"}`), useful for clients that render custom UI components.
|
|
65
|
+
* @default markdown
|
|
66
|
+
* @enum {string}
|
|
67
|
+
*/
|
|
68
|
+
format: 'markdown' | 'directives';
|
|
71
69
|
};
|
|
72
|
-
|
|
70
|
+
PromptRequest: {
|
|
73
71
|
/**
|
|
74
72
|
* @description Your Sanity organization ID
|
|
75
73
|
* @example abc123
|
|
@@ -86,6 +84,14 @@ type components = {
|
|
|
86
84
|
* @example Be concise and use bullet points
|
|
87
85
|
*/
|
|
88
86
|
instructions?: string;
|
|
87
|
+
/**
|
|
88
|
+
* @description Controls how directives in the response are formatted.
|
|
89
|
+
* - markdown (default): Directives are resolved server-side into standard markdown.
|
|
90
|
+
* - directives: Raw directive syntax is preserved for clients that render custom UI.
|
|
91
|
+
* @default markdown
|
|
92
|
+
* @enum {string}
|
|
93
|
+
*/
|
|
94
|
+
format: 'markdown' | 'directives';
|
|
89
95
|
};
|
|
90
96
|
Message: {
|
|
91
97
|
/**
|
|
@@ -125,7 +131,7 @@ type components = {
|
|
|
125
131
|
name?: string; /** @description Application title */
|
|
126
132
|
title?: string; /** @description Schema descriptor ID */
|
|
127
133
|
schemaDescriptorId?: string;
|
|
128
|
-
}; /** @description Agent configuration
|
|
134
|
+
}; /** @description Agent configuration. Controls behavior, capabilities, and document access. */
|
|
129
135
|
Config: {
|
|
130
136
|
/**
|
|
131
137
|
* @description Custom instruction string to include in the system prompt
|
|
@@ -146,6 +152,7 @@ type components = {
|
|
|
146
152
|
};
|
|
147
153
|
capabilities?: components['schemas']['Capabilities'];
|
|
148
154
|
filter?: components['schemas']['Filter'];
|
|
155
|
+
perspectives?: components['schemas']['Perspectives'];
|
|
149
156
|
};
|
|
150
157
|
/**
|
|
151
158
|
* @description Agent capabilities that control what operations are allowed.
|
|
@@ -158,6 +165,18 @@ type components = {
|
|
|
158
165
|
Capabilities: {
|
|
159
166
|
read?: components['schemas']['Capability'];
|
|
160
167
|
write?: components['schemas']['Capability'];
|
|
168
|
+
features?: components['schemas']['FeatureOverrides'];
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* @description Explicit feature overrides applied on top of capability-derived defaults.
|
|
172
|
+
* When not specified, features use values derived from read/write capability presets.
|
|
173
|
+
*/
|
|
174
|
+
FeatureOverrides: {
|
|
175
|
+
/**
|
|
176
|
+
* @description Override web search availability.
|
|
177
|
+
* By default, web search is enabled when read capability is 'standard'.
|
|
178
|
+
*/
|
|
179
|
+
webSearch?: boolean;
|
|
161
180
|
};
|
|
162
181
|
/**
|
|
163
182
|
* @description A capability can be:
|
|
@@ -168,8 +187,13 @@ type components = {
|
|
|
168
187
|
Capability: boolean | components['schemas']['CapabilityPreset'];
|
|
169
188
|
CapabilityPreset: {
|
|
170
189
|
/**
|
|
171
|
-
* @description
|
|
172
|
-
* -
|
|
190
|
+
* @description For read capability:
|
|
191
|
+
* - minimal: Basic queries only (no bulk document analysis)
|
|
192
|
+
* - standard: All read tools including bulk analysis
|
|
193
|
+
*
|
|
194
|
+
* For write capability:
|
|
195
|
+
* - minimal: Basic mutations only (no bulk mutations)
|
|
196
|
+
* - standard: All write tools including bulk mutations
|
|
173
197
|
* @enum {string}
|
|
174
198
|
*/
|
|
175
199
|
preset: 'minimal' | 'standard';
|
|
@@ -187,6 +211,28 @@ type components = {
|
|
|
187
211
|
* @example _type == 'post'
|
|
188
212
|
*/
|
|
189
213
|
write?: string;
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* @description Perspective locking configuration.
|
|
217
|
+
* Controls which document perspectives the agent can read from and write to.
|
|
218
|
+
* Values are Sanity perspective IDs: 'drafts', 'published', 'raw', or release/bundle IDs.
|
|
219
|
+
*/
|
|
220
|
+
Perspectives: {
|
|
221
|
+
/**
|
|
222
|
+
* @description Allowed read perspectives. When set, query tools can only use these perspectives.
|
|
223
|
+
* If the agent tries to use a disallowed perspective, the request is rejected with an error.
|
|
224
|
+
* @example [
|
|
225
|
+
* "drafts",
|
|
226
|
+
* "published"
|
|
227
|
+
* ]
|
|
228
|
+
*/
|
|
229
|
+
read?: string[];
|
|
230
|
+
/**
|
|
231
|
+
* @description The write perspective. When set, new documents are created in this perspective
|
|
232
|
+
* and mutations are restricted to documents whose ID matches it.
|
|
233
|
+
* @example drafts
|
|
234
|
+
*/
|
|
235
|
+
write?: string;
|
|
190
236
|
}; /** @description JSON response when streaming is disabled */
|
|
191
237
|
ChatResponse: {
|
|
192
238
|
/** @description The agent's response text */text?: string; /** @description The application key used for this conversation */
|
|
@@ -288,7 +334,18 @@ interface operations {
|
|
|
288
334
|
parameters: {
|
|
289
335
|
query?: never;
|
|
290
336
|
header?: never;
|
|
291
|
-
path
|
|
337
|
+
path: {
|
|
338
|
+
/**
|
|
339
|
+
* @description Your Sanity organization ID
|
|
340
|
+
* @example abc123
|
|
341
|
+
*/
|
|
342
|
+
organizationId: string;
|
|
343
|
+
/**
|
|
344
|
+
* @description Unique identifier for the conversation thread
|
|
345
|
+
* @example my-conversation-thread
|
|
346
|
+
*/
|
|
347
|
+
threadId: string;
|
|
348
|
+
};
|
|
292
349
|
cookie?: never;
|
|
293
350
|
};
|
|
294
351
|
requestBody: {
|
|
@@ -313,7 +370,7 @@ interface operations {
|
|
|
313
370
|
500: components['responses']['InternalServerError'];
|
|
314
371
|
};
|
|
315
372
|
};
|
|
316
|
-
|
|
373
|
+
prompt: {
|
|
317
374
|
parameters: {
|
|
318
375
|
query?: never;
|
|
319
376
|
header?: never;
|
|
@@ -322,7 +379,7 @@ interface operations {
|
|
|
322
379
|
};
|
|
323
380
|
requestBody: {
|
|
324
381
|
content: {
|
|
325
|
-
'application/json': components['schemas']['
|
|
382
|
+
'application/json': components['schemas']['PromptRequest'];
|
|
326
383
|
};
|
|
327
384
|
};
|
|
328
385
|
responses: {
|
|
@@ -343,7 +400,8 @@ interface operations {
|
|
|
343
400
|
};
|
|
344
401
|
}
|
|
345
402
|
type ChatRequest = components['schemas']['ChatRequest'];
|
|
346
|
-
type GenerateRequest = components['schemas']['
|
|
403
|
+
type GenerateRequest = components['schemas']['PromptRequest'];
|
|
404
|
+
type OutputFormat = ChatRequest['format'];
|
|
347
405
|
type ChatResponse = components['schemas']['ChatResponse'];
|
|
348
406
|
type ErrorResponse = components['schemas']['ErrorResponse'];
|
|
349
407
|
type ValidationIssue = components['schemas']['ValidationIssue'];
|
|
@@ -405,6 +463,13 @@ interface BaseAgentSettings {
|
|
|
405
463
|
* Agent configuration for controlling behavior, capabilities, and document access.
|
|
406
464
|
*/
|
|
407
465
|
config?: Config;
|
|
466
|
+
/**
|
|
467
|
+
* Controls how directives in the response are formatted.
|
|
468
|
+
* - `markdown` (default): Directives are resolved server-side into standard markdown.
|
|
469
|
+
* - `directives`: Raw directive syntax is preserved for clients that render custom UI.
|
|
470
|
+
* @default 'markdown'
|
|
471
|
+
*/
|
|
472
|
+
format?: OutputFormat;
|
|
408
473
|
}
|
|
409
474
|
/**
|
|
410
475
|
* Settings for creating an agent instance (per-thread).
|
|
@@ -494,6 +559,23 @@ interface ContentAgentProvider {
|
|
|
494
559
|
* Creates an agent for a conversation thread.
|
|
495
560
|
*/
|
|
496
561
|
agent(threadId: string, settings?: AgentSettings): LanguageModelV1;
|
|
562
|
+
/**
|
|
563
|
+
* Lists available applications for the organization.
|
|
564
|
+
*
|
|
565
|
+
* Returns all Sanity Studio applications the authenticated user has access to.
|
|
566
|
+
* Use the `key` from a returned application to target it when creating an agent.
|
|
567
|
+
*
|
|
568
|
+
* @example
|
|
569
|
+
* ```ts
|
|
570
|
+
* const apps = await contentAgent.applications()
|
|
571
|
+
* const app = apps.find((app) => app.title === "My Studio")
|
|
572
|
+
*
|
|
573
|
+
* const model = contentAgent.agent("my-thread", {
|
|
574
|
+
* application: { key: app.key },
|
|
575
|
+
* })
|
|
576
|
+
* ```
|
|
577
|
+
*/
|
|
578
|
+
applications(): Promise<Application[]>;
|
|
497
579
|
/**
|
|
498
580
|
* Sends a one-shot prompt to the Content Agent (stateless).
|
|
499
581
|
*
|
|
@@ -574,5 +656,5 @@ declare function extractTextFromStream(responseBody: ReadableStream<Uint8Array>)
|
|
|
574
656
|
* Creates a ReadableStream that parses SSE data from a response body.
|
|
575
657
|
*/
|
|
576
658
|
declare function createSSEStream(responseBody: ReadableStream<Uint8Array>): ReadableStream<LanguageModelV1StreamPart>;
|
|
577
|
-
export { type AgentSettings, type Application, type ApplicationResource, type Capabilities, type Capability, type CapabilityPreset, type CapabilityPresetValue, type ChatRequest, type ChatResponse, type Config, ContentAgentModel, type ContentAgentModelConfig, type ContentAgentProvider, type ContentAgentProviderSettings, type ErrorResponse, type Filter, type GenerateOptions, type GenerateRequest, type GenerateResult, type GenerateSettings, type Message, type MessageRole, SanityAgentError, type UserMessageContext, type ValidationIssue, buildApiUrl, buildHeaders, type components, createContentAgent, createSSEStream, extractTextFromParts, extractTextFromStream, fetchApi, mapFinishReason, type operations, parseFinishLine, parseStreamLine, type paths };
|
|
659
|
+
export { type AgentSettings, type Application, type ApplicationResource, type Capabilities, type Capability, type CapabilityPreset, type CapabilityPresetValue, type ChatRequest, type ChatResponse, type Config, ContentAgentModel, type ContentAgentModelConfig, type ContentAgentProvider, type ContentAgentProviderSettings, type ErrorResponse, type Filter, type GenerateOptions, type GenerateRequest, type GenerateResult, type GenerateSettings, type Message, type MessageRole, type OutputFormat, SanityAgentError, type UserMessageContext, type ValidationIssue, buildApiUrl, buildHeaders, type components, createContentAgent, createSSEStream, extractTextFromParts, extractTextFromStream, fetchApi, mapFinishReason, type operations, parseFinishLine, parseStreamLine, type paths };
|
|
578
660
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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":"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"}
|
package/dist/index.js
CHANGED
|
@@ -179,12 +179,11 @@ class ContentAgentModel {
|
|
|
179
179
|
}
|
|
180
180
|
buildRequestBody(options, stream) {
|
|
181
181
|
return {
|
|
182
|
-
organizationId: this.config.organizationId,
|
|
183
|
-
threadId: this.threadId,
|
|
184
182
|
messages: this.convertPromptToMessages(options.prompt),
|
|
185
183
|
stream,
|
|
186
184
|
...this.settings.application && { application: this.settings.application },
|
|
187
|
-
...this.settings.config && { config: this.settings.config }
|
|
185
|
+
...this.settings.config && { config: this.settings.config },
|
|
186
|
+
...this.settings.format && { format: this.settings.format }
|
|
188
187
|
};
|
|
189
188
|
}
|
|
190
189
|
getResponseHeaders(response) {
|
|
@@ -192,7 +191,11 @@ class ContentAgentModel {
|
|
|
192
191
|
}
|
|
193
192
|
async doGenerate(options) {
|
|
194
193
|
const body = this.buildRequestBody(options, !1), warnings = this.collectWarnings(options), response = await fetchApi({
|
|
195
|
-
url: buildApiUrl(
|
|
194
|
+
url: buildApiUrl(
|
|
195
|
+
this.config.baseURL,
|
|
196
|
+
this.config.apiVersion,
|
|
197
|
+
`/${this.config.organizationId}/threads/${this.threadId}`
|
|
198
|
+
),
|
|
196
199
|
body,
|
|
197
200
|
headers: buildHeaders(this.config.headers()),
|
|
198
201
|
signal: options.abortSignal,
|
|
@@ -209,7 +212,11 @@ class ContentAgentModel {
|
|
|
209
212
|
}
|
|
210
213
|
async doStream(options) {
|
|
211
214
|
const body = this.buildRequestBody(options, !0), warnings = this.collectWarnings(options), response = await fetchApi({
|
|
212
|
-
url: buildApiUrl(
|
|
215
|
+
url: buildApiUrl(
|
|
216
|
+
this.config.baseURL,
|
|
217
|
+
this.config.apiVersion,
|
|
218
|
+
`/${this.config.organizationId}/threads/${this.threadId}`
|
|
219
|
+
),
|
|
213
220
|
body,
|
|
214
221
|
headers: buildHeaders(this.config.headers()),
|
|
215
222
|
signal: options.abortSignal,
|
|
@@ -238,16 +245,24 @@ function createContentAgent(options) {
|
|
|
238
245
|
headers: getHeaders,
|
|
239
246
|
fetch: options.fetch
|
|
240
247
|
};
|
|
241
|
-
return { agent: (threadId, settings) => new ContentAgentModel(threadId, settings, config),
|
|
248
|
+
return { agent: (threadId, settings) => new ContentAgentModel(threadId, settings, config), applications: async () => {
|
|
249
|
+
const fetchFn = options.fetch ?? globalThis.fetch, url = buildApiUrl(baseURL, apiVersion, `/${organizationId}/applications`), headers = buildHeaders(getHeaders()), response = await fetchFn(url, { method: "GET", headers });
|
|
250
|
+
if (!response.ok) {
|
|
251
|
+
const errorText = await response.text();
|
|
252
|
+
throw new SanityAgentError(response.status, errorText);
|
|
253
|
+
}
|
|
254
|
+
return (await response.json()).applications ?? [];
|
|
255
|
+
}, prompt: async (settings, generateOptions) => {
|
|
242
256
|
const body = {
|
|
243
257
|
organizationId,
|
|
244
258
|
message: generateOptions.message,
|
|
245
259
|
stream: generateOptions.stream ?? !1,
|
|
246
260
|
...settings.application && { application: settings.application },
|
|
247
261
|
...settings.config && { config: settings.config },
|
|
248
|
-
...settings.instructions && { instructions: settings.instructions }
|
|
262
|
+
...settings.instructions && { instructions: settings.instructions },
|
|
263
|
+
...settings.format && { format: settings.format }
|
|
249
264
|
}, response = await fetchApi({
|
|
250
|
-
url: buildApiUrl(baseURL, apiVersion, "/
|
|
265
|
+
url: buildApiUrl(baseURL, apiVersion, "/prompt"),
|
|
251
266
|
body,
|
|
252
267
|
headers: buildHeaders(getHeaders()),
|
|
253
268
|
signal: generateOptions.abortSignal,
|
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 { LanguageModelV1FinishReason, LanguageModelV1StreamPart } from '@ai-sdk/provider'\nimport { isString, pickBy } from 'es-toolkit'\n\n/**\n * Builds headers for API requests, filtering out undefined values.\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 */\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 */\nexport class SanityAgentError extends Error {\n readonly status: number\n readonly isRetryable: boolean\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 }\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 */\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 */\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 * Maps API finish reasons to LanguageModelV1FinishReason.\n */\nexport function mapFinishReason(reason: string | undefined): LanguageModelV1FinishReason {\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'\n }\n}\n\n/**\n * Parses a single line from Vercel AI Data Stream Protocol.\n * Returns null if the line cannot be parsed or should be ignored.\n */\nexport function parseStreamLine(line: string): LanguageModelV1StreamPart | null {\n const trimmed = line.trim()\n if (!trimmed) return null\n\n // Format: TYPE:JSON_DATA\n // 0:\"text\" - text content\n // 2:[data] - data array (ignored)\n // d:{finishReason, usage} - finish metadata (handled separately)\n // e:{error} - error\n\n if (trimmed.startsWith('0:')) {\n try {\n const text = JSON.parse(trimmed.slice(2)) as unknown\n if (typeof text === 'string') {\n return { type: 'text-delta', textDelta: text }\n }\n } catch {\n // Ignore parse errors\n }\n } else if (trimmed.startsWith('e:')) {\n try {\n const data = JSON.parse(trimmed.slice(2)) as { error?: string }\n return { type: 'error', error: new Error(data.error ?? 'Unknown error') }\n } catch {\n return { type: 'error', error: new Error('Unknown streaming error') }\n }\n }\n\n return null\n}\n\n/**\n * Parses finish metadata from a stream line.\n * Returns the finish reason if found, null otherwise.\n */\nexport function parseFinishLine(line: string): LanguageModelV1FinishReason | null {\n const trimmed = line.trim()\n if (!trimmed.startsWith('d:')) return null\n\n try {\n const data = JSON.parse(trimmed.slice(2)) as { finishReason?: string }\n return mapFinishReason(data.finishReason)\n } catch {\n return null\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 */\nexport async function extractTextFromStream(\n responseBody: ReadableStream<Uint8Array>,\n): Promise<string> {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\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 if (line.startsWith('0:')) {\n try {\n const parsed = JSON.parse(line.slice(2)) as unknown\n if (typeof parsed === 'string') {\n text += parsed\n }\n } catch {\n // Ignore parse errors\n }\n }\n }\n }\n\n return text\n}\n\n/**\n * Creates a ReadableStream that parses SSE data from a response body.\n */\nexport function createSSEStream(\n responseBody: ReadableStream<Uint8Array>,\n): ReadableStream<LanguageModelV1StreamPart> {\n let finishReason: LanguageModelV1FinishReason = 'other'\n\n return new ReadableStream<LanguageModelV1StreamPart>({\n async start(controller) {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\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)\n if (parsed) {\n controller.enqueue(parsed)\n }\n\n const finish = parseFinishLine(line)\n if (finish) {\n finishReason = finish\n }\n }\n }\n\n // Process remaining buffer\n if (buffer.trim()) {\n const parsed = parseStreamLine(buffer)\n if (parsed) {\n controller.enqueue(parsed)\n }\n }\n\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage: { promptTokens: 0, completionTokens: 0 },\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 LanguageModelV1,\n LanguageModelV1CallOptions,\n LanguageModelV1CallWarning,\n LanguageModelV1FinishReason,\n LanguageModelV1Prompt,\n LanguageModelV1StreamPart,\n} from '@ai-sdk/provider'\nimport type { AgentSettings, Message } from './types'\nimport { buildApiUrl, buildHeaders, createSSEStream, extractTextFromParts, fetchApi } from './utils'\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\nconst UNSUPPORTED_SETTINGS = [\n 'maxTokens',\n 'temperature',\n 'topP',\n 'topK',\n 'frequencyPenalty',\n 'presencePenalty',\n 'seed',\n] as const\n\nexport class ContentAgentModel implements LanguageModelV1 {\n readonly specificationVersion = 'v1'\n readonly provider: string\n readonly modelId: string\n readonly defaultObjectGenerationMode = undefined\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 private convertPromptToMessages(prompt: LanguageModelV1Prompt): Message[] {\n const messages: Message[] = []\n\n for (const message of prompt) {\n if (message.role === 'tool') continue\n\n const content =\n message.role === 'system'\n ? message.content\n : extractTextFromParts(message.content as string | Array<{ type: string; text?: string }>)\n\n if (content) {\n messages.push({ role: message.role, content })\n }\n }\n\n return messages\n }\n\n private collectWarnings(options: LanguageModelV1CallOptions): LanguageModelV1CallWarning[] {\n const warnings: LanguageModelV1CallWarning[] = []\n\n if (options.mode.type === 'regular') {\n if (options.mode.tools?.length) {\n warnings.push({ type: 'other', message: 'Tools are not supported by Content Agent API' })\n }\n if (options.mode.toolChoice) {\n warnings.push({\n type: 'other',\n message: 'Tool choice is not supported by Content Agent API',\n })\n }\n }\n\n for (const setting of UNSUPPORTED_SETTINGS) {\n if (options[setting] !== undefined) {\n warnings.push({ type: 'unsupported-setting', setting })\n }\n }\n\n if (options.stopSequences?.length) {\n warnings.push({ type: 'unsupported-setting', setting: 'stopSequences' })\n }\n\n return warnings\n }\n\n private buildRequestBody(options: LanguageModelV1CallOptions, stream: boolean) {\n return {\n organizationId: this.config.organizationId,\n threadId: this.threadId,\n messages: this.convertPromptToMessages(options.prompt),\n stream,\n ...(this.settings.application && { application: this.settings.application }),\n ...(this.settings.config && { config: this.settings.config }),\n }\n }\n\n private getResponseHeaders(response: Response): Record<string, string> {\n return Object.fromEntries(response.headers.entries())\n }\n\n async doGenerate(options: LanguageModelV1CallOptions): Promise<{\n text?: string\n finishReason: LanguageModelV1FinishReason\n usage: { promptTokens: number; completionTokens: number }\n rawCall: { rawPrompt: unknown; rawSettings: Record<string, unknown> }\n rawResponse?: { headers?: Record<string, string> }\n warnings?: LanguageModelV1CallWarning[]\n }> {\n const body = this.buildRequestBody(options, false)\n const warnings = this.collectWarnings(options)\n\n const response = await fetchApi({\n url: buildApiUrl(this.config.baseURL, this.config.apiVersion, '/chat'),\n body,\n headers: buildHeaders(this.config.headers()),\n signal: options.abortSignal,\n fetch: this.config.fetch,\n })\n\n const responseBody = (await response.json()) as { text?: string }\n\n return {\n text: responseBody.text ?? '',\n finishReason: 'stop',\n usage: { promptTokens: 0, completionTokens: 0 },\n rawCall: { rawPrompt: body.messages, rawSettings: {} },\n rawResponse: { headers: this.getResponseHeaders(response) },\n warnings,\n }\n }\n\n async doStream(options: LanguageModelV1CallOptions): Promise<{\n stream: ReadableStream<LanguageModelV1StreamPart>\n rawCall: { rawPrompt: unknown; rawSettings: Record<string, unknown> }\n rawResponse?: { headers?: Record<string, string> }\n warnings?: LanguageModelV1CallWarning[]\n }> {\n const body = this.buildRequestBody(options, true)\n const warnings = this.collectWarnings(options)\n\n const response = await fetchApi({\n url: buildApiUrl(this.config.baseURL, this.config.apiVersion, '/chat'),\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),\n rawCall: { rawPrompt: body.messages, rawSettings: {} },\n rawResponse: { headers: this.getResponseHeaders(response) },\n warnings,\n }\n }\n}\n","import type { LanguageModelV1 } from '@ai-sdk/provider'\nimport { ContentAgentModel, type ContentAgentModelConfig } from './sanity-agent-language-model'\nimport type {\n AgentSettings,\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\nexport interface ContentAgentProvider {\n /**\n * Creates an agent for a conversation thread.\n */\n agent(threadId: string, settings?: AgentSettings): LanguageModelV1\n\n /**\n * Sends a one-shot prompt to the Content Agent (stateless).\n *\n * Unlike `.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 result = await contentAgent.prompt(\n * { instructions: \"Be concise\" },\n * { message: \"List all authors in my dataset\" }\n * )\n * console.log(result.text)\n * ```\n */\n prompt(settings: GenerateSettings, options: GenerateOptions): Promise<GenerateResult>\n}\n\n/**\n * Creates a Content Agent provider instance.\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): LanguageModelV1 => {\n return new ContentAgentModel(threadId, settings, config)\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 }\n\n const response = await fetchApi({\n url: buildApiUrl(baseURL, apiVersion, '/generate'),\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, prompt }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/utils.ts","../src/sanity-agent-language-model.ts","../src/sanity-agent-provider.ts"],"sourcesContent":["import type { LanguageModelV1FinishReason, LanguageModelV1StreamPart } from '@ai-sdk/provider'\nimport { isString, pickBy } from 'es-toolkit'\n\n/**\n * Builds headers for API requests, filtering out undefined values.\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 */\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 */\nexport class SanityAgentError extends Error {\n readonly status: number\n readonly isRetryable: boolean\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 }\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 */\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 */\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 * Maps API finish reasons to LanguageModelV1FinishReason.\n */\nexport function mapFinishReason(reason: string | undefined): LanguageModelV1FinishReason {\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'\n }\n}\n\n/**\n * Parses a single line from Vercel AI Data Stream Protocol.\n * Returns null if the line cannot be parsed or should be ignored.\n */\nexport function parseStreamLine(line: string): LanguageModelV1StreamPart | null {\n const trimmed = line.trim()\n if (!trimmed) return null\n\n // Format: TYPE:JSON_DATA\n // 0:\"text\" - text content\n // 2:[data] - data array (ignored)\n // d:{finishReason, usage} - finish metadata (handled separately)\n // e:{error} - error\n\n if (trimmed.startsWith('0:')) {\n try {\n const text = JSON.parse(trimmed.slice(2)) as unknown\n if (typeof text === 'string') {\n return { type: 'text-delta', textDelta: text }\n }\n } catch {\n // Ignore parse errors\n }\n } else if (trimmed.startsWith('e:')) {\n try {\n const data = JSON.parse(trimmed.slice(2)) as { error?: string }\n return { type: 'error', error: new Error(data.error ?? 'Unknown error') }\n } catch {\n return { type: 'error', error: new Error('Unknown streaming error') }\n }\n }\n\n return null\n}\n\n/**\n * Parses finish metadata from a stream line.\n * Returns the finish reason if found, null otherwise.\n */\nexport function parseFinishLine(line: string): LanguageModelV1FinishReason | null {\n const trimmed = line.trim()\n if (!trimmed.startsWith('d:')) return null\n\n try {\n const data = JSON.parse(trimmed.slice(2)) as { finishReason?: string }\n return mapFinishReason(data.finishReason)\n } catch {\n return null\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 */\nexport async function extractTextFromStream(\n responseBody: ReadableStream<Uint8Array>,\n): Promise<string> {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\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 if (line.startsWith('0:')) {\n try {\n const parsed = JSON.parse(line.slice(2)) as unknown\n if (typeof parsed === 'string') {\n text += parsed\n }\n } catch {\n // Ignore parse errors\n }\n }\n }\n }\n\n return text\n}\n\n/**\n * Creates a ReadableStream that parses SSE data from a response body.\n */\nexport function createSSEStream(\n responseBody: ReadableStream<Uint8Array>,\n): ReadableStream<LanguageModelV1StreamPart> {\n let finishReason: LanguageModelV1FinishReason = 'other'\n\n return new ReadableStream<LanguageModelV1StreamPart>({\n async start(controller) {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\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)\n if (parsed) {\n controller.enqueue(parsed)\n }\n\n const finish = parseFinishLine(line)\n if (finish) {\n finishReason = finish\n }\n }\n }\n\n // Process remaining buffer\n if (buffer.trim()) {\n const parsed = parseStreamLine(buffer)\n if (parsed) {\n controller.enqueue(parsed)\n }\n }\n\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage: { promptTokens: 0, completionTokens: 0 },\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 LanguageModelV1,\n LanguageModelV1CallOptions,\n LanguageModelV1CallWarning,\n LanguageModelV1FinishReason,\n LanguageModelV1Prompt,\n LanguageModelV1StreamPart,\n} from '@ai-sdk/provider'\nimport type { AgentSettings, Message } from './types'\nimport { buildApiUrl, buildHeaders, createSSEStream, extractTextFromParts, fetchApi } from './utils'\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\nconst UNSUPPORTED_SETTINGS = [\n 'maxTokens',\n 'temperature',\n 'topP',\n 'topK',\n 'frequencyPenalty',\n 'presencePenalty',\n 'seed',\n] as const\n\nexport class ContentAgentModel implements LanguageModelV1 {\n readonly specificationVersion = 'v1'\n readonly provider: string\n readonly modelId: string\n readonly defaultObjectGenerationMode = undefined\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 private convertPromptToMessages(prompt: LanguageModelV1Prompt): Message[] {\n const messages: Message[] = []\n\n for (const message of prompt) {\n if (message.role === 'tool') continue\n\n const content =\n message.role === 'system'\n ? message.content\n : extractTextFromParts(message.content as string | Array<{ type: string; text?: string }>)\n\n if (content) {\n messages.push({ role: message.role, content })\n }\n }\n\n return messages\n }\n\n private collectWarnings(options: LanguageModelV1CallOptions): LanguageModelV1CallWarning[] {\n const warnings: LanguageModelV1CallWarning[] = []\n\n if (options.mode.type === 'regular') {\n if (options.mode.tools?.length) {\n warnings.push({ type: 'other', message: 'Tools are not supported by Content Agent API' })\n }\n if (options.mode.toolChoice) {\n warnings.push({\n type: 'other',\n message: 'Tool choice is not supported by Content Agent API',\n })\n }\n }\n\n for (const setting of UNSUPPORTED_SETTINGS) {\n if (options[setting] !== undefined) {\n warnings.push({ type: 'unsupported-setting', setting })\n }\n }\n\n if (options.stopSequences?.length) {\n warnings.push({ type: 'unsupported-setting', setting: 'stopSequences' })\n }\n\n return warnings\n }\n\n private buildRequestBody(options: LanguageModelV1CallOptions, stream: boolean) {\n return {\n messages: this.convertPromptToMessages(options.prompt),\n stream,\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: LanguageModelV1CallOptions): Promise<{\n text?: string\n finishReason: LanguageModelV1FinishReason\n usage: { promptTokens: number; completionTokens: number }\n rawCall: { rawPrompt: unknown; rawSettings: Record<string, unknown> }\n rawResponse?: { headers?: Record<string, string> }\n warnings?: LanguageModelV1CallWarning[]\n }> {\n const body = this.buildRequestBody(options, false)\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 const responseBody = (await response.json()) as { text?: string }\n\n return {\n text: responseBody.text ?? '',\n finishReason: 'stop',\n usage: { promptTokens: 0, completionTokens: 0 },\n rawCall: { rawPrompt: body.messages, rawSettings: {} },\n rawResponse: { headers: this.getResponseHeaders(response) },\n warnings,\n }\n }\n\n async doStream(options: LanguageModelV1CallOptions): Promise<{\n stream: ReadableStream<LanguageModelV1StreamPart>\n rawCall: { rawPrompt: unknown; rawSettings: Record<string, unknown> }\n rawResponse?: { headers?: Record<string, string> }\n warnings?: LanguageModelV1CallWarning[]\n }> {\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),\n rawCall: { rawPrompt: body.messages, rawSettings: {} },\n rawResponse: { headers: this.getResponseHeaders(response) },\n warnings,\n }\n }\n}\n","import type { LanguageModelV1 } 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\nexport interface ContentAgentProvider {\n /**\n * Creates an agent for a conversation thread.\n */\n agent(threadId: string, settings?: AgentSettings): LanguageModelV1\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 `.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 result = await contentAgent.prompt(\n * { instructions: \"Be concise\" },\n * { message: \"List all authors in my dataset\" }\n * )\n * console.log(result.text)\n * ```\n */\n prompt(settings: GenerateSettings, options: GenerateOptions): Promise<GenerateResult>\n}\n\n/**\n * Creates a Content Agent provider instance.\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): LanguageModelV1 => {\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":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "content-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Vercel AI SDK provider for Sanity Content Agent API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@sanity/pkg-utils": "^10.4.1",
|
|
36
|
-
"@types/node": "^22.
|
|
36
|
+
"@types/node": "^22.19.7",
|
|
37
37
|
"openapi-typescript": "^7.10.1",
|
|
38
38
|
"typescript": "^5.9.3",
|
|
39
39
|
"vitest": "^4.0.18",
|
|
40
|
-
"@repo/
|
|
41
|
-
"@repo/
|
|
40
|
+
"@repo/tsconfig": "0.0.0",
|
|
41
|
+
"@repo/package.config": "0.0.0"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"ai": ">=4.0.0"
|