content-agent 0.1.1 → 0.4.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 +57 -5
- package/dist/index.d.ts +181 -68
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +263 -86
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
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,67 @@ for await (const text of textStream) {
|
|
|
48
48
|
}
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
##
|
|
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.
|
|
52
54
|
|
|
53
|
-
|
|
55
|
+
List available applications for your organization, then target one by its key:
|
|
54
56
|
|
|
55
57
|
```typescript
|
|
58
|
+
const apps = await contentAgent.applications();
|
|
59
|
+
|
|
60
|
+
const app = apps.find((app) => app.title === "My Studio");
|
|
61
|
+
|
|
56
62
|
const model = contentAgent.agent("my-thread", {
|
|
57
|
-
application: {
|
|
58
|
-
|
|
63
|
+
application: { key: app.key },
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Tools
|
|
68
|
+
|
|
69
|
+
Pass AI SDK tools to `streamText` or `generateText` — tool schemas are forwarded to the agent, and execution happens locally on the client:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { streamText, tool, stepCountIs } from "ai";
|
|
73
|
+
import { z } from "zod";
|
|
74
|
+
|
|
75
|
+
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.`,
|
|
78
|
+
tools: {
|
|
79
|
+
submit_for_review: tool({
|
|
80
|
+
description: `Submit a document for editorial review. The document must be in draft state.`,
|
|
81
|
+
inputSchema: z.object({
|
|
82
|
+
documentId: z.string().describe("The Sanity document _id"),
|
|
83
|
+
email: z.string().email().describe("Assign a specific reviewer"),
|
|
84
|
+
note: z.string().optional().describe("Note for the reviewer"),
|
|
85
|
+
}),
|
|
86
|
+
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
|
+
},
|
|
98
|
+
}),
|
|
59
99
|
},
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
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
|
+
## Configuration
|
|
106
|
+
|
|
107
|
+
Pass settings to `.agent()` to configure capabilities:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
const model = contentAgent.agent("my-thread", {
|
|
111
|
+
application: { key: "your-application-key" },
|
|
60
112
|
config: {
|
|
61
113
|
capabilities: {
|
|
62
114
|
read: true,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ClientToolDefinition, HeadlessErrorResponse } from "@sanity/agent-types";
|
|
2
|
+
import { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3FinishReason, LanguageModelV3GenerateResult, LanguageModelV3StreamPart, LanguageModelV3StreamResult, SharedV3Warning } from "@ai-sdk/provider";
|
|
2
3
|
/**
|
|
3
4
|
* This file was auto-generated by openapi-typescript.
|
|
4
5
|
* Do not make direct changes to the file.
|
|
5
6
|
*/
|
|
6
7
|
type paths = {
|
|
7
|
-
'/
|
|
8
|
+
'/{organizationId}/threads/{threadId}': {
|
|
8
9
|
parameters: {
|
|
9
10
|
query?: never;
|
|
10
11
|
header?: never;
|
|
@@ -25,7 +26,7 @@ type paths = {
|
|
|
25
26
|
patch?: never;
|
|
26
27
|
trace?: never;
|
|
27
28
|
};
|
|
28
|
-
'/
|
|
29
|
+
'/prompt': {
|
|
29
30
|
parameters: {
|
|
30
31
|
query?: never;
|
|
31
32
|
header?: never;
|
|
@@ -35,11 +36,11 @@ type paths = {
|
|
|
35
36
|
get?: never;
|
|
36
37
|
put?: never;
|
|
37
38
|
/**
|
|
38
|
-
*
|
|
39
|
-
* @description Stateless one-shot
|
|
39
|
+
* Send a one-shot prompt
|
|
40
|
+
* @description Stateless one-shot prompt endpoint. No thread management or message persistence.
|
|
40
41
|
* Ideal for simple, single-turn interactions.
|
|
41
42
|
*/
|
|
42
|
-
post: operations['
|
|
43
|
+
post: operations['prompt'];
|
|
43
44
|
delete?: never;
|
|
44
45
|
options?: never;
|
|
45
46
|
head?: never;
|
|
@@ -50,17 +51,7 @@ type paths = {
|
|
|
50
51
|
type components = {
|
|
51
52
|
schemas: {
|
|
52
53
|
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'][];
|
|
54
|
+
/** @description Array of message objects */messages: components['schemas']['Message'][];
|
|
64
55
|
application?: components['schemas']['Application'];
|
|
65
56
|
config?: components['schemas']['Config'];
|
|
66
57
|
/**
|
|
@@ -68,8 +59,16 @@ type components = {
|
|
|
68
59
|
* @default true
|
|
69
60
|
*/
|
|
70
61
|
stream: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* @description Controls how directives in the response are formatted.
|
|
64
|
+
* - markdown (default): Directives are resolved server-side into standard markdown (e.g., links with titles).
|
|
65
|
+
* - directives: Raw directive syntax is preserved (e.g., `::document{id="doc-id"}`), useful for clients that render custom UI components.
|
|
66
|
+
* @default markdown
|
|
67
|
+
* @enum {string}
|
|
68
|
+
*/
|
|
69
|
+
format: 'markdown' | 'directives';
|
|
71
70
|
};
|
|
72
|
-
|
|
71
|
+
PromptRequest: {
|
|
73
72
|
/**
|
|
74
73
|
* @description Your Sanity organization ID
|
|
75
74
|
* @example abc123
|
|
@@ -86,6 +85,14 @@ type components = {
|
|
|
86
85
|
* @example Be concise and use bullet points
|
|
87
86
|
*/
|
|
88
87
|
instructions?: string;
|
|
88
|
+
/**
|
|
89
|
+
* @description Controls how directives in the response are formatted.
|
|
90
|
+
* - markdown (default): Directives are resolved server-side into standard markdown.
|
|
91
|
+
* - directives: Raw directive syntax is preserved for clients that render custom UI.
|
|
92
|
+
* @default markdown
|
|
93
|
+
* @enum {string}
|
|
94
|
+
*/
|
|
95
|
+
format: 'markdown' | 'directives';
|
|
89
96
|
};
|
|
90
97
|
Message: {
|
|
91
98
|
/**
|
|
@@ -125,7 +132,7 @@ type components = {
|
|
|
125
132
|
name?: string; /** @description Application title */
|
|
126
133
|
title?: string; /** @description Schema descriptor ID */
|
|
127
134
|
schemaDescriptorId?: string;
|
|
128
|
-
}; /** @description Agent configuration
|
|
135
|
+
}; /** @description Agent configuration. Controls behavior, capabilities, and document access. */
|
|
129
136
|
Config: {
|
|
130
137
|
/**
|
|
131
138
|
* @description Custom instruction string to include in the system prompt
|
|
@@ -146,6 +153,7 @@ type components = {
|
|
|
146
153
|
};
|
|
147
154
|
capabilities?: components['schemas']['Capabilities'];
|
|
148
155
|
filter?: components['schemas']['Filter'];
|
|
156
|
+
perspectives?: components['schemas']['Perspectives'];
|
|
149
157
|
};
|
|
150
158
|
/**
|
|
151
159
|
* @description Agent capabilities that control what operations are allowed.
|
|
@@ -158,6 +166,18 @@ type components = {
|
|
|
158
166
|
Capabilities: {
|
|
159
167
|
read?: components['schemas']['Capability'];
|
|
160
168
|
write?: components['schemas']['Capability'];
|
|
169
|
+
features?: components['schemas']['FeatureOverrides'];
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* @description Explicit feature overrides applied on top of capability-derived defaults.
|
|
173
|
+
* When not specified, features use values derived from read/write capability presets.
|
|
174
|
+
*/
|
|
175
|
+
FeatureOverrides: {
|
|
176
|
+
/**
|
|
177
|
+
* @description Override web search availability.
|
|
178
|
+
* By default, web search is enabled when read capability is 'standard'.
|
|
179
|
+
*/
|
|
180
|
+
webSearch?: boolean;
|
|
161
181
|
};
|
|
162
182
|
/**
|
|
163
183
|
* @description A capability can be:
|
|
@@ -168,8 +188,13 @@ type components = {
|
|
|
168
188
|
Capability: boolean | components['schemas']['CapabilityPreset'];
|
|
169
189
|
CapabilityPreset: {
|
|
170
190
|
/**
|
|
171
|
-
* @description
|
|
172
|
-
* -
|
|
191
|
+
* @description For read capability:
|
|
192
|
+
* - minimal: Basic queries only (no bulk document analysis)
|
|
193
|
+
* - standard: All read tools including bulk analysis
|
|
194
|
+
*
|
|
195
|
+
* For write capability:
|
|
196
|
+
* - minimal: Basic mutations only (no bulk mutations)
|
|
197
|
+
* - standard: All write tools including bulk mutations
|
|
173
198
|
* @enum {string}
|
|
174
199
|
*/
|
|
175
200
|
preset: 'minimal' | 'standard';
|
|
@@ -187,6 +212,28 @@ type components = {
|
|
|
187
212
|
* @example _type == 'post'
|
|
188
213
|
*/
|
|
189
214
|
write?: string;
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* @description Perspective locking configuration.
|
|
218
|
+
* Controls which document perspectives the agent can read from and write to.
|
|
219
|
+
* Values are Sanity perspective IDs: 'drafts', 'published', 'raw', or release/bundle IDs.
|
|
220
|
+
*/
|
|
221
|
+
Perspectives: {
|
|
222
|
+
/**
|
|
223
|
+
* @description Allowed read perspectives. When set, query tools can only use these perspectives.
|
|
224
|
+
* If the agent tries to use a disallowed perspective, the request is rejected with an error.
|
|
225
|
+
* @example [
|
|
226
|
+
* "drafts",
|
|
227
|
+
* "published"
|
|
228
|
+
* ]
|
|
229
|
+
*/
|
|
230
|
+
read?: string[];
|
|
231
|
+
/**
|
|
232
|
+
* @description The write perspective. When set, new documents are created in this perspective
|
|
233
|
+
* and mutations are restricted to documents whose ID matches it.
|
|
234
|
+
* @example drafts
|
|
235
|
+
*/
|
|
236
|
+
write?: string;
|
|
190
237
|
}; /** @description JSON response when streaming is disabled */
|
|
191
238
|
ChatResponse: {
|
|
192
239
|
/** @description The agent's response text */text?: string; /** @description The application key used for this conversation */
|
|
@@ -288,7 +335,18 @@ interface operations {
|
|
|
288
335
|
parameters: {
|
|
289
336
|
query?: never;
|
|
290
337
|
header?: never;
|
|
291
|
-
path
|
|
338
|
+
path: {
|
|
339
|
+
/**
|
|
340
|
+
* @description Your Sanity organization ID
|
|
341
|
+
* @example abc123
|
|
342
|
+
*/
|
|
343
|
+
organizationId: string;
|
|
344
|
+
/**
|
|
345
|
+
* @description Unique identifier for the conversation thread
|
|
346
|
+
* @example my-conversation-thread
|
|
347
|
+
*/
|
|
348
|
+
threadId: string;
|
|
349
|
+
};
|
|
292
350
|
cookie?: never;
|
|
293
351
|
};
|
|
294
352
|
requestBody: {
|
|
@@ -313,7 +371,7 @@ interface operations {
|
|
|
313
371
|
500: components['responses']['InternalServerError'];
|
|
314
372
|
};
|
|
315
373
|
};
|
|
316
|
-
|
|
374
|
+
prompt: {
|
|
317
375
|
parameters: {
|
|
318
376
|
query?: never;
|
|
319
377
|
header?: never;
|
|
@@ -322,7 +380,7 @@ interface operations {
|
|
|
322
380
|
};
|
|
323
381
|
requestBody: {
|
|
324
382
|
content: {
|
|
325
|
-
'application/json': components['schemas']['
|
|
383
|
+
'application/json': components['schemas']['PromptRequest'];
|
|
326
384
|
};
|
|
327
385
|
};
|
|
328
386
|
responses: {
|
|
@@ -343,7 +401,8 @@ interface operations {
|
|
|
343
401
|
};
|
|
344
402
|
}
|
|
345
403
|
type ChatRequest = components['schemas']['ChatRequest'];
|
|
346
|
-
type GenerateRequest = components['schemas']['
|
|
404
|
+
type GenerateRequest = components['schemas']['PromptRequest'];
|
|
405
|
+
type OutputFormat = ChatRequest['format'];
|
|
347
406
|
type ChatResponse = components['schemas']['ChatResponse'];
|
|
348
407
|
type ErrorResponse = components['schemas']['ErrorResponse'];
|
|
349
408
|
type ValidationIssue = components['schemas']['ValidationIssue'];
|
|
@@ -405,6 +464,13 @@ interface BaseAgentSettings {
|
|
|
405
464
|
* Agent configuration for controlling behavior, capabilities, and document access.
|
|
406
465
|
*/
|
|
407
466
|
config?: Config;
|
|
467
|
+
/**
|
|
468
|
+
* Controls how directives in the response are formatted.
|
|
469
|
+
* - `markdown` (default): Directives are resolved server-side into standard markdown.
|
|
470
|
+
* - `directives`: Raw directive syntax is preserved for clients that render custom UI.
|
|
471
|
+
* @default 'markdown'
|
|
472
|
+
*/
|
|
473
|
+
format?: OutputFormat;
|
|
408
474
|
}
|
|
409
475
|
/**
|
|
410
476
|
* Settings for creating an agent instance (per-thread).
|
|
@@ -448,52 +514,63 @@ interface ContentAgentModelConfig {
|
|
|
448
514
|
headers: () => Record<string, string | undefined>;
|
|
449
515
|
fetch?: typeof globalThis.fetch;
|
|
450
516
|
}
|
|
451
|
-
declare class ContentAgentModel implements
|
|
452
|
-
readonly specificationVersion
|
|
517
|
+
declare class ContentAgentModel implements LanguageModelV3 {
|
|
518
|
+
readonly specificationVersion: "v3";
|
|
453
519
|
readonly provider: string;
|
|
454
520
|
readonly modelId: string;
|
|
455
|
-
readonly
|
|
521
|
+
readonly supportedUrls: Record<string, RegExp[]>;
|
|
456
522
|
private readonly config;
|
|
457
523
|
private readonly threadId;
|
|
458
524
|
private readonly settings;
|
|
459
525
|
constructor(threadId: string, settings: AgentSettings | undefined, config: ContentAgentModelConfig);
|
|
526
|
+
/**
|
|
527
|
+
* Converts a LanguageModelV3Prompt into wire messages for the agent API.
|
|
528
|
+
*
|
|
529
|
+
* Handles all message roles:
|
|
530
|
+
* - system: plain text system messages
|
|
531
|
+
* - user: extracts text from content parts
|
|
532
|
+
* - assistant: extracts text and/or tool-call parts
|
|
533
|
+
* - tool: converts tool-result parts for the API
|
|
534
|
+
*/
|
|
460
535
|
private convertPromptToMessages;
|
|
536
|
+
/**
|
|
537
|
+
* Extracts client tool definitions from the model call options.
|
|
538
|
+
* Only the schemas are sent — execute functions stay on the client.
|
|
539
|
+
*/
|
|
540
|
+
private extractClientTools;
|
|
461
541
|
private collectWarnings;
|
|
462
542
|
private buildRequestBody;
|
|
463
543
|
private getResponseHeaders;
|
|
464
|
-
doGenerate(options:
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
rawCall: {
|
|
472
|
-
rawPrompt: unknown;
|
|
473
|
-
rawSettings: Record<string, unknown>;
|
|
474
|
-
};
|
|
475
|
-
rawResponse?: {
|
|
476
|
-
headers?: Record<string, string>;
|
|
477
|
-
};
|
|
478
|
-
warnings?: LanguageModelV1CallWarning[];
|
|
479
|
-
}>;
|
|
480
|
-
doStream(options: LanguageModelV1CallOptions): Promise<{
|
|
481
|
-
stream: ReadableStream<LanguageModelV1StreamPart>;
|
|
482
|
-
rawCall: {
|
|
483
|
-
rawPrompt: unknown;
|
|
484
|
-
rawSettings: Record<string, unknown>;
|
|
485
|
-
};
|
|
486
|
-
rawResponse?: {
|
|
487
|
-
headers?: Record<string, string>;
|
|
488
|
-
};
|
|
489
|
-
warnings?: LanguageModelV1CallWarning[];
|
|
490
|
-
}>;
|
|
544
|
+
doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult>;
|
|
545
|
+
/**
|
|
546
|
+
* Parses a streamed response body into content parts (text and tool calls)
|
|
547
|
+
* and a finish reason. Used by doGenerate to buffer the full response.
|
|
548
|
+
*/
|
|
549
|
+
private extractContentFromStream;
|
|
550
|
+
doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult>;
|
|
491
551
|
}
|
|
492
552
|
interface ContentAgentProvider {
|
|
493
553
|
/**
|
|
494
554
|
* Creates an agent for a conversation thread.
|
|
495
555
|
*/
|
|
496
|
-
agent(threadId: string, settings?: AgentSettings):
|
|
556
|
+
agent(threadId: string, settings?: AgentSettings): LanguageModelV3;
|
|
557
|
+
/**
|
|
558
|
+
* Lists available applications for the organization.
|
|
559
|
+
*
|
|
560
|
+
* Returns all Sanity Studio applications the authenticated user has access to.
|
|
561
|
+
* Use the `key` from a returned application to target it when creating an agent.
|
|
562
|
+
*
|
|
563
|
+
* @example
|
|
564
|
+
* ```ts
|
|
565
|
+
* const apps = await contentAgent.applications()
|
|
566
|
+
* const app = apps.find((app) => app.title === "My Studio")
|
|
567
|
+
*
|
|
568
|
+
* const model = contentAgent.agent("my-thread", {
|
|
569
|
+
* application: { key: app.key },
|
|
570
|
+
* })
|
|
571
|
+
* ```
|
|
572
|
+
*/
|
|
573
|
+
applications(): Promise<Application[]>;
|
|
497
574
|
/**
|
|
498
575
|
* Sends a one-shot prompt to the Content Agent (stateless).
|
|
499
576
|
*
|
|
@@ -526,12 +603,35 @@ declare function buildHeaders(configHeaders: Record<string, string | undefined>,
|
|
|
526
603
|
declare function buildApiUrl(baseURL: string, apiVersion: string, endpoint: string): string;
|
|
527
604
|
/**
|
|
528
605
|
* Custom error class for Sanity Agent API errors.
|
|
606
|
+
* The {@link body} is parsed from the JSON response and follows the
|
|
607
|
+
* {@link HeadlessErrorResponse} shape defined in `@sanity/agent-types`.
|
|
529
608
|
*/
|
|
530
609
|
declare class SanityAgentError extends Error {
|
|
531
610
|
readonly status: number;
|
|
532
611
|
readonly isRetryable: boolean;
|
|
612
|
+
readonly body: Partial<HeadlessErrorResponse>;
|
|
533
613
|
constructor(status: number, message: string);
|
|
614
|
+
private static parseBody;
|
|
534
615
|
}
|
|
616
|
+
declare const GENERIC_ERROR_MESSAGE = "Sorry, something went wrong. Please try again.";
|
|
617
|
+
type AgentErrorType = {
|
|
618
|
+
type: 'no_applications';
|
|
619
|
+
} | {
|
|
620
|
+
type: 'application_not_found';
|
|
621
|
+
} | {
|
|
622
|
+
type: 'unknown';
|
|
623
|
+
};
|
|
624
|
+
/**
|
|
625
|
+
* Classifies a caught error from the Content Agent API into a known error type.
|
|
626
|
+
* Useful for clients that need to take different actions per error (e.g. show
|
|
627
|
+
* resource-selection buttons). For the user-facing message, use {@link getAgentErrorMessage}.
|
|
628
|
+
*/
|
|
629
|
+
declare function classifyAgentError(error: unknown): AgentErrorType;
|
|
630
|
+
/**
|
|
631
|
+
* Extracts a user-facing error message from an agent API error.
|
|
632
|
+
* Returns the message sent by the API when available, otherwise a generic fallback.
|
|
633
|
+
*/
|
|
634
|
+
declare function getAgentErrorMessage(error: unknown): string;
|
|
535
635
|
interface FetchOptions {
|
|
536
636
|
url: string;
|
|
537
637
|
body: unknown;
|
|
@@ -552,27 +652,40 @@ declare function extractTextFromParts(content: string | Array<{
|
|
|
552
652
|
text?: string;
|
|
553
653
|
}>): string;
|
|
554
654
|
/**
|
|
555
|
-
* Maps API finish reasons to
|
|
655
|
+
* Maps API finish reasons to LanguageModelV3FinishReason.
|
|
556
656
|
*/
|
|
557
|
-
declare function mapFinishReason(reason: string | undefined):
|
|
657
|
+
declare function mapFinishReason(reason: string | undefined): LanguageModelV3FinishReason;
|
|
658
|
+
type ParsedStreamLine = {
|
|
659
|
+
kind: 'part';
|
|
660
|
+
part: LanguageModelV3StreamPart;
|
|
661
|
+
} | {
|
|
662
|
+
kind: 'finish';
|
|
663
|
+
finishReason: LanguageModelV3FinishReason;
|
|
664
|
+
};
|
|
558
665
|
/**
|
|
559
|
-
* Parses a single line from Vercel AI Data Stream Protocol.
|
|
666
|
+
* Parses a single line from the Vercel AI Data Stream Protocol.
|
|
560
667
|
* Returns null if the line cannot be parsed or should be ignored.
|
|
668
|
+
*
|
|
669
|
+
* Protocol prefixes:
|
|
670
|
+
* 0:"text" – text content
|
|
671
|
+
* 2:[data] – data array (ignored)
|
|
672
|
+
* 3:"error" – error
|
|
673
|
+
* b:{toolCallId,toolName,args} – client tool call
|
|
674
|
+
* d:{finishReason, usage} – finish message
|
|
675
|
+
* e:{finishReason, usage} – finish step
|
|
676
|
+
*
|
|
677
|
+
* @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol
|
|
561
678
|
*/
|
|
562
|
-
declare function parseStreamLine(line: string):
|
|
563
|
-
/**
|
|
564
|
-
* Parses finish metadata from a stream line.
|
|
565
|
-
* Returns the finish reason if found, null otherwise.
|
|
566
|
-
*/
|
|
567
|
-
declare function parseFinishLine(line: string): LanguageModelV1FinishReason | null;
|
|
679
|
+
declare function parseStreamLine(line: string, textContentId: string): ParsedStreamLine | null;
|
|
568
680
|
/**
|
|
569
681
|
* Extracts accumulated text from a streaming response body.
|
|
570
682
|
* Used for simple streaming cases where only the final text is needed.
|
|
571
683
|
*/
|
|
572
684
|
declare function extractTextFromStream(responseBody: ReadableStream<Uint8Array>): Promise<string>;
|
|
573
685
|
/**
|
|
574
|
-
* Creates a ReadableStream that parses SSE data from a response body
|
|
686
|
+
* Creates a ReadableStream that parses SSE data from a response body
|
|
687
|
+
* and emits LanguageModelV3 stream parts with proper lifecycle events.
|
|
575
688
|
*/
|
|
576
|
-
declare function createSSEStream(responseBody: ReadableStream<Uint8Array
|
|
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,
|
|
689
|
+
declare function createSSEStream(responseBody: ReadableStream<Uint8Array>, warnings: SharedV3Warning[]): ReadableStream<LanguageModelV3StreamPart>;
|
|
690
|
+
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 };
|
|
578
691
|
//# 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":"
|
|
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
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { pickBy, isString } from "es-toolkit";
|
|
1
|
+
import { pickBy, isString, groupBy } from "es-toolkit";
|
|
2
|
+
import { HEADLESS_ERROR_CODES } from "@sanity/agent-types";
|
|
2
3
|
function buildHeaders(configHeaders, additionalHeaders) {
|
|
3
4
|
return pickBy(
|
|
4
5
|
{
|
|
@@ -15,10 +16,34 @@ function buildApiUrl(baseURL, apiVersion, endpoint) {
|
|
|
15
16
|
class SanityAgentError extends Error {
|
|
16
17
|
status;
|
|
17
18
|
isRetryable;
|
|
19
|
+
body;
|
|
18
20
|
constructor(status, message) {
|
|
19
|
-
super(`Sanity Agent API error: ${status} ${message}`), this.name = "SanityAgentError", this.status = status, this.isRetryable = status >= 500;
|
|
21
|
+
super(`Sanity Agent API error: ${status} ${message}`), this.name = "SanityAgentError", this.status = status, this.isRetryable = status >= 500, this.body = SanityAgentError.parseBody(message);
|
|
22
|
+
}
|
|
23
|
+
static parseBody(message) {
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(message);
|
|
26
|
+
} catch {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
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) {
|
|
36
|
+
case HEADLESS_ERROR_CODES.NO_COMPATIBLE_APPLICATIONS:
|
|
37
|
+
return { type: "no_applications" };
|
|
38
|
+
case HEADLESS_ERROR_CODES.APPLICATION_NOT_FOUND:
|
|
39
|
+
return { type: "application_not_found" };
|
|
40
|
+
default:
|
|
41
|
+
return { type: "unknown" };
|
|
20
42
|
}
|
|
21
43
|
}
|
|
44
|
+
function getAgentErrorMessage(error) {
|
|
45
|
+
return error instanceof SanityAgentError && error.body.message ? error.body.message : GENERIC_ERROR_MESSAGE;
|
|
46
|
+
}
|
|
22
47
|
async function fetchApi(options) {
|
|
23
48
|
const response = await (options.fetch ?? globalThis.fetch)(options.url, {
|
|
24
49
|
method: "POST",
|
|
@@ -38,71 +63,116 @@ function extractTextFromParts(content) {
|
|
|
38
63
|
).map((part) => part.text).join(`
|
|
39
64
|
`);
|
|
40
65
|
}
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
function parseStreamLine(line) {
|
|
54
|
-
const trimmed = line.trim();
|
|
55
|
-
if (!trimmed) return null;
|
|
56
|
-
if (trimmed.startsWith("0:"))
|
|
57
|
-
try {
|
|
58
|
-
const text = JSON.parse(trimmed.slice(2));
|
|
59
|
-
if (typeof text == "string")
|
|
60
|
-
return { type: "text-delta", textDelta: text };
|
|
61
|
-
} catch {
|
|
66
|
+
function createEmptyUsage() {
|
|
67
|
+
return {
|
|
68
|
+
inputTokens: {
|
|
69
|
+
total: 0,
|
|
70
|
+
noCache: void 0,
|
|
71
|
+
cacheRead: void 0,
|
|
72
|
+
cacheWrite: void 0
|
|
73
|
+
},
|
|
74
|
+
outputTokens: {
|
|
75
|
+
total: 0,
|
|
76
|
+
text: void 0,
|
|
77
|
+
reasoning: void 0
|
|
62
78
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function mapFinishReason(reason) {
|
|
82
|
+
return { unified: (() => {
|
|
83
|
+
switch (reason) {
|
|
84
|
+
case "stop":
|
|
85
|
+
case "length":
|
|
86
|
+
case "content-filter":
|
|
87
|
+
case "tool-calls":
|
|
88
|
+
case "error":
|
|
89
|
+
return reason;
|
|
90
|
+
default:
|
|
91
|
+
return "other";
|
|
69
92
|
}
|
|
70
|
-
|
|
93
|
+
})(), raw: reason };
|
|
71
94
|
}
|
|
72
|
-
function
|
|
95
|
+
function parseStreamLine(line, textContentId) {
|
|
73
96
|
const trimmed = line.trim();
|
|
74
|
-
if (!trimmed.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
97
|
+
if (!trimmed || trimmed.length < 2 || trimmed[1] !== ":") return null;
|
|
98
|
+
const prefix = trimmed[0], payload = trimmed.slice(2);
|
|
99
|
+
switch (prefix) {
|
|
100
|
+
case "0": {
|
|
101
|
+
try {
|
|
102
|
+
const text = JSON.parse(payload);
|
|
103
|
+
if (typeof text == "string")
|
|
104
|
+
return { kind: "part", part: { type: "text-delta", id: textContentId, delta: text } };
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
case "3":
|
|
110
|
+
try {
|
|
111
|
+
const msg = JSON.parse(payload);
|
|
112
|
+
return {
|
|
113
|
+
kind: "part",
|
|
114
|
+
part: {
|
|
115
|
+
type: "error",
|
|
116
|
+
error: new Error(typeof msg == "string" ? msg : "Unknown error")
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
} catch {
|
|
120
|
+
return {
|
|
121
|
+
kind: "part",
|
|
122
|
+
part: { type: "error", error: new Error("Unknown streaming error") }
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
case "b":
|
|
126
|
+
try {
|
|
127
|
+
const data = JSON.parse(payload);
|
|
128
|
+
return {
|
|
129
|
+
kind: "part",
|
|
130
|
+
part: {
|
|
131
|
+
type: "tool-call",
|
|
132
|
+
toolCallId: data.toolCallId,
|
|
133
|
+
toolName: data.toolName,
|
|
134
|
+
input: typeof data.args == "string" ? data.args : JSON.stringify(data.args)
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
} catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
case "d":
|
|
141
|
+
case "e":
|
|
142
|
+
try {
|
|
143
|
+
const data = JSON.parse(payload);
|
|
144
|
+
return { kind: "finish", finishReason: mapFinishReason(data.finishReason) };
|
|
145
|
+
} catch {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
default:
|
|
149
|
+
return null;
|
|
80
150
|
}
|
|
81
151
|
}
|
|
82
152
|
async function extractTextFromStream(responseBody) {
|
|
83
|
-
const reader = responseBody.getReader(), decoder = new TextDecoder();
|
|
153
|
+
const reader = responseBody.getReader(), decoder = new TextDecoder(), textContentId = "extract";
|
|
84
154
|
let text = "";
|
|
85
155
|
for (; ; ) {
|
|
86
156
|
const { done, value } = await reader.read();
|
|
87
157
|
if (done) break;
|
|
88
158
|
const chunk = decoder.decode(value, { stream: !0 });
|
|
89
159
|
for (const line of chunk.split(`
|
|
90
|
-
`))
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
typeof parsed == "string" && (text += parsed);
|
|
95
|
-
} catch {
|
|
96
|
-
}
|
|
160
|
+
`)) {
|
|
161
|
+
const parsed = parseStreamLine(line, textContentId);
|
|
162
|
+
parsed?.kind === "part" && parsed.part.type === "text-delta" && (text += parsed.part.delta);
|
|
163
|
+
}
|
|
97
164
|
}
|
|
98
165
|
return text;
|
|
99
166
|
}
|
|
100
|
-
function createSSEStream(responseBody) {
|
|
101
|
-
let finishReason = "other";
|
|
167
|
+
function createSSEStream(responseBody, warnings) {
|
|
168
|
+
let finishReason = { unified: "other", raw: void 0 };
|
|
169
|
+
const textContentId = crypto.randomUUID();
|
|
170
|
+
let textStarted = !1, hasToolCalls = !1;
|
|
102
171
|
return new ReadableStream({
|
|
103
172
|
async start(controller) {
|
|
104
173
|
const reader = responseBody.getReader(), decoder = new TextDecoder();
|
|
105
174
|
let buffer = "";
|
|
175
|
+
controller.enqueue({ type: "stream-start", warnings });
|
|
106
176
|
try {
|
|
107
177
|
for (; ; ) {
|
|
108
178
|
const { done, value } = await reader.read();
|
|
@@ -112,20 +182,18 @@ function createSSEStream(responseBody) {
|
|
|
112
182
|
`);
|
|
113
183
|
buffer = lines.pop() ?? "";
|
|
114
184
|
for (const line of lines) {
|
|
115
|
-
const parsed = parseStreamLine(line);
|
|
116
|
-
parsed && controller.enqueue(parsed);
|
|
117
|
-
const finish = parseFinishLine(line);
|
|
118
|
-
finish && (finishReason = finish);
|
|
185
|
+
const parsed = parseStreamLine(line, textContentId);
|
|
186
|
+
parsed?.kind === "part" ? (parsed.part.type === "text-delta" && !textStarted && (controller.enqueue({ type: "text-start", id: textContentId }), textStarted = !0), parsed.part.type === "tool-call" && (textStarted && (controller.enqueue({ type: "text-end", id: textContentId }), textStarted = !1), hasToolCalls = !0), controller.enqueue(parsed.part)) : parsed?.kind === "finish" && (finishReason = parsed.finishReason);
|
|
119
187
|
}
|
|
120
188
|
}
|
|
121
189
|
if (buffer.trim()) {
|
|
122
|
-
const parsed = parseStreamLine(buffer);
|
|
123
|
-
parsed && controller.enqueue(parsed);
|
|
190
|
+
const parsed = parseStreamLine(buffer, textContentId);
|
|
191
|
+
parsed?.kind === "part" ? (parsed.part.type === "text-delta" && !textStarted && (controller.enqueue({ type: "text-start", id: textContentId }), textStarted = !0), parsed.part.type === "tool-call" && (textStarted && (controller.enqueue({ type: "text-end", id: textContentId }), textStarted = !1), hasToolCalls = !0), controller.enqueue(parsed.part)) : parsed?.kind === "finish" && (finishReason = parsed.finishReason);
|
|
124
192
|
}
|
|
125
|
-
controller.enqueue({
|
|
193
|
+
textStarted && controller.enqueue({ type: "text-end", id: textContentId }), hasToolCalls && finishReason.unified !== "tool-calls" && (finishReason = { unified: "tool-calls", raw: finishReason.raw ?? "tool-calls" }), controller.enqueue({
|
|
126
194
|
type: "finish",
|
|
127
195
|
finishReason,
|
|
128
|
-
usage:
|
|
196
|
+
usage: createEmptyUsage()
|
|
129
197
|
});
|
|
130
198
|
} catch (error) {
|
|
131
199
|
controller.enqueue({
|
|
@@ -139,7 +207,7 @@ function createSSEStream(responseBody) {
|
|
|
139
207
|
});
|
|
140
208
|
}
|
|
141
209
|
const UNSUPPORTED_SETTINGS = [
|
|
142
|
-
"
|
|
210
|
+
"maxOutputTokens",
|
|
143
211
|
"temperature",
|
|
144
212
|
"topP",
|
|
145
213
|
"topK",
|
|
@@ -148,68 +216,168 @@ const UNSUPPORTED_SETTINGS = [
|
|
|
148
216
|
"seed"
|
|
149
217
|
];
|
|
150
218
|
class ContentAgentModel {
|
|
151
|
-
specificationVersion = "
|
|
219
|
+
specificationVersion = "v3";
|
|
152
220
|
provider;
|
|
153
221
|
modelId;
|
|
154
|
-
|
|
222
|
+
supportedUrls = {};
|
|
155
223
|
config;
|
|
156
224
|
threadId;
|
|
157
225
|
settings;
|
|
158
226
|
constructor(threadId, settings, config) {
|
|
159
227
|
this.threadId = threadId, this.modelId = `content-agent:${threadId}`, this.provider = config.provider, this.settings = settings ?? {}, this.config = config;
|
|
160
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Converts a LanguageModelV3Prompt into wire messages for the agent API.
|
|
231
|
+
*
|
|
232
|
+
* Handles all message roles:
|
|
233
|
+
* - system: plain text system messages
|
|
234
|
+
* - user: extracts text from content parts
|
|
235
|
+
* - assistant: extracts text and/or tool-call parts
|
|
236
|
+
* - tool: converts tool-result parts for the API
|
|
237
|
+
*/
|
|
161
238
|
convertPromptToMessages(prompt) {
|
|
162
239
|
const messages = [];
|
|
163
240
|
for (const message of prompt) {
|
|
164
|
-
if (message.role === "
|
|
165
|
-
|
|
166
|
-
|
|
241
|
+
if (message.role === "system") {
|
|
242
|
+
message.content && messages.push({ role: "system", content: message.content });
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (message.role === "tool") {
|
|
246
|
+
const toolResults = message.content.filter((part) => part.type === "tool-result").map((part) => {
|
|
247
|
+
const p = part;
|
|
248
|
+
return {
|
|
249
|
+
type: "tool-result",
|
|
250
|
+
toolCallId: p.toolCallId,
|
|
251
|
+
toolName: p.toolName,
|
|
252
|
+
output: p.output && typeof p.output == "object" && "value" in p.output ? p.output.value : p.output
|
|
253
|
+
};
|
|
254
|
+
});
|
|
255
|
+
toolResults.length > 0 && messages.push({ role: "tool", content: toolResults });
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (message.role === "assistant") {
|
|
259
|
+
const content = message.content, grouped = groupBy(content, (p) => p.type), toolCalls = grouped["tool-call"] ?? [], textParts = grouped.text ?? [];
|
|
260
|
+
if (toolCalls.length > 0) {
|
|
261
|
+
const parts = [
|
|
262
|
+
...textParts.filter((p) => p.text).map((p) => ({ type: "text", text: p.text })),
|
|
263
|
+
...toolCalls.map((tc) => ({
|
|
264
|
+
type: "tool-call",
|
|
265
|
+
toolCallId: tc.toolCallId,
|
|
266
|
+
toolName: tc.toolName,
|
|
267
|
+
input: tc.input
|
|
268
|
+
}))
|
|
269
|
+
];
|
|
270
|
+
parts.length > 0 && messages.push({ role: "assistant", content: parts });
|
|
271
|
+
} else {
|
|
272
|
+
const text2 = extractTextFromParts(content);
|
|
273
|
+
text2 && messages.push({ role: "assistant", content: text2 });
|
|
274
|
+
}
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
const text = extractTextFromParts(message.content);
|
|
278
|
+
text && messages.push({ role: message.role, content: text });
|
|
167
279
|
}
|
|
168
280
|
return messages;
|
|
169
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* Extracts client tool definitions from the model call options.
|
|
284
|
+
* Only the schemas are sent — execute functions stay on the client.
|
|
285
|
+
*/
|
|
286
|
+
extractClientTools(options) {
|
|
287
|
+
if (!options.tools?.length) return;
|
|
288
|
+
const clientTools = options.tools.filter((t) => t.type === "function").map((t) => ({
|
|
289
|
+
type: "function",
|
|
290
|
+
name: t.name,
|
|
291
|
+
description: t.description,
|
|
292
|
+
inputSchema: t.inputSchema
|
|
293
|
+
}));
|
|
294
|
+
return clientTools.length > 0 ? clientTools : void 0;
|
|
295
|
+
}
|
|
170
296
|
collectWarnings(options) {
|
|
171
297
|
const warnings = [];
|
|
172
|
-
options.mode.type === "regular" && (options.mode.tools?.length && warnings.push({ type: "other", message: "Tools are not supported by Content Agent API" }), options.mode.toolChoice && warnings.push({
|
|
173
|
-
type: "other",
|
|
174
|
-
message: "Tool choice is not supported by Content Agent API"
|
|
175
|
-
}));
|
|
176
298
|
for (const setting of UNSUPPORTED_SETTINGS)
|
|
177
|
-
options[setting] !== void 0 && warnings.push({ type: "unsupported
|
|
178
|
-
return options.stopSequences?.length && warnings.push({ type: "unsupported
|
|
299
|
+
options[setting] !== void 0 && warnings.push({ type: "unsupported", feature: setting });
|
|
300
|
+
return options.stopSequences?.length && warnings.push({ type: "unsupported", feature: "stopSequences" }), options.responseFormat && options.responseFormat.type !== "text" && warnings.push({ type: "unsupported", feature: "responseFormat" }), warnings;
|
|
179
301
|
}
|
|
180
302
|
buildRequestBody(options, stream) {
|
|
303
|
+
const clientTools = this.extractClientTools(options), toolChoice = options.toolChoice;
|
|
181
304
|
return {
|
|
182
|
-
organizationId: this.config.organizationId,
|
|
183
|
-
threadId: this.threadId,
|
|
184
305
|
messages: this.convertPromptToMessages(options.prompt),
|
|
185
306
|
stream,
|
|
307
|
+
...clientTools && { clientTools },
|
|
308
|
+
...toolChoice && { toolChoice },
|
|
186
309
|
...this.settings.application && { application: this.settings.application },
|
|
187
|
-
...this.settings.config && { config: this.settings.config }
|
|
310
|
+
...this.settings.config && { config: this.settings.config },
|
|
311
|
+
...this.settings.format && { format: this.settings.format }
|
|
188
312
|
};
|
|
189
313
|
}
|
|
190
314
|
getResponseHeaders(response) {
|
|
191
315
|
return Object.fromEntries(response.headers.entries());
|
|
192
316
|
}
|
|
193
317
|
async doGenerate(options) {
|
|
194
|
-
const body = this.buildRequestBody(options, !
|
|
195
|
-
url: buildApiUrl(
|
|
318
|
+
const body = this.buildRequestBody(options, !0), warnings = this.collectWarnings(options), response = await fetchApi({
|
|
319
|
+
url: buildApiUrl(
|
|
320
|
+
this.config.baseURL,
|
|
321
|
+
this.config.apiVersion,
|
|
322
|
+
`/${this.config.organizationId}/threads/${this.threadId}`
|
|
323
|
+
),
|
|
196
324
|
body,
|
|
197
325
|
headers: buildHeaders(this.config.headers()),
|
|
198
326
|
signal: options.abortSignal,
|
|
199
327
|
fetch: this.config.fetch
|
|
200
328
|
});
|
|
329
|
+
if (!response.body)
|
|
330
|
+
throw new Error("No response body for generate request");
|
|
331
|
+
const { content, finishReason } = await this.extractContentFromStream(response.body);
|
|
201
332
|
return {
|
|
202
|
-
|
|
203
|
-
finishReason
|
|
204
|
-
usage:
|
|
205
|
-
|
|
206
|
-
|
|
333
|
+
content,
|
|
334
|
+
finishReason,
|
|
335
|
+
usage: createEmptyUsage(),
|
|
336
|
+
request: { body },
|
|
337
|
+
response: { headers: this.getResponseHeaders(response) },
|
|
207
338
|
warnings
|
|
208
339
|
};
|
|
209
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* Parses a streamed response body into content parts (text and tool calls)
|
|
343
|
+
* and a finish reason. Used by doGenerate to buffer the full response.
|
|
344
|
+
*/
|
|
345
|
+
async extractContentFromStream(responseBody) {
|
|
346
|
+
const reader = responseBody.getReader(), decoder = new TextDecoder(), textContentId = "generate";
|
|
347
|
+
let text = "", hasToolCalls = !1;
|
|
348
|
+
const content = [];
|
|
349
|
+
for (; ; ) {
|
|
350
|
+
const { done, value } = await reader.read();
|
|
351
|
+
if (done) break;
|
|
352
|
+
const chunk = decoder.decode(value, { stream: !0 });
|
|
353
|
+
for (const line of chunk.split(`
|
|
354
|
+
`)) {
|
|
355
|
+
const parsed = parseStreamLine(line, textContentId);
|
|
356
|
+
if (parsed?.kind === "part") {
|
|
357
|
+
if (parsed.part.type === "text-delta")
|
|
358
|
+
text += parsed.part.delta;
|
|
359
|
+
else if (parsed.part.type === "tool-call") {
|
|
360
|
+
hasToolCalls = !0;
|
|
361
|
+
const tc = parsed.part;
|
|
362
|
+
content.push({
|
|
363
|
+
type: "tool-call",
|
|
364
|
+
toolCallId: tc.toolCallId,
|
|
365
|
+
toolName: tc.toolName,
|
|
366
|
+
input: tc.input
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return text && content.unshift({ type: "text", text }), { content, finishReason: hasToolCalls ? { unified: "tool-calls", raw: "tool-calls" } : { unified: "stop", raw: void 0 } };
|
|
373
|
+
}
|
|
210
374
|
async doStream(options) {
|
|
211
375
|
const body = this.buildRequestBody(options, !0), warnings = this.collectWarnings(options), response = await fetchApi({
|
|
212
|
-
url: buildApiUrl(
|
|
376
|
+
url: buildApiUrl(
|
|
377
|
+
this.config.baseURL,
|
|
378
|
+
this.config.apiVersion,
|
|
379
|
+
`/${this.config.organizationId}/threads/${this.threadId}`
|
|
380
|
+
),
|
|
213
381
|
body,
|
|
214
382
|
headers: buildHeaders(this.config.headers()),
|
|
215
383
|
signal: options.abortSignal,
|
|
@@ -218,10 +386,9 @@ class ContentAgentModel {
|
|
|
218
386
|
if (!response.body)
|
|
219
387
|
throw new Error("No response body for streaming request");
|
|
220
388
|
return {
|
|
221
|
-
stream: createSSEStream(response.body),
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
warnings
|
|
389
|
+
stream: createSSEStream(response.body, warnings),
|
|
390
|
+
request: { body },
|
|
391
|
+
response: { headers: this.getResponseHeaders(response) }
|
|
225
392
|
};
|
|
226
393
|
}
|
|
227
394
|
}
|
|
@@ -238,16 +405,24 @@ function createContentAgent(options) {
|
|
|
238
405
|
headers: getHeaders,
|
|
239
406
|
fetch: options.fetch
|
|
240
407
|
};
|
|
241
|
-
return { agent: (threadId, settings) => new ContentAgentModel(threadId, settings, config),
|
|
408
|
+
return { agent: (threadId, settings) => new ContentAgentModel(threadId, settings, config), applications: async () => {
|
|
409
|
+
const fetchFn = options.fetch ?? globalThis.fetch, url = buildApiUrl(baseURL, apiVersion, `/${organizationId}/applications`), headers = buildHeaders(getHeaders()), response = await fetchFn(url, { method: "GET", headers });
|
|
410
|
+
if (!response.ok) {
|
|
411
|
+
const errorText = await response.text();
|
|
412
|
+
throw new SanityAgentError(response.status, errorText);
|
|
413
|
+
}
|
|
414
|
+
return (await response.json()).applications ?? [];
|
|
415
|
+
}, prompt: async (settings, generateOptions) => {
|
|
242
416
|
const body = {
|
|
243
417
|
organizationId,
|
|
244
418
|
message: generateOptions.message,
|
|
245
419
|
stream: generateOptions.stream ?? !1,
|
|
246
420
|
...settings.application && { application: settings.application },
|
|
247
421
|
...settings.config && { config: settings.config },
|
|
248
|
-
...settings.instructions && { instructions: settings.instructions }
|
|
422
|
+
...settings.instructions && { instructions: settings.instructions },
|
|
423
|
+
...settings.format && { format: settings.format }
|
|
249
424
|
}, response = await fetchApi({
|
|
250
|
-
url: buildApiUrl(baseURL, apiVersion, "/
|
|
425
|
+
url: buildApiUrl(baseURL, apiVersion, "/prompt"),
|
|
251
426
|
body,
|
|
252
427
|
headers: buildHeaders(getHeaders()),
|
|
253
428
|
signal: generateOptions.abortSignal,
|
|
@@ -263,16 +438,18 @@ function createContentAgent(options) {
|
|
|
263
438
|
}
|
|
264
439
|
export {
|
|
265
440
|
ContentAgentModel,
|
|
441
|
+
GENERIC_ERROR_MESSAGE,
|
|
266
442
|
SanityAgentError,
|
|
267
443
|
buildApiUrl,
|
|
268
444
|
buildHeaders,
|
|
445
|
+
classifyAgentError,
|
|
269
446
|
createContentAgent,
|
|
270
447
|
createSSEStream,
|
|
271
448
|
extractTextFromParts,
|
|
272
449
|
extractTextFromStream,
|
|
273
450
|
fetchApi,
|
|
451
|
+
getAgentErrorMessage,
|
|
274
452
|
mapFinishReason,
|
|
275
|
-
parseFinishLine,
|
|
276
453
|
parseStreamLine
|
|
277
454
|
};
|
|
278
455
|
//# 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 { 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":";AAMO,SAAS,aACd,eACA,mBACwB;AACxB,SAAO;AAAA,IACL;AAAA,MACE,gBAAgB;AAAA,MAChB,GAAG;AAAA,MACH,GAAG;AAAA,IAAA;AAAA,IAEL;AAAA,EAAA;AAEJ;AAKO,SAAS,YAAY,SAAiB,YAAoB,UAA0B;AACzF,SAAO,GAAG,OAAO,IAAI,UAAU,SAAS,QAAQ;AAClD;AAKO,MAAM,yBAAyB,MAAM;AAAA,EACjC;AAAA,EACA;AAAA,EAET,YAAY,QAAgB,SAAiB;AAC3C,UAAM,2BAA2B,MAAM,IAAI,OAAO,EAAE,GACpD,KAAK,OAAO,oBACZ,KAAK,SAAS,QACd,KAAK,cAAc,UAAU;AAAA,EAC/B;AACF;AAcA,eAAsB,SAAS,SAA0C;AAGvE,QAAM,WAAW,OAFD,QAAQ,SAAS,WAAW,OAEb,QAAQ,KAAK;AAAA,IAC1C,QAAQ;AAAA,IACR,SAAS,QAAQ;AAAA,IACjB,MAAM,KAAK,UAAU,QAAQ,IAAI;AAAA,IACjC,QAAQ,QAAQ;AAAA,EAAA,CACjB;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,YAAY,MAAM,SAAS,KAAA;AACjC,UAAM,IAAI,iBAAiB,SAAS,QAAQ,SAAS;AAAA,EACvD;AAEA,SAAO;AACT;AAKO,SAAS,qBACd,SACQ;AACR,SAAI,OAAO,WAAY,WACd,UAGF,QACJ;AAAA,IACC,CAAC,SACC,KAAK,SAAS,UAAU,OAAO,KAAK,QAAS;AAAA,EAAA,EAEhD,IAAI,CAAC,SAAS,KAAK,IAAI,EACvB,KAAK;AAAA,CAAI;AACd;AAKO,SAAS,gBAAgB,QAAyD;AACvF,UAAQ,QAAA;AAAA,IACN,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb;AAMO,SAAS,gBAAgB,MAAgD;AAC9E,QAAM,UAAU,KAAK,KAAA;AACrB,MAAI,CAAC,QAAS,QAAO;AAQrB,MAAI,QAAQ,WAAW,IAAI;AACzB,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,QAAQ,MAAM,CAAC,CAAC;AACxC,UAAI,OAAO,QAAS;AAClB,eAAO,EAAE,MAAM,cAAc,WAAW,KAAA;AAAA,IAE5C,QAAQ;AAAA,IAER;AAAA,WACS,QAAQ,WAAW,IAAI;AAChC,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,QAAQ,MAAM,CAAC,CAAC;AACxC,aAAO,EAAE,MAAM,SAAS,OAAO,IAAI,MAAM,KAAK,SAAS,eAAe,EAAA;AAAA,IACxE,QAAQ;AACN,aAAO,EAAE,MAAM,SAAS,OAAO,IAAI,MAAM,yBAAyB,EAAA;AAAA,IACpE;AAGF,SAAO;AACT;AAMO,SAAS,gBAAgB,MAAkD;AAChF,QAAM,UAAU,KAAK,KAAA;AACrB,MAAI,CAAC,QAAQ,WAAW,IAAI,EAAG,QAAO;AAEtC,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,QAAQ,MAAM,CAAC,CAAC;AACxC,WAAO,gBAAgB,KAAK,YAAY;AAAA,EAC1C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,eAAsB,sBACpB,cACiB;AACjB,QAAM,SAAS,aAAa,UAAA,GACtB,UAAU,IAAI,YAAA;AACpB,MAAI,OAAO;AAEX,aAAa;AACX,UAAM,EAAE,MAAM,MAAA,IAAU,MAAM,OAAO,KAAA;AACrC,QAAI,KAAM;AAEV,UAAM,QAAQ,QAAQ,OAAO,OAAO,EAAE,QAAQ,IAAM;AACpD,eAAW,QAAQ,MAAM,MAAM;AAAA,CAAI;AACjC,UAAI,KAAK,WAAW,IAAI;AACtB,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,KAAK,MAAM,CAAC,CAAC;AACnC,iBAAO,UAAW,aACpB,QAAQ;AAAA,QAEZ,QAAQ;AAAA,QAER;AAAA,EAGN;AAEA,SAAO;AACT;AAKO,SAAS,gBACd,cAC2C;AAC3C,MAAI,eAA4C;AAEhD,SAAO,IAAI,eAA0C;AAAA,IACnD,MAAM,MAAM,YAAY;AACtB,YAAM,SAAS,aAAa,UAAA,GACtB,UAAU,IAAI,YAAA;AACpB,UAAI,SAAS;AAEb,UAAI;AACF,mBAAa;AACX,gBAAM,EAAE,MAAM,MAAA,IAAU,MAAM,OAAO,KAAA;AACrC,cAAI,KAAM;AAEV,oBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,IAAM;AAChD,gBAAM,QAAQ,OAAO,MAAM;AAAA,CAAI;AAC/B,mBAAS,MAAM,SAAS;AAExB,qBAAW,QAAQ,OAAO;AACxB,kBAAM,SAAS,gBAAgB,IAAI;AAC/B,sBACF,WAAW,QAAQ,MAAM;AAG3B,kBAAM,SAAS,gBAAgB,IAAI;AAC/B,uBACF,eAAe;AAAA,UAEnB;AAAA,QACF;AAGA,YAAI,OAAO,QAAQ;AACjB,gBAAM,SAAS,gBAAgB,MAAM;AACjC,oBACF,WAAW,QAAQ,MAAM;AAAA,QAE7B;AAEA,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN;AAAA,UACA,OAAO,EAAE,cAAc,GAAG,kBAAkB,EAAA;AAAA,QAAE,CAC/C;AAAA,MACH,SAAS,OAAO;AACd,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,QAAA,CAChE;AAAA,MACH,UAAA;AACE,mBAAW,MAAA;AAAA,MACb;AAAA,IACF;AAAA,EAAA,CACD;AACH;ACtOA,MAAM,uBAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,MAAM,kBAA6C;AAAA,EAC/C,uBAAuB;AAAA,EACvB;AAAA,EACA;AAAA,EACA,8BAA8B;AAAA,EAEtB;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YACE,UACA,UACA,QACA;AACA,SAAK,WAAW,UAChB,KAAK,UAAU,iBAAiB,QAAQ,IACxC,KAAK,WAAW,OAAO,UACvB,KAAK,WAAW,YAAY,CAAA,GAC5B,KAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,wBAAwB,QAA0C;AACxE,UAAM,WAAsB,CAAA;AAE5B,eAAW,WAAW,QAAQ;AAC5B,UAAI,QAAQ,SAAS,OAAQ;AAE7B,YAAM,UACJ,QAAQ,SAAS,WACb,QAAQ,UACR,qBAAqB,QAAQ,OAA0D;AAEzF,iBACF,SAAS,KAAK,EAAE,MAAM,QAAQ,MAAM,SAAS;AAAA,IAEjD;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,gBAAgB,SAAmE;AACzF,UAAM,WAAyC,CAAA;AAE3C,YAAQ,KAAK,SAAS,cACpB,QAAQ,KAAK,OAAO,UACtB,SAAS,KAAK,EAAE,MAAM,SAAS,SAAS,gDAAgD,GAEtF,QAAQ,KAAK,cACf,SAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,SAAS;AAAA,IAAA,CACV;AAIL,eAAW,WAAW;AAChB,cAAQ,OAAO,MAAM,UACvB,SAAS,KAAK,EAAE,MAAM,uBAAuB,SAAS;AAI1D,WAAI,QAAQ,eAAe,UACzB,SAAS,KAAK,EAAE,MAAM,uBAAuB,SAAS,gBAAA,CAAiB,GAGlE;AAAA,EACT;AAAA,EAEQ,iBAAiB,SAAqC,QAAiB;AAC7E,WAAO;AAAA,MACL,gBAAgB,KAAK,OAAO;AAAA,MAC5B,UAAU,KAAK;AAAA,MACf,UAAU,KAAK,wBAAwB,QAAQ,MAAM;AAAA,MACrD;AAAA,MACA,GAAI,KAAK,SAAS,eAAe,EAAE,aAAa,KAAK,SAAS,YAAA;AAAA,MAC9D,GAAI,KAAK,SAAS,UAAU,EAAE,QAAQ,KAAK,SAAS,OAAA;AAAA,IAAO;AAAA,EAE/D;AAAA,EAEQ,mBAAmB,UAA4C;AACrE,WAAO,OAAO,YAAY,SAAS,QAAQ,SAAS;AAAA,EACtD;AAAA,EAEA,MAAM,WAAW,SAOd;AACD,UAAM,OAAO,KAAK,iBAAiB,SAAS,EAAK,GAC3C,WAAW,KAAK,gBAAgB,OAAO,GAEvC,WAAW,MAAM,SAAS;AAAA,MAC9B,KAAK,YAAY,KAAK,OAAO,SAAS,KAAK,OAAO,YAAY,OAAO;AAAA,MACrE;AAAA,MACA,SAAS,aAAa,KAAK,OAAO,SAAS;AAAA,MAC3C,QAAQ,QAAQ;AAAA,MAChB,OAAO,KAAK,OAAO;AAAA,IAAA,CACpB;AAID,WAAO;AAAA,MACL,OAHoB,MAAM,SAAS,KAAA,GAGhB,QAAQ;AAAA,MAC3B,cAAc;AAAA,MACd,OAAO,EAAE,cAAc,GAAG,kBAAkB,EAAA;AAAA,MAC5C,SAAS,EAAE,WAAW,KAAK,UAAU,aAAa,CAAA,EAAC;AAAA,MACnD,aAAa,EAAE,SAAS,KAAK,mBAAmB,QAAQ,EAAA;AAAA,MACxD;AAAA,IAAA;AAAA,EAEJ;AAAA,EAEA,MAAM,SAAS,SAKZ;AACD,UAAM,OAAO,KAAK,iBAAiB,SAAS,EAAI,GAC1C,WAAW,KAAK,gBAAgB,OAAO,GAEvC,WAAW,MAAM,SAAS;AAAA,MAC9B,KAAK,YAAY,KAAK,OAAO,SAAS,KAAK,OAAO,YAAY,OAAO;AAAA,MACrE;AAAA,MACA,SAAS,aAAa,KAAK,OAAO,SAAS;AAAA,MAC3C,QAAQ,QAAQ;AAAA,MAChB,OAAO,KAAK,OAAO;AAAA,IAAA,CACpB;AAED,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,wCAAwC;AAG1D,WAAO;AAAA,MACL,QAAQ,gBAAgB,SAAS,IAAI;AAAA,MACrC,SAAS,EAAE,WAAW,KAAK,UAAU,aAAa,CAAA,EAAC;AAAA,MACnD,aAAa,EAAE,SAAS,KAAK,mBAAmB,QAAQ,EAAA;AAAA,MACxD;AAAA,IAAA;AAAA,EAEJ;AACF;AC5JA,MAAM,mBAAmB,yBACnB,sBAAsB;AA8BrB,SAAS,mBAAmB,SAA6D;AAC9F,QAAM,UAAU,QAAQ,SAAS,QAAQ,OAAO,EAAE,KAAK,kBACjD,aAAa,QAAQ,cAAc,qBACnC,EAAE,mBAAmB,SAErB,aAAa,OAA2C;AAAA,IAC5D,GAAI,QAAQ,SAAS,EAAE,eAAe,UAAU,QAAQ,KAAK,GAAA;AAAA,IAC7D,GAAG,QAAQ;AAAA,EAAA,IAGP,SAAkC;AAAA,IACtC,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,OAAO,QAAQ;AAAA,EAAA;AAuCjB,SAAO,EAAE,OApCK,CAAC,UAAkB,aACxB,IAAI,kBAAkB,UAAU,UAAU,MAAM,GAmCzC,QAhCD,OACb,UACA,oBAC4B;AAC5B,UAAM,OAAO;AAAA,MACX;AAAA,MACA,SAAS,gBAAgB;AAAA,MACzB,QAAQ,gBAAgB,UAAU;AAAA,MAClC,GAAI,SAAS,eAAe,EAAE,aAAa,SAAS,YAAA;AAAA,MACpD,GAAI,SAAS,UAAU,EAAE,QAAQ,SAAS,OAAA;AAAA,MAC1C,GAAI,SAAS,gBAAgB,EAAE,cAAc,SAAS,aAAA;AAAA,IAAa,GAG/D,WAAW,MAAM,SAAS;AAAA,MAC9B,KAAK,YAAY,SAAS,YAAY,WAAW;AAAA,MACjD;AAAA,MACA,SAAS,aAAa,YAAY;AAAA,MAClC,QAAQ,gBAAgB;AAAA,MACxB,OAAO,QAAQ;AAAA,IAAA,CAChB;AAED,QAAI,KAAK,QAAQ;AACf,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI,iBAAiB,KAAK,kBAAkB;AAEpD,aAAO,EAAE,MAAM,MAAM,sBAAsB,SAAS,IAAI,EAAA;AAAA,IAC1D;AAGA,WAAO,EAAE,OADK,MAAM,SAAS,KAAA,GACT,QAAQ,GAAA;AAAA,EAC9B,EAAA;AAGF;"}
|
|
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 { HEADLESS_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 */\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 * The {@link body} is parsed from the JSON response and follows the\n * {@link HeadlessErrorResponse} shape defined in `@sanity/agent-types`.\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 */\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 HEADLESS_ERROR_CODES.NO_COMPATIBLE_APPLICATIONS:\n return { type: 'no_applications' }\n case HEADLESS_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 */\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 */\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 * Creates an empty V3 usage object. Our API does not return token counts.\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 */\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\n/**\n * Parses a single line from the Vercel AI Data Stream Protocol.\n * Returns null if the line cannot be parsed or should be ignored.\n *\n * Protocol prefixes:\n * 0:\"text\" – text content\n * 2:[data] – data array (ignored)\n * 3:\"error\" – error\n * b:{toolCallId,toolName,args} – client tool call\n * d:{finishReason, usage} – finish message\n * e:{finishReason, usage} – finish step\n *\n * @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol\n */\nexport function parseStreamLine(line: string, textContentId: string): ParsedStreamLine | null {\n const trimmed = line.trim()\n if (!trimmed || trimmed.length < 2 || trimmed[1] !== ':') return null\n\n const prefix = trimmed[0]\n const payload = trimmed.slice(2)\n\n switch (prefix) {\n case '0': {\n try {\n const text = JSON.parse(payload) as unknown\n if (typeof text === 'string') {\n return { kind: 'part', part: { type: 'text-delta', id: textContentId, delta: text } }\n }\n } catch {\n // Ignore parse errors\n }\n return null\n }\n\n case '3': {\n try {\n const msg = JSON.parse(payload) as unknown\n return {\n kind: 'part',\n part: {\n type: 'error',\n error: new Error(typeof msg === 'string' ? msg : 'Unknown error'),\n },\n }\n } catch {\n return {\n kind: 'part',\n part: { type: 'error', error: new Error('Unknown streaming error') },\n }\n }\n }\n\n case 'b': {\n try {\n const data = JSON.parse(payload) as {\n toolCallId: string\n toolName: string\n args: unknown\n }\n return {\n kind: 'part',\n part: {\n type: 'tool-call',\n toolCallId: data.toolCallId,\n toolName: data.toolName,\n input: typeof data.args === 'string' ? data.args : JSON.stringify(data.args),\n },\n }\n } catch {\n return null\n }\n }\n\n case 'd':\n case 'e': {\n try {\n const data = JSON.parse(payload) as { finishReason?: string }\n return { kind: 'finish', finishReason: mapFinishReason(data.finishReason) }\n } catch {\n return null\n }\n }\n\n default:\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 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 SSE data from a response body\n * and emits LanguageModelV3 stream parts with proper lifecycle events.\n */\nexport function createSSEStream(\n responseBody: ReadableStream<Uint8Array>,\n warnings: SharedV3Warning[],\n): ReadableStream<LanguageModelV3StreamPart> {\n let finishReason: LanguageModelV3FinishReason = { unified: 'other', raw: undefined }\n const textContentId = crypto.randomUUID()\n let textStarted = false\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, textContentId)\n if (parsed?.kind === 'part') {\n if (parsed.part.type === 'text-delta' && !textStarted) {\n controller.enqueue({ type: 'text-start', id: textContentId })\n textStarted = true\n }\n if (parsed.part.type === 'tool-call') {\n // Close any open text block before emitting a tool call\n if (textStarted) {\n controller.enqueue({ type: 'text-end', id: textContentId })\n textStarted = false\n }\n hasToolCalls = true\n }\n controller.enqueue(parsed.part)\n } else if (parsed?.kind === 'finish') {\n finishReason = parsed.finishReason\n }\n }\n }\n\n // Process remaining buffer\n if (buffer.trim()) {\n const parsed = parseStreamLine(buffer, textContentId)\n if (parsed?.kind === 'part') {\n if (parsed.part.type === 'text-delta' && !textStarted) {\n controller.enqueue({ type: 'text-start', id: textContentId })\n textStarted = true\n }\n if (parsed.part.type === 'tool-call') {\n if (textStarted) {\n controller.enqueue({ type: 'text-end', id: textContentId })\n textStarted = false\n }\n hasToolCalls = true\n }\n controller.enqueue(parsed.part)\n } else if (parsed?.kind === 'finish') {\n finishReason = parsed.finishReason\n }\n }\n\n if (textStarted) {\n controller.enqueue({ type: 'text-end', id: textContentId })\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\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\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),\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\nexport interface ContentAgentProvider {\n /**\n * Creates an agent for a conversation thread.\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 `.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): 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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "content-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Vercel AI SDK provider for Sanity Content Agent API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -27,13 +27,14 @@
|
|
|
27
27
|
"dist"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@ai-sdk/provider": "^
|
|
30
|
+
"@ai-sdk/provider": "^3.0.0",
|
|
31
31
|
"@ai-sdk/provider-utils": "^2.2.8",
|
|
32
|
-
"es-toolkit": "^1.32.0"
|
|
32
|
+
"es-toolkit": "^1.32.0",
|
|
33
|
+
"@sanity/agent-types": "0.0.79"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@sanity/pkg-utils": "^10.4.1",
|
|
36
|
-
"@types/node": "^22.
|
|
37
|
+
"@types/node": "^22.19.7",
|
|
37
38
|
"openapi-typescript": "^7.10.1",
|
|
38
39
|
"typescript": "^5.9.3",
|
|
39
40
|
"vitest": "^4.0.18",
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
"@repo/tsconfig": "0.0.0"
|
|
42
43
|
},
|
|
43
44
|
"peerDependencies": {
|
|
44
|
-
"ai": ">=
|
|
45
|
+
"ai": ">=6.0.0"
|
|
45
46
|
},
|
|
46
47
|
"peerDependenciesMeta": {
|
|
47
48
|
"ai": {
|