content-agent 0.4.0 → 0.4.2
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/dist/index.d.ts +460 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -60
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.d.ts
CHANGED
|
@@ -400,25 +400,197 @@ interface operations {
|
|
|
400
400
|
};
|
|
401
401
|
};
|
|
402
402
|
}
|
|
403
|
+
/**
|
|
404
|
+
* Request body for the conversation thread endpoint (`POST /{organizationId}/threads/{threadId}`).
|
|
405
|
+
* @category API Types
|
|
406
|
+
*/
|
|
403
407
|
type ChatRequest = components['schemas']['ChatRequest'];
|
|
408
|
+
/**
|
|
409
|
+
* Request body for the one-shot prompt endpoint (`POST /prompt`).
|
|
410
|
+
* @category API Types
|
|
411
|
+
*/
|
|
404
412
|
type GenerateRequest = components['schemas']['PromptRequest'];
|
|
413
|
+
/**
|
|
414
|
+
* Controls how directives in the response are formatted (`'markdown'` or `'directives'`).
|
|
415
|
+
* @category Configuration
|
|
416
|
+
*/
|
|
405
417
|
type OutputFormat = ChatRequest['format'];
|
|
418
|
+
/**
|
|
419
|
+
* Response from the conversation thread endpoint when `stream: false`.
|
|
420
|
+
* @category API Types
|
|
421
|
+
*/
|
|
406
422
|
type ChatResponse = components['schemas']['ChatResponse'];
|
|
423
|
+
/**
|
|
424
|
+
* Error response body returned by the API on failure.
|
|
425
|
+
* @category API Types
|
|
426
|
+
*/
|
|
407
427
|
type ErrorResponse = components['schemas']['ErrorResponse'];
|
|
428
|
+
/**
|
|
429
|
+
* Individual validation issue within an {@link ErrorResponse}.
|
|
430
|
+
* @category API Types
|
|
431
|
+
*/
|
|
408
432
|
type ValidationIssue = components['schemas']['ValidationIssue'];
|
|
433
|
+
/**
|
|
434
|
+
* A message in a conversation (user, assistant, or system).
|
|
435
|
+
* @category API Types
|
|
436
|
+
*/
|
|
409
437
|
type Message = components['schemas']['Message'];
|
|
438
|
+
/**
|
|
439
|
+
* The role of a {@link Message}: `'user'`, `'assistant'`, or `'system'`.
|
|
440
|
+
* @category API Types
|
|
441
|
+
*/
|
|
410
442
|
type MessageRole = Message['role'];
|
|
443
|
+
/**
|
|
444
|
+
* Specifies which Sanity project and dataset the agent should work with.
|
|
445
|
+
*
|
|
446
|
+
* @category Configuration
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* ```ts
|
|
450
|
+
* const application = {
|
|
451
|
+
* key: 'project-id.dataset-name',
|
|
452
|
+
* }
|
|
453
|
+
* ```
|
|
454
|
+
*/
|
|
411
455
|
type Application = components['schemas']['Application'];
|
|
456
|
+
/**
|
|
457
|
+
* Resource within an {@link Application}.
|
|
458
|
+
* @category Configuration
|
|
459
|
+
*/
|
|
412
460
|
type ApplicationResource = NonNullable<Application['resource']>;
|
|
461
|
+
/**
|
|
462
|
+
* Agent configuration for controlling behavior, capabilities, and document access.
|
|
463
|
+
*
|
|
464
|
+
* @category Configuration
|
|
465
|
+
*
|
|
466
|
+
* @example Read-only with custom instruction and user message context
|
|
467
|
+
* ```ts
|
|
468
|
+
* const config = {
|
|
469
|
+
* instruction: 'You are a Slack bot helping users manage content.',
|
|
470
|
+
* userMessageContext: {
|
|
471
|
+
* 'slack-channel': '#content-team',
|
|
472
|
+
* 'slack-user': '@john.doe',
|
|
473
|
+
* },
|
|
474
|
+
* capabilities: {
|
|
475
|
+
* read: true,
|
|
476
|
+
* write: false,
|
|
477
|
+
* },
|
|
478
|
+
* }
|
|
479
|
+
* ```
|
|
480
|
+
*
|
|
481
|
+
* @example Read-only document explorer with type filtering
|
|
482
|
+
* ```ts
|
|
483
|
+
* const config = {
|
|
484
|
+
* capabilities: {
|
|
485
|
+
* read: { preset: 'standard' },
|
|
486
|
+
* write: false,
|
|
487
|
+
* },
|
|
488
|
+
* filter: {
|
|
489
|
+
* read: '_type in ["post", "author", "page"]',
|
|
490
|
+
* },
|
|
491
|
+
* }
|
|
492
|
+
* ```
|
|
493
|
+
*/
|
|
413
494
|
type Config = components['schemas']['Config'];
|
|
495
|
+
/**
|
|
496
|
+
* Controls what operations the agent can perform.
|
|
497
|
+
*
|
|
498
|
+
* Each capability (`read`, `write`) can be:
|
|
499
|
+
* - `true` — Full access (standard preset)
|
|
500
|
+
* - `false` — No access
|
|
501
|
+
* - `{ preset: 'minimal' }` — Basic tools only
|
|
502
|
+
* - `{ preset: 'standard' }` — All tools available
|
|
503
|
+
*
|
|
504
|
+
* Use `features` to override individual feature toggles independently of presets.
|
|
505
|
+
*
|
|
506
|
+
* @example Read-only access
|
|
507
|
+
* ```ts
|
|
508
|
+
* const capabilities = { read: true, write: false }
|
|
509
|
+
* ```
|
|
510
|
+
*
|
|
511
|
+
* @example Full read, minimal write
|
|
512
|
+
* ```ts
|
|
513
|
+
* const capabilities = {
|
|
514
|
+
* read: true,
|
|
515
|
+
* write: { preset: 'minimal' },
|
|
516
|
+
* }
|
|
517
|
+
* ```
|
|
518
|
+
*
|
|
519
|
+
* @example Standard read with web search disabled
|
|
520
|
+
* ```ts
|
|
521
|
+
* const capabilities = {
|
|
522
|
+
* read: true,
|
|
523
|
+
* write: false,
|
|
524
|
+
* features: { webSearch: false },
|
|
525
|
+
* }
|
|
526
|
+
* ```
|
|
527
|
+
*
|
|
528
|
+
* @category Configuration
|
|
529
|
+
*/
|
|
414
530
|
type Capabilities = components['schemas']['Capabilities'];
|
|
531
|
+
/**
|
|
532
|
+
* A single capability value: `true`, `false`, or a {@link CapabilityPreset}.
|
|
533
|
+
* @category Configuration
|
|
534
|
+
*/
|
|
415
535
|
type Capability = components['schemas']['Capability'];
|
|
536
|
+
/**
|
|
537
|
+
* A capability preset object, e.g. `{ preset: 'minimal' }` or `{ preset: 'standard' }`.
|
|
538
|
+
* @category Configuration
|
|
539
|
+
*/
|
|
416
540
|
type CapabilityPreset = components['schemas']['CapabilityPreset'];
|
|
541
|
+
/**
|
|
542
|
+
* The preset level string: `'minimal'` or `'standard'`.
|
|
543
|
+
* @category Configuration
|
|
544
|
+
*/
|
|
417
545
|
type CapabilityPresetValue = CapabilityPreset['preset'];
|
|
546
|
+
/**
|
|
547
|
+
* GROQ boolean expressions to control document visibility and mutation permissions.
|
|
548
|
+
*
|
|
549
|
+
* @category Configuration
|
|
550
|
+
*
|
|
551
|
+
* @example
|
|
552
|
+
* ```ts
|
|
553
|
+
* const filter = {
|
|
554
|
+
* read: '_type in ["post", "author", "category"]',
|
|
555
|
+
* write: '_type == "post"',
|
|
556
|
+
* }
|
|
557
|
+
* ```
|
|
558
|
+
*/
|
|
418
559
|
type Filter = components['schemas']['Filter'];
|
|
560
|
+
/**
|
|
561
|
+
* Key-value pairs appended to each user message as XML tags.
|
|
562
|
+
*
|
|
563
|
+
* @category Configuration
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
* ```ts
|
|
567
|
+
* const userMessageContext = {
|
|
568
|
+
* 'slack-channel': '#marketing',
|
|
569
|
+
* 'user-role': 'editor',
|
|
570
|
+
* }
|
|
571
|
+
* // Renders in the user message as:
|
|
572
|
+
* // <slack-channel>#marketing</slack-channel>
|
|
573
|
+
* // <user-role>editor</user-role>
|
|
574
|
+
* ```
|
|
575
|
+
*/
|
|
419
576
|
type UserMessageContext = NonNullable<Config['userMessageContext']>;
|
|
420
577
|
/**
|
|
421
|
-
* Settings for creating a Content Agent provider instance.
|
|
578
|
+
* Settings for creating a Content Agent provider instance via {@link createContentAgent}.
|
|
579
|
+
*
|
|
580
|
+
* @category Provider
|
|
581
|
+
*
|
|
582
|
+
* @example
|
|
583
|
+
* ```ts
|
|
584
|
+
* import { createContentAgent } from 'content-agent'
|
|
585
|
+
*
|
|
586
|
+
* const contentAgent = createContentAgent({
|
|
587
|
+
* organizationId: 'your-org-id',
|
|
588
|
+
* token: 'your-sanity-token',
|
|
589
|
+
* // Optional overrides:
|
|
590
|
+
* // baseURL: 'https://api.sanity.io',
|
|
591
|
+
* // apiVersion: 'v2026-01-01',
|
|
592
|
+
* })
|
|
593
|
+
* ```
|
|
422
594
|
*/
|
|
423
595
|
interface ContentAgentProviderSettings {
|
|
424
596
|
/**
|
|
@@ -454,6 +626,44 @@ interface ContentAgentProviderSettings {
|
|
|
454
626
|
}
|
|
455
627
|
/**
|
|
456
628
|
* Base settings shared between agent and generate requests.
|
|
629
|
+
*
|
|
630
|
+
* @example Read-only agent with document type filtering
|
|
631
|
+
* ```ts
|
|
632
|
+
* const settings = {
|
|
633
|
+
* application: { key: 'projectId.datasetName' },
|
|
634
|
+
* config: {
|
|
635
|
+
* instruction: 'You are a helpful content assistant for our blog.',
|
|
636
|
+
* capabilities: {
|
|
637
|
+
* read: true,
|
|
638
|
+
* write: false,
|
|
639
|
+
* },
|
|
640
|
+
* filter: {
|
|
641
|
+
* read: '_type in ["post", "author", "category"]',
|
|
642
|
+
* },
|
|
643
|
+
* },
|
|
644
|
+
* }
|
|
645
|
+
* ```
|
|
646
|
+
*
|
|
647
|
+
* @example Read/write agent with perspective locking
|
|
648
|
+
* ```ts
|
|
649
|
+
* const settings = {
|
|
650
|
+
* application: { key: 'projectId.datasetName' },
|
|
651
|
+
* config: {
|
|
652
|
+
* capabilities: {
|
|
653
|
+
* read: true,
|
|
654
|
+
* write: { preset: 'minimal' },
|
|
655
|
+
* },
|
|
656
|
+
* filter: {
|
|
657
|
+
* read: '_type in ["post", "author", "category"]',
|
|
658
|
+
* write: '_type == "post"',
|
|
659
|
+
* },
|
|
660
|
+
* perspectives: {
|
|
661
|
+
* read: ['drafts', 'published'],
|
|
662
|
+
* write: 'drafts',
|
|
663
|
+
* },
|
|
664
|
+
* },
|
|
665
|
+
* }
|
|
666
|
+
* ```
|
|
457
667
|
*/
|
|
458
668
|
interface BaseAgentSettings {
|
|
459
669
|
/**
|
|
@@ -474,10 +684,49 @@ interface BaseAgentSettings {
|
|
|
474
684
|
}
|
|
475
685
|
/**
|
|
476
686
|
* Settings for creating an agent instance (per-thread).
|
|
687
|
+
*
|
|
688
|
+
* Passed as the second argument to {@link ContentAgentProvider.agent | contentAgent.agent(threadId, settings)}.
|
|
689
|
+
*
|
|
690
|
+
* @example
|
|
691
|
+
* ```ts
|
|
692
|
+
* const model = contentAgent.agent('my-thread-id', {
|
|
693
|
+
* application: { key: 'projectId.datasetName' },
|
|
694
|
+
* config: {
|
|
695
|
+
* capabilities: { read: true, write: false },
|
|
696
|
+
* },
|
|
697
|
+
* })
|
|
698
|
+
* ```
|
|
699
|
+
*
|
|
700
|
+
* @category Configuration
|
|
477
701
|
*/
|
|
478
|
-
|
|
702
|
+
interface AgentSettings extends BaseAgentSettings {
|
|
703
|
+
/**
|
|
704
|
+
* Called when a custom `data-*` SSE part arrives during streaming.
|
|
705
|
+
*
|
|
706
|
+
* @param type - The data part type with the `data-` prefix stripped (e.g. `'agent-status'`).
|
|
707
|
+
* @param data - The parsed payload.
|
|
708
|
+
*/
|
|
709
|
+
onStreamData?: (type: string, data: unknown) => void;
|
|
710
|
+
}
|
|
479
711
|
/**
|
|
480
|
-
* Settings for one-shot generation requests.
|
|
712
|
+
* Settings for one-shot generation requests via {@link ContentAgentProvider.prompt | contentAgent.prompt()}.
|
|
713
|
+
*
|
|
714
|
+
* Extends {@link BaseAgentSettings} with an additional `instructions` field
|
|
715
|
+
* for providing custom system-level instructions.
|
|
716
|
+
*
|
|
717
|
+
* @example
|
|
718
|
+
* ```ts
|
|
719
|
+
* const { text } = await contentAgent.prompt(
|
|
720
|
+
* {
|
|
721
|
+
* application: { key: 'projectId.datasetName' },
|
|
722
|
+
* config: { capabilities: { read: true, write: false } },
|
|
723
|
+
* instructions: 'Be concise',
|
|
724
|
+
* },
|
|
725
|
+
* { message: 'List my 5 most recent posts' },
|
|
726
|
+
* )
|
|
727
|
+
* ```
|
|
728
|
+
*
|
|
729
|
+
* @category Configuration
|
|
481
730
|
*/
|
|
482
731
|
interface GenerateSettings extends BaseAgentSettings {
|
|
483
732
|
/**
|
|
@@ -485,6 +734,19 @@ interface GenerateSettings extends BaseAgentSettings {
|
|
|
485
734
|
*/
|
|
486
735
|
instructions?: string;
|
|
487
736
|
}
|
|
737
|
+
/**
|
|
738
|
+
* Options for a one-shot generation request via {@link ContentAgentProvider.prompt | contentAgent.prompt()}.
|
|
739
|
+
*
|
|
740
|
+
* @category Configuration
|
|
741
|
+
*
|
|
742
|
+
* @example
|
|
743
|
+
* ```ts
|
|
744
|
+
* const { text } = await contentAgent.prompt(
|
|
745
|
+
* { instructions: 'Be concise' },
|
|
746
|
+
* { message: 'List all authors in my dataset' },
|
|
747
|
+
* )
|
|
748
|
+
* ```
|
|
749
|
+
*/
|
|
488
750
|
interface GenerateOptions {
|
|
489
751
|
/**
|
|
490
752
|
* The prompt message to send.
|
|
@@ -500,12 +762,20 @@ interface GenerateOptions {
|
|
|
500
762
|
*/
|
|
501
763
|
abortSignal?: AbortSignal;
|
|
502
764
|
}
|
|
765
|
+
/**
|
|
766
|
+
* Result from a one-shot generation request via {@link ContentAgentProvider.prompt | contentAgent.prompt()}.
|
|
767
|
+
*
|
|
768
|
+
* @category Configuration
|
|
769
|
+
*/
|
|
503
770
|
interface GenerateResult {
|
|
504
771
|
/**
|
|
505
772
|
* The generated text response.
|
|
506
773
|
*/
|
|
507
774
|
text: string;
|
|
508
775
|
}
|
|
776
|
+
/**
|
|
777
|
+
* @category Model
|
|
778
|
+
*/
|
|
509
779
|
interface ContentAgentModelConfig {
|
|
510
780
|
provider: string;
|
|
511
781
|
baseURL: string;
|
|
@@ -514,6 +784,38 @@ interface ContentAgentModelConfig {
|
|
|
514
784
|
headers: () => Record<string, string | undefined>;
|
|
515
785
|
fetch?: typeof globalThis.fetch;
|
|
516
786
|
}
|
|
787
|
+
/**
|
|
788
|
+
* Vercel AI SDK `LanguageModelV1` implementation that communicates with the
|
|
789
|
+
* Sanity Content Agent API via a conversation thread.
|
|
790
|
+
*
|
|
791
|
+
* Typically you don't construct this directly — use
|
|
792
|
+
* {@link createContentAgent | createContentAgent().agent(threadId)} instead.
|
|
793
|
+
*
|
|
794
|
+
* @category Model
|
|
795
|
+
*
|
|
796
|
+
* @example
|
|
797
|
+
* ```ts
|
|
798
|
+
* import { createContentAgent } from 'content-agent'
|
|
799
|
+
* import { streamText } from 'ai'
|
|
800
|
+
*
|
|
801
|
+
* const contentAgent = createContentAgent({
|
|
802
|
+
* organizationId: 'your-org-id',
|
|
803
|
+
* token: 'your-sanity-token',
|
|
804
|
+
* })
|
|
805
|
+
*
|
|
806
|
+
* const model = contentAgent.agent('my-thread-id', {
|
|
807
|
+
* application: { key: 'projectId.datasetName' },
|
|
808
|
+
* config: {
|
|
809
|
+
* capabilities: { read: true, write: false },
|
|
810
|
+
* },
|
|
811
|
+
* })
|
|
812
|
+
*
|
|
813
|
+
* const { textStream } = await streamText({ model, prompt: 'Summarize my content' })
|
|
814
|
+
* for await (const chunk of textStream) {
|
|
815
|
+
* process.stdout.write(chunk)
|
|
816
|
+
* }
|
|
817
|
+
* ```
|
|
818
|
+
*/
|
|
517
819
|
declare class ContentAgentModel implements LanguageModelV3 {
|
|
518
820
|
readonly specificationVersion: "v3";
|
|
519
821
|
readonly provider: string;
|
|
@@ -549,9 +851,48 @@ declare class ContentAgentModel implements LanguageModelV3 {
|
|
|
549
851
|
private extractContentFromStream;
|
|
550
852
|
doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult>;
|
|
551
853
|
}
|
|
854
|
+
/**
|
|
855
|
+
* A Content Agent provider instance returned by {@link createContentAgent}.
|
|
856
|
+
*
|
|
857
|
+
* Provides two modes of interaction:
|
|
858
|
+
* - **Conversation threads** via {@link ContentAgentProvider.agent | .agent()} — stateful, multi-turn conversations with server-side message history.
|
|
859
|
+
* - **One-shot prompts** via {@link ContentAgentProvider.prompt | .prompt()} — stateless, single-turn interactions.
|
|
860
|
+
*
|
|
861
|
+
* @category Provider
|
|
862
|
+
*/
|
|
552
863
|
interface ContentAgentProvider {
|
|
553
864
|
/**
|
|
554
|
-
* Creates
|
|
865
|
+
* Creates a Vercel AI SDK {@link https://sdk.vercel.ai/docs/ai-sdk-core | LanguageModelV1} for a conversation thread.
|
|
866
|
+
*
|
|
867
|
+
* The thread ID identifies the conversation and maintains message history server-side.
|
|
868
|
+
* If a thread with that ID already exists, the conversation continues. If not, a new
|
|
869
|
+
* thread is automatically created.
|
|
870
|
+
*
|
|
871
|
+
* Use the returned model with `generateText` or `streamText` from the `ai` package.
|
|
872
|
+
*
|
|
873
|
+
* @example
|
|
874
|
+
* ```ts
|
|
875
|
+
* import { generateText, streamText } from 'ai'
|
|
876
|
+
*
|
|
877
|
+
* const model = contentAgent.agent('my-thread-id', {
|
|
878
|
+
* application: { key: 'projectId.datasetName' },
|
|
879
|
+
* config: {
|
|
880
|
+
* capabilities: { read: true, write: false },
|
|
881
|
+
* },
|
|
882
|
+
* })
|
|
883
|
+
*
|
|
884
|
+
* // Non-streaming
|
|
885
|
+
* const { text } = await generateText({ model, prompt: 'What blog posts do I have?' })
|
|
886
|
+
*
|
|
887
|
+
* // Streaming
|
|
888
|
+
* const { textStream } = await streamText({ model, prompt: 'Summarize my content' })
|
|
889
|
+
* for await (const chunk of textStream) {
|
|
890
|
+
* process.stdout.write(chunk)
|
|
891
|
+
* }
|
|
892
|
+
* ```
|
|
893
|
+
*
|
|
894
|
+
* @param threadId - Unique identifier for the conversation thread.
|
|
895
|
+
* @param settings - Optional agent settings (application, capabilities, filters, etc.).
|
|
555
896
|
*/
|
|
556
897
|
agent(threadId: string, settings?: AgentSettings): LanguageModelV3;
|
|
557
898
|
/**
|
|
@@ -574,37 +915,105 @@ interface ContentAgentProvider {
|
|
|
574
915
|
/**
|
|
575
916
|
* Sends a one-shot prompt to the Content Agent (stateless).
|
|
576
917
|
*
|
|
577
|
-
* Unlike
|
|
918
|
+
* Unlike {@link ContentAgentProvider.agent | .agent()}, this does not create or use a conversation thread.
|
|
578
919
|
* Each call is independent with no message history or persistence.
|
|
579
920
|
* Ideal for simple, single-turn interactions.
|
|
580
921
|
*
|
|
581
922
|
* @example
|
|
582
923
|
* ```ts
|
|
583
|
-
* const
|
|
584
|
-
* {
|
|
585
|
-
*
|
|
924
|
+
* const { text } = await contentAgent.prompt(
|
|
925
|
+
* {
|
|
926
|
+
* application: { key: 'projectId.datasetName' },
|
|
927
|
+
* config: { capabilities: { read: true, write: false } },
|
|
928
|
+
* instructions: 'Be concise',
|
|
929
|
+
* },
|
|
930
|
+
* { message: 'List my 5 most recent posts' },
|
|
586
931
|
* )
|
|
587
|
-
* console.log(result.text)
|
|
588
932
|
* ```
|
|
933
|
+
*
|
|
934
|
+
* @param settings - Generation settings (application, capabilities, instructions, etc.).
|
|
935
|
+
* @param options - The prompt message and request options.
|
|
589
936
|
*/
|
|
590
937
|
prompt(settings: GenerateSettings, options: GenerateOptions): Promise<GenerateResult>;
|
|
591
938
|
}
|
|
592
939
|
/**
|
|
593
940
|
* Creates a Content Agent provider instance.
|
|
941
|
+
*
|
|
942
|
+
* The provider is the main entry point for interacting with the Sanity Content Agent API.
|
|
943
|
+
* It returns an object with methods for conversation threads and one-shot prompts.
|
|
944
|
+
*
|
|
945
|
+
* @category Provider
|
|
946
|
+
*
|
|
947
|
+
* @example Basic setup
|
|
948
|
+
* ```ts
|
|
949
|
+
* import { createContentAgent } from 'content-agent'
|
|
950
|
+
*
|
|
951
|
+
* const contentAgent = createContentAgent({
|
|
952
|
+
* organizationId: 'your-org-id',
|
|
953
|
+
* token: 'your-sanity-token',
|
|
954
|
+
* })
|
|
955
|
+
* ```
|
|
956
|
+
*
|
|
957
|
+
* @example Using with Vercel AI SDK for conversation threads
|
|
958
|
+
* ```ts
|
|
959
|
+
* import { createContentAgent } from 'content-agent'
|
|
960
|
+
* import { generateText, streamText } from 'ai'
|
|
961
|
+
*
|
|
962
|
+
* const contentAgent = createContentAgent({
|
|
963
|
+
* organizationId: 'your-org-id',
|
|
964
|
+
* token: 'your-sanity-token',
|
|
965
|
+
* })
|
|
966
|
+
*
|
|
967
|
+
* const model = contentAgent.agent('my-thread-id', {
|
|
968
|
+
* application: { key: 'projectId.datasetName' },
|
|
969
|
+
* config: {
|
|
970
|
+
* capabilities: { read: true, write: false },
|
|
971
|
+
* },
|
|
972
|
+
* })
|
|
973
|
+
*
|
|
974
|
+
* // Non-streaming
|
|
975
|
+
* const { text } = await generateText({ model, prompt: 'What blog posts do I have?' })
|
|
976
|
+
*
|
|
977
|
+
* // Streaming
|
|
978
|
+
* const { textStream } = await streamText({ model, prompt: 'Summarize my content' })
|
|
979
|
+
* for await (const chunk of textStream) {
|
|
980
|
+
* process.stdout.write(chunk)
|
|
981
|
+
* }
|
|
982
|
+
* ```
|
|
983
|
+
*
|
|
984
|
+
* @example One-shot generation (stateless, no thread)
|
|
985
|
+
* ```ts
|
|
986
|
+
* const { text } = await contentAgent.prompt(
|
|
987
|
+
* {
|
|
988
|
+
* application: { key: 'projectId.datasetName' },
|
|
989
|
+
* config: { capabilities: { read: true, write: false } },
|
|
990
|
+
* instructions: 'Be concise',
|
|
991
|
+
* },
|
|
992
|
+
* { message: 'List my 5 most recent posts' },
|
|
993
|
+
* )
|
|
994
|
+
* ```
|
|
995
|
+
*
|
|
996
|
+
* @param options - Provider configuration including organization ID, token, and optional overrides.
|
|
594
997
|
*/
|
|
595
998
|
declare function createContentAgent(options: ContentAgentProviderSettings): ContentAgentProvider;
|
|
596
999
|
/**
|
|
597
1000
|
* Builds headers for API requests, filtering out undefined values.
|
|
1001
|
+
*
|
|
1002
|
+
* @category Utilities
|
|
598
1003
|
*/
|
|
599
1004
|
declare function buildHeaders(configHeaders: Record<string, string | undefined>, additionalHeaders?: Record<string, string>): Record<string, string>;
|
|
600
1005
|
/**
|
|
601
1006
|
* Constructs the full API URL for an endpoint.
|
|
1007
|
+
*
|
|
1008
|
+
* @category Utilities
|
|
602
1009
|
*/
|
|
603
1010
|
declare function buildApiUrl(baseURL: string, apiVersion: string, endpoint: string): string;
|
|
604
1011
|
/**
|
|
605
1012
|
* Custom error class for Sanity Agent API errors.
|
|
606
1013
|
* The {@link body} is parsed from the JSON response and follows the
|
|
607
1014
|
* {@link HeadlessErrorResponse} shape defined in `@sanity/agent-types`.
|
|
1015
|
+
*
|
|
1016
|
+
* @category Utilities
|
|
608
1017
|
*/
|
|
609
1018
|
declare class SanityAgentError extends Error {
|
|
610
1019
|
readonly status: number;
|
|
@@ -625,11 +1034,15 @@ type AgentErrorType = {
|
|
|
625
1034
|
* Classifies a caught error from the Content Agent API into a known error type.
|
|
626
1035
|
* Useful for clients that need to take different actions per error (e.g. show
|
|
627
1036
|
* resource-selection buttons). For the user-facing message, use {@link getAgentErrorMessage}.
|
|
1037
|
+
*
|
|
1038
|
+
* @category Utilities
|
|
628
1039
|
*/
|
|
629
1040
|
declare function classifyAgentError(error: unknown): AgentErrorType;
|
|
630
1041
|
/**
|
|
631
1042
|
* Extracts a user-facing error message from an agent API error.
|
|
632
1043
|
* Returns the message sent by the API when available, otherwise a generic fallback.
|
|
1044
|
+
*
|
|
1045
|
+
* @category Utilities
|
|
633
1046
|
*/
|
|
634
1047
|
declare function getAgentErrorMessage(error: unknown): string;
|
|
635
1048
|
interface FetchOptions {
|
|
@@ -642,10 +1055,14 @@ interface FetchOptions {
|
|
|
642
1055
|
/**
|
|
643
1056
|
* Makes a POST request and returns the response.
|
|
644
1057
|
* Throws SanityAgentError if the response is not ok.
|
|
1058
|
+
*
|
|
1059
|
+
* @category Utilities
|
|
645
1060
|
*/
|
|
646
1061
|
declare function fetchApi(options: FetchOptions): Promise<Response>;
|
|
647
1062
|
/**
|
|
648
1063
|
* Extracts text content from message parts (user or assistant).
|
|
1064
|
+
*
|
|
1065
|
+
* @category Utilities
|
|
649
1066
|
*/
|
|
650
1067
|
declare function extractTextFromParts(content: string | Array<{
|
|
651
1068
|
type: string;
|
|
@@ -653,6 +1070,8 @@ declare function extractTextFromParts(content: string | Array<{
|
|
|
653
1070
|
}>): string;
|
|
654
1071
|
/**
|
|
655
1072
|
* Maps API finish reasons to LanguageModelV3FinishReason.
|
|
1073
|
+
*
|
|
1074
|
+
* @category Utilities
|
|
656
1075
|
*/
|
|
657
1076
|
declare function mapFinishReason(reason: string | undefined): LanguageModelV3FinishReason;
|
|
658
1077
|
type ParsedStreamLine = {
|
|
@@ -661,31 +1080,52 @@ type ParsedStreamLine = {
|
|
|
661
1080
|
} | {
|
|
662
1081
|
kind: 'finish';
|
|
663
1082
|
finishReason: LanguageModelV3FinishReason;
|
|
1083
|
+
} | {
|
|
1084
|
+
kind: 'data';
|
|
1085
|
+
type: string;
|
|
1086
|
+
data: unknown;
|
|
664
1087
|
};
|
|
665
1088
|
/**
|
|
666
|
-
* Parses a single line from the
|
|
1089
|
+
* Parses a single SSE line from the AI SDK v6 UI Message Stream protocol.
|
|
667
1090
|
* Returns null if the line cannot be parsed or should be ignored.
|
|
668
1091
|
*
|
|
669
|
-
*
|
|
670
|
-
*
|
|
671
|
-
*
|
|
672
|
-
*
|
|
673
|
-
*
|
|
674
|
-
*
|
|
675
|
-
*
|
|
1092
|
+
* Format: `data: <json>\n`
|
|
1093
|
+
*
|
|
1094
|
+
* Supported types:
|
|
1095
|
+
* text-start – Text block start (forwarded as-is)
|
|
1096
|
+
* text-delta – Text chunk
|
|
1097
|
+
* text-end – Text block end (forwarded as-is)
|
|
1098
|
+
* tool-input-available – Tool call (client tools only, without providerExecuted)
|
|
1099
|
+
* tool-output-available – Tool result (informational, skipped)
|
|
1100
|
+
* finish – Finish event with reason
|
|
1101
|
+
* error – Error event
|
|
1102
|
+
* start – Stream start (skipped)
|
|
1103
|
+
* [DONE] – Stream termination (skipped)
|
|
676
1104
|
*
|
|
677
1105
|
* @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol
|
|
1106
|
+
*
|
|
1107
|
+
* @param line A single line from the SSE byte stream.
|
|
1108
|
+
* @param textContentId Fallback ID for text parts that lack an explicit id.
|
|
1109
|
+
*
|
|
1110
|
+
* @category Utilities
|
|
678
1111
|
*/
|
|
679
1112
|
declare function parseStreamLine(line: string, textContentId: string): ParsedStreamLine | null;
|
|
680
1113
|
/**
|
|
681
1114
|
* Extracts accumulated text from a streaming response body.
|
|
682
1115
|
* Used for simple streaming cases where only the final text is needed.
|
|
1116
|
+
*
|
|
1117
|
+
* @category Utilities
|
|
683
1118
|
*/
|
|
684
1119
|
declare function extractTextFromStream(responseBody: ReadableStream<Uint8Array>): Promise<string>;
|
|
685
1120
|
/**
|
|
686
|
-
* Creates a ReadableStream that parses
|
|
687
|
-
* and emits LanguageModelV3 stream parts
|
|
1121
|
+
* Creates a ReadableStream that parses AI SDK v6 UI Message Stream SSE data
|
|
1122
|
+
* from a response body and emits LanguageModelV3 stream parts.
|
|
1123
|
+
*
|
|
1124
|
+
* Text lifecycle events (text-start / text-end) are forwarded from the server.
|
|
1125
|
+
* Tool calls are tracked to ensure the finish reason is set correctly.
|
|
1126
|
+
*
|
|
1127
|
+
* @category Utilities
|
|
688
1128
|
*/
|
|
689
|
-
declare function createSSEStream(responseBody: ReadableStream<Uint8Array>, warnings: SharedV3Warning[]): ReadableStream<LanguageModelV3StreamPart>;
|
|
1129
|
+
declare function createSSEStream(responseBody: ReadableStream<Uint8Array>, warnings: SharedV3Warning[], onData?: (type: string, data: unknown) => void): ReadableStream<LanguageModelV3StreamPart>;
|
|
690
1130
|
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 };
|
|
691
1131
|
//# 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,sCAAA;IACE,UAAA;MACE,KAAA;MACA,MAAA;MACA,IAAA;MACA,MAAA;IAAA;IAEF,GAAA;IACA,GAAA;IAAA;;;;;IAMA,IAAA,EAAM,UAAA;IACN,MAAA;IACA,OAAA;IACA,IAAA;IACA,KAAA;IACA,KAAA;EAAA;EAEF,SAAA;IACE,UAAA;MACE,KAAA;MACA,MAAA;MACA,IAAA;MACA,MAAA;IAAA;IAEF,GAAA;IACA,GAAA;IAUA;;;;AAKJ;IATI,IAAA,EAAM,UAAA;IACN,MAAA;IACA,OAAA;IACA,IAAA;IACA,KAAA;IACA,KAAA;EAAA;AAAA;AAAA,KAIQ,UAAA;EACV,OAAA;IACE,WAAA;MAiJsB,4CA/IpB,QAAA,EAAU,UAAA;MACV,WAAA,GAAc,UAAA;MACd,MAAA,GAAS,UAAA;MA6Ra;;;;MAxRtB,MAAA;MAPA;;;;;;;MAeA,MAAA;IAAA;IAEF,aAAA;MAUE;;;;MALA,cAAA;MAqBF;;;;MAhBE,OAAA;MACA,MAAA,GAAS,UAAA;MAkCT;;;;MA7BA,YAAA;MAiDA;;;;;;;MAzCA,MAAA;IAAA;IAEF,OAAA;MAmEE;;;;MA9DA,IAAA,mCA0EA;MAxEA,OAAA,UAyEA;MAvEA,EAAA,WAwEA;MAtEA,IAAA;IAAA,GAiFA;IA9EF,WAAA;MAsFsB;;;;MAjFpB,GAAA;MACA,QAAA;QAkHF;;;;QA7GI,EAAA;QAmIF;;;;QA9HE,IAAA;MAAA;MA8IJ;;;;;MAvIE,aAAA,WA8JA;MA5JA,aAAA,WA+JA;MA7JA,IAAA,WA6KsB;MA3KtB,KAAA,WAgLA;MA9KA,kBAAA;IAAA,GAwLE;IArLJ,MAAA;MAyLA;;;;MApLE,WAAA;MA+LsB;;;;;;;AAU5B;;MA/LM,kBAAA;QAAA,CACG,GAAA;MAAA;MAEH,YAAA,GAAe,UAAA;MACf,MAAA,GAAS,UAAA;MACT,YAAA,GAAe,UAAA;IAAA;IA6PV;;;;;;;;IAnPP,YAAA;MACE,IAAA,GAAO,UAAA;MACP,KAAA,GAAQ,UAAA;MACR,QAAA,GAAW,UAAA;IAAA;IAgMb;;;;IA1LA,gBAAA;MAiME;;;;MA5LA,SAAA;IAAA;IAmMI;;;;;;IA3LN,UAAA,YAAsB,UAAA;IACtB,gBAAA;MAiMO;;;;;;;;;;MAtLL,MAAA;IAAA,GAuMA;IApMF,MAAA;MAsMM;;;;;MAhMJ,IAAA;MAwMK;;;;;MAlML,KAAA;IAAA;;
|
|
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
|
@@ -94,59 +94,54 @@ function mapFinishReason(reason) {
|
|
|
94
94
|
}
|
|
95
95
|
function parseStreamLine(line, textContentId) {
|
|
96
96
|
const trimmed = line.trim();
|
|
97
|
-
if (!trimmed
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
97
|
+
if (!trimmed.startsWith("data: ")) return null;
|
|
98
|
+
const payload = trimmed.slice(6);
|
|
99
|
+
if (payload === "[DONE]") return null;
|
|
100
|
+
let part;
|
|
101
|
+
try {
|
|
102
|
+
part = JSON.parse(payload);
|
|
103
|
+
} catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const type = part.type;
|
|
107
|
+
if (!type) return null;
|
|
108
|
+
switch (type) {
|
|
109
|
+
case "text-start":
|
|
110
|
+
return { kind: "part", part: { type: "text-start", id: part.id || textContentId } };
|
|
111
|
+
case "text-delta": {
|
|
112
|
+
const id = part.id || textContentId, delta = part.delta;
|
|
113
|
+
return typeof delta != "string" ? null : { kind: "part", part: { type: "text-delta", id, delta } };
|
|
108
114
|
}
|
|
109
|
-
case "
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
}
|
|
115
|
+
case "text-end":
|
|
116
|
+
return { kind: "part", part: { type: "text-end", id: part.id || textContentId } };
|
|
117
|
+
case "tool-input-available": {
|
|
118
|
+
if (part.providerExecuted) return null;
|
|
119
|
+
const input = part.input;
|
|
120
|
+
return {
|
|
121
|
+
kind: "part",
|
|
122
|
+
part: {
|
|
123
|
+
type: "tool-call",
|
|
124
|
+
toolCallId: part.toolCallId,
|
|
125
|
+
toolName: part.toolName,
|
|
126
|
+
input: typeof input == "string" ? input : JSON.stringify(input)
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
case "error":
|
|
131
|
+
return {
|
|
132
|
+
kind: "part",
|
|
133
|
+
part: {
|
|
134
|
+
type: "error",
|
|
135
|
+
error: new Error(part.errorText ?? "Unknown error")
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
case "finish":
|
|
139
|
+
return {
|
|
140
|
+
kind: "finish",
|
|
141
|
+
finishReason: mapFinishReason(part.finishReason)
|
|
142
|
+
};
|
|
148
143
|
default:
|
|
149
|
-
return null;
|
|
144
|
+
return type.startsWith("data-") ? { kind: "data", type: type.slice(5), data: part.data } : null;
|
|
150
145
|
}
|
|
151
146
|
}
|
|
152
147
|
async function extractTextFromStream(responseBody) {
|
|
@@ -164,10 +159,10 @@ async function extractTextFromStream(responseBody) {
|
|
|
164
159
|
}
|
|
165
160
|
return text;
|
|
166
161
|
}
|
|
167
|
-
function createSSEStream(responseBody, warnings) {
|
|
162
|
+
function createSSEStream(responseBody, warnings, onData) {
|
|
168
163
|
let finishReason = { unified: "other", raw: void 0 };
|
|
169
|
-
const
|
|
170
|
-
let
|
|
164
|
+
const fallbackTextId = crypto.randomUUID();
|
|
165
|
+
let hasToolCalls = !1;
|
|
171
166
|
return new ReadableStream({
|
|
172
167
|
async start(controller) {
|
|
173
168
|
const reader = responseBody.getReader(), decoder = new TextDecoder();
|
|
@@ -182,15 +177,15 @@ function createSSEStream(responseBody, warnings) {
|
|
|
182
177
|
`);
|
|
183
178
|
buffer = lines.pop() ?? "";
|
|
184
179
|
for (const line of lines) {
|
|
185
|
-
const parsed = parseStreamLine(line,
|
|
186
|
-
parsed?.kind === "part" ? (parsed.part.type === "
|
|
180
|
+
const parsed = parseStreamLine(line, fallbackTextId);
|
|
181
|
+
parsed?.kind === "part" ? (parsed.part.type === "tool-call" && (hasToolCalls = !0), controller.enqueue(parsed.part)) : parsed?.kind === "finish" ? finishReason = parsed.finishReason : parsed?.kind === "data" && onData?.(parsed.type, parsed.data);
|
|
187
182
|
}
|
|
188
183
|
}
|
|
189
184
|
if (buffer.trim()) {
|
|
190
|
-
const parsed = parseStreamLine(buffer,
|
|
191
|
-
parsed?.kind === "part" ? (parsed.part.type === "
|
|
185
|
+
const parsed = parseStreamLine(buffer, fallbackTextId);
|
|
186
|
+
parsed?.kind === "part" ? (parsed.part.type === "tool-call" && (hasToolCalls = !0), controller.enqueue(parsed.part)) : parsed?.kind === "finish" ? finishReason = parsed.finishReason : parsed?.kind === "data" && onData?.(parsed.type, parsed.data);
|
|
192
187
|
}
|
|
193
|
-
|
|
188
|
+
hasToolCalls && finishReason.unified !== "tool-calls" && (finishReason = { unified: "tool-calls", raw: finishReason.raw ?? "tool-calls" }), controller.enqueue({
|
|
194
189
|
type: "finish",
|
|
195
190
|
finishReason,
|
|
196
191
|
usage: createEmptyUsage()
|
|
@@ -386,7 +381,7 @@ class ContentAgentModel {
|
|
|
386
381
|
if (!response.body)
|
|
387
382
|
throw new Error("No response body for streaming request");
|
|
388
383
|
return {
|
|
389
|
-
stream: createSSEStream(response.body, warnings),
|
|
384
|
+
stream: createSSEStream(response.body, warnings, this.settings.onStreamData),
|
|
390
385
|
request: { body },
|
|
391
386
|
response: { headers: this.getResponseHeaders(response) }
|
|
392
387
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/utils.ts","../src/sanity-agent-language-model.ts","../src/sanity-agent-provider.ts"],"sourcesContent":["import type {\n LanguageModelV3FinishReason,\n LanguageModelV3StreamPart,\n LanguageModelV3Usage,\n SharedV3Warning,\n} from '@ai-sdk/provider'\nimport { 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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"}
|
|
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 *\n * @category Utilities\n */\nexport function buildHeaders(\n configHeaders: Record<string, string | undefined>,\n additionalHeaders?: Record<string, string>,\n): Record<string, string> {\n return pickBy(\n {\n 'Content-Type': 'application/json',\n ...additionalHeaders,\n ...configHeaders,\n },\n isString,\n )\n}\n\n/**\n * Constructs the full API URL for an endpoint.\n *\n * @category Utilities\n */\nexport function buildApiUrl(baseURL: string, apiVersion: string, endpoint: string): string {\n return `${baseURL}/${apiVersion}/agent${endpoint}`\n}\n\n/**\n * Custom error class for Sanity Agent API errors.\n * The {@link body} is parsed from the JSON response and follows the\n * {@link HeadlessErrorResponse} shape defined in `@sanity/agent-types`.\n *\n * @category Utilities\n */\nexport class SanityAgentError extends Error {\n readonly status: number\n readonly isRetryable: boolean\n readonly body: Partial<HeadlessErrorResponse>\n\n constructor(status: number, message: string) {\n super(`Sanity Agent API error: ${status} ${message}`)\n this.name = 'SanityAgentError'\n this.status = status\n this.isRetryable = status >= 500\n this.body = SanityAgentError.parseBody(message)\n }\n\n private static parseBody(message: string): Partial<HeadlessErrorResponse> {\n try {\n return JSON.parse(message)\n } catch {\n return {}\n }\n }\n}\n\nexport const GENERIC_ERROR_MESSAGE = 'Sorry, something went wrong. Please try again.'\n\nexport type AgentErrorType =\n | { type: 'no_applications' }\n | { type: 'application_not_found' }\n | { type: 'unknown' }\n\n/**\n * Classifies a caught error from the Content Agent API into a known error type.\n * Useful for clients that need to take different actions per error (e.g. show\n * resource-selection buttons). For the user-facing message, use {@link getAgentErrorMessage}.\n *\n * @category Utilities\n */\nexport function classifyAgentError(error: unknown): AgentErrorType {\n if (!(error instanceof SanityAgentError) || error.status !== 400) {\n return { type: 'unknown' }\n }\n\n switch (error.body.code) {\n case 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 *\n * @category Utilities\n */\nexport function getAgentErrorMessage(error: unknown): string {\n if (error instanceof SanityAgentError && error.body.message) {\n return error.body.message\n }\n return GENERIC_ERROR_MESSAGE\n}\n\nexport interface FetchOptions {\n url: string\n body: unknown\n headers: Record<string, string>\n signal?: AbortSignal\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Makes a POST request and returns the response.\n * Throws SanityAgentError if the response is not ok.\n *\n * @category Utilities\n */\nexport async function fetchApi(options: FetchOptions): Promise<Response> {\n const fetchFn = options.fetch ?? globalThis.fetch\n\n const response = await fetchFn(options.url, {\n method: 'POST',\n headers: options.headers,\n body: JSON.stringify(options.body),\n signal: options.signal,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new SanityAgentError(response.status, errorText)\n }\n\n return response\n}\n\n/**\n * Extracts text content from message parts (user or assistant).\n *\n * @category Utilities\n */\nexport function extractTextFromParts(\n content: string | Array<{ type: string; text?: string }>,\n): string {\n if (typeof content === 'string') {\n return content\n }\n\n return content\n .filter(\n (part): part is { type: 'text'; text: string } =>\n part.type === 'text' && typeof part.text === 'string',\n )\n .map((part) => part.text)\n .join('\\n')\n}\n\n/**\n * Creates an empty V3 usage object. Our API does not return token counts.\n *\n * @category Utilities\n */\nexport function createEmptyUsage(): LanguageModelV3Usage {\n return {\n inputTokens: {\n total: 0,\n noCache: undefined,\n cacheRead: undefined,\n cacheWrite: undefined,\n },\n outputTokens: {\n total: 0,\n text: undefined,\n reasoning: undefined,\n },\n }\n}\n\n/**\n * Maps API finish reasons to LanguageModelV3FinishReason.\n *\n * @category Utilities\n */\nexport function mapFinishReason(reason: string | undefined): LanguageModelV3FinishReason {\n const unified = (() => {\n switch (reason) {\n case 'stop':\n case 'length':\n case 'content-filter':\n case 'tool-calls':\n case 'error':\n return reason\n default:\n return 'other' as const\n }\n })()\n\n return { unified, raw: reason }\n}\n\nexport type ParsedStreamLine =\n | { kind: 'part'; part: LanguageModelV3StreamPart }\n | { kind: 'finish'; finishReason: LanguageModelV3FinishReason }\n | { kind: 'data'; type: string; data: unknown }\n\n/**\n * Parses a single SSE line from the AI SDK v6 UI Message Stream protocol.\n * Returns null if the line cannot be parsed or should be ignored.\n *\n * Format: `data: <json>\\n`\n *\n * Supported types:\n * text-start – Text block start (forwarded as-is)\n * text-delta – Text chunk\n * text-end – Text block end (forwarded as-is)\n * tool-input-available – Tool call (client tools only, without providerExecuted)\n * tool-output-available – Tool result (informational, skipped)\n * finish – Finish event with reason\n * error – Error event\n * start – Stream start (skipped)\n * [DONE] – Stream termination (skipped)\n *\n * @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol\n *\n * @param line A single line from the SSE byte stream.\n * @param textContentId Fallback ID for text parts that lack an explicit id.\n *\n * @category Utilities\n */\nexport function parseStreamLine(line: string, textContentId: string): ParsedStreamLine | null {\n const trimmed = line.trim()\n if (!trimmed.startsWith('data: ')) return null\n\n const payload = trimmed.slice(6)\n if (payload === '[DONE]') return null\n\n let part: Record<string, unknown>\n try {\n part = JSON.parse(payload) as Record<string, unknown>\n } catch {\n return null\n }\n\n const type = part.type as string | undefined\n if (!type) return null\n\n switch (type) {\n case 'text-start': {\n const id = (part.id as string) || textContentId\n return { kind: 'part', part: { type: 'text-start', id } }\n }\n\n case 'text-delta': {\n const id = (part.id as string) || textContentId\n const delta = part.delta as string\n if (typeof delta !== 'string') return null\n return { kind: 'part', part: { type: 'text-delta', id, delta } }\n }\n\n case 'text-end': {\n const id = (part.id as string) || textContentId\n return { kind: 'part', part: { type: 'text-end', id } }\n }\n\n case 'tool-input-available': {\n // Skip server-executed tools — only forward client tools for local execution.\n if (part.providerExecuted) return null\n\n const input = part.input\n return {\n kind: 'part',\n part: {\n type: 'tool-call',\n toolCallId: part.toolCallId as string,\n toolName: part.toolName as string,\n input: typeof input === 'string' ? input : JSON.stringify(input),\n },\n }\n }\n\n case 'error': {\n return {\n kind: 'part',\n part: {\n type: 'error',\n error: new Error((part.errorText as string) ?? 'Unknown error'),\n },\n }\n }\n\n case 'finish': {\n return {\n kind: 'finish',\n finishReason: mapFinishReason(part.finishReason as string | undefined),\n }\n }\n\n default: {\n if (type.startsWith('data-')) {\n return { kind: 'data', type: type.slice(5), data: part.data }\n }\n return null\n }\n }\n}\n\n/**\n * Extracts accumulated text from a streaming response body.\n * Used for simple streaming cases where only the final text is needed.\n *\n * @category Utilities\n */\nexport async function extractTextFromStream(\n responseBody: ReadableStream<Uint8Array>,\n): Promise<string> {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\n const textContentId = 'extract'\n let text = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n for (const line of chunk.split('\\n')) {\n const parsed = parseStreamLine(line, textContentId)\n if (parsed?.kind === 'part' && parsed.part.type === 'text-delta') {\n text += parsed.part.delta\n }\n }\n }\n\n return text\n}\n\n/**\n * Creates a ReadableStream that parses AI SDK v6 UI Message Stream SSE data\n * from a response body and emits LanguageModelV3 stream parts.\n *\n * Text lifecycle events (text-start / text-end) are forwarded from the server.\n * Tool calls are tracked to ensure the finish reason is set correctly.\n *\n * @category Utilities\n */\nexport function createSSEStream(\n responseBody: ReadableStream<Uint8Array>,\n warnings: SharedV3Warning[],\n onData?: (type: string, data: unknown) => void,\n): ReadableStream<LanguageModelV3StreamPart> {\n let finishReason: LanguageModelV3FinishReason = { unified: 'other', raw: undefined }\n const fallbackTextId = crypto.randomUUID()\n let hasToolCalls = false\n\n return new ReadableStream<LanguageModelV3StreamPart>({\n async start(controller) {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n controller.enqueue({ type: 'stream-start', warnings })\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n\n for (const line of lines) {\n const parsed = parseStreamLine(line, fallbackTextId)\n if (parsed?.kind === 'part') {\n if (parsed.part.type === 'tool-call') {\n hasToolCalls = true\n }\n controller.enqueue(parsed.part)\n } else if (parsed?.kind === 'finish') {\n finishReason = parsed.finishReason\n } else if (parsed?.kind === 'data') {\n onData?.(parsed.type, parsed.data)\n }\n }\n }\n\n if (buffer.trim()) {\n const parsed = parseStreamLine(buffer, fallbackTextId)\n if (parsed?.kind === 'part') {\n if (parsed.part.type === 'tool-call') {\n hasToolCalls = true\n }\n controller.enqueue(parsed.part)\n } else if (parsed?.kind === 'finish') {\n finishReason = parsed.finishReason\n } else if (parsed?.kind === 'data') {\n onData?.(parsed.type, parsed.data)\n }\n }\n\n // If tool calls were emitted, override finish reason so streamText\n // knows to execute tools and continue with the next step.\n if (hasToolCalls && finishReason.unified !== 'tool-calls') {\n finishReason = { unified: 'tool-calls', raw: finishReason.raw ?? 'tool-calls' }\n }\n\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage: createEmptyUsage(),\n })\n } catch (error) {\n controller.enqueue({\n type: 'error',\n error: error instanceof Error ? error : new Error(String(error)),\n })\n } finally {\n controller.close()\n }\n },\n })\n}\n","import type {\n LanguageModelV3,\n LanguageModelV3CallOptions,\n LanguageModelV3Content,\n LanguageModelV3GenerateResult,\n LanguageModelV3Prompt,\n LanguageModelV3StreamResult,\n SharedV3Warning,\n} from '@ai-sdk/provider'\nimport type { ClientToolDefinition } from '@sanity/agent-types'\nimport { groupBy } from 'es-toolkit'\nimport type { AgentSettings, Message } from './types'\nimport {\n buildApiUrl,\n buildHeaders,\n createEmptyUsage,\n createSSEStream,\n extractTextFromParts,\n fetchApi,\n parseStreamLine,\n} from './utils'\n\n/**\n * @category Model\n */\nexport interface ContentAgentModelConfig {\n provider: string\n baseURL: string\n apiVersion: string\n organizationId: string\n headers: () => Record<string, string | undefined>\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Extended message type for the wire format that supports tool calls and tool results\n * in addition to plain text messages.\n */\ntype WireMessage =\n | Message\n | {\n role: 'assistant'\n content: Array<\n | { type: 'text'; text: string }\n | { type: 'tool-call'; toolCallId: string; toolName: string; input: string }\n >\n }\n | {\n role: 'tool'\n content: Array<{\n type: 'tool-result'\n toolCallId: string\n toolName: string\n output: unknown\n }>\n }\n\nconst UNSUPPORTED_SETTINGS = [\n 'maxOutputTokens',\n 'temperature',\n 'topP',\n 'topK',\n 'frequencyPenalty',\n 'presencePenalty',\n 'seed',\n] as const\n\n/**\n * Vercel AI SDK `LanguageModelV1` implementation that communicates with the\n * Sanity Content Agent API via a conversation thread.\n *\n * Typically you don't construct this directly — use\n * {@link createContentAgent | createContentAgent().agent(threadId)} instead.\n *\n * @category Model\n *\n * @example\n * ```ts\n * import { createContentAgent } from 'content-agent'\n * import { streamText } from 'ai'\n *\n * const contentAgent = createContentAgent({\n * organizationId: 'your-org-id',\n * token: 'your-sanity-token',\n * })\n *\n * const model = contentAgent.agent('my-thread-id', {\n * application: { key: 'projectId.datasetName' },\n * config: {\n * capabilities: { read: true, write: false },\n * },\n * })\n *\n * const { textStream } = await streamText({ model, prompt: 'Summarize my content' })\n * for await (const chunk of textStream) {\n * process.stdout.write(chunk)\n * }\n * ```\n */\nexport class ContentAgentModel implements LanguageModelV3 {\n readonly specificationVersion = 'v3' as const\n readonly provider: string\n readonly modelId: string\n readonly supportedUrls: Record<string, RegExp[]> = {}\n\n private readonly config: ContentAgentModelConfig\n private readonly threadId: string\n private readonly settings: AgentSettings\n\n constructor(\n threadId: string,\n settings: AgentSettings | undefined,\n config: ContentAgentModelConfig,\n ) {\n this.threadId = threadId\n this.modelId = `content-agent:${threadId}`\n this.provider = config.provider\n this.settings = settings ?? {}\n this.config = config\n }\n\n /**\n * Converts a LanguageModelV3Prompt into wire messages for the agent API.\n *\n * Handles all message roles:\n * - system: plain text system messages\n * - user: extracts text from content parts\n * - assistant: extracts text and/or tool-call parts\n * - tool: converts tool-result parts for the API\n */\n private convertPromptToMessages(prompt: LanguageModelV3Prompt): WireMessage[] {\n const messages: WireMessage[] = []\n\n for (const message of prompt) {\n if (message.role === 'system') {\n if (message.content) {\n messages.push({ role: 'system', content: message.content })\n }\n continue\n }\n\n if (message.role === 'tool') {\n const toolResults = message.content\n .filter((part) => part.type === 'tool-result')\n .map((part) => {\n const p = part as {\n toolCallId: string\n toolName: string\n output: { type: string; value: unknown } | unknown\n }\n return {\n type: 'tool-result' as const,\n toolCallId: p.toolCallId,\n toolName: p.toolName,\n output:\n p.output && typeof p.output === 'object' && 'value' in p.output\n ? (p.output as { value: unknown }).value\n : p.output,\n }\n })\n\n if (toolResults.length > 0) {\n messages.push({ role: 'tool', content: toolResults })\n }\n continue\n }\n\n if (message.role === 'assistant') {\n const content = message.content as Array<{\n type: string\n text?: string\n toolCallId?: string\n toolName?: string\n input?: string\n }>\n\n const grouped = groupBy(content, (p) => p.type)\n const toolCalls = grouped['tool-call'] ?? []\n const textParts = grouped['text'] ?? []\n\n if (toolCalls.length > 0) {\n const parts = [\n ...textParts\n .filter((p) => p.text)\n .map((p) => ({ type: 'text' as const, text: p.text! })),\n ...toolCalls.map((tc) => ({\n type: 'tool-call' as const,\n toolCallId: tc.toolCallId!,\n toolName: tc.toolName!,\n input: tc.input!,\n })),\n ]\n\n if (parts.length > 0) {\n messages.push({ role: 'assistant', content: parts })\n }\n } else {\n const text = extractTextFromParts(content as Array<{ type: string; text?: string }>)\n if (text) {\n messages.push({ role: 'assistant', content: text })\n }\n }\n continue\n }\n\n // user messages\n const text = extractTextFromParts(message.content as Array<{ type: string; text?: string }>)\n if (text) {\n messages.push({ role: message.role, content: text })\n }\n }\n\n return messages\n }\n\n /**\n * Extracts client tool definitions from the model call options.\n * Only the schemas are sent — execute functions stay on the client.\n */\n private extractClientTools(\n options: LanguageModelV3CallOptions,\n ): ClientToolDefinition[] | undefined {\n if (!options.tools?.length) return undefined\n\n const clientTools = options.tools\n .filter((t) => t.type === 'function')\n .map((t) => ({\n type: 'function' as const,\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema as Record<string, unknown>,\n }))\n\n return clientTools.length > 0 ? clientTools : undefined\n }\n\n private collectWarnings(options: LanguageModelV3CallOptions): SharedV3Warning[] {\n const warnings: SharedV3Warning[] = []\n\n for (const setting of UNSUPPORTED_SETTINGS) {\n if (options[setting] !== undefined) {\n warnings.push({ type: 'unsupported', feature: setting })\n }\n }\n\n if (options.stopSequences?.length) {\n warnings.push({ type: 'unsupported', feature: 'stopSequences' })\n }\n\n if (options.responseFormat && options.responseFormat.type !== 'text') {\n warnings.push({ type: 'unsupported', feature: 'responseFormat' })\n }\n\n return warnings\n }\n\n private buildRequestBody(options: LanguageModelV3CallOptions, stream: boolean) {\n const clientTools = this.extractClientTools(options)\n const toolChoice = options.toolChoice\n\n return {\n messages: this.convertPromptToMessages(options.prompt),\n stream,\n ...(clientTools && { clientTools }),\n ...(toolChoice && { toolChoice }),\n ...(this.settings.application && { application: this.settings.application }),\n ...(this.settings.config && { config: this.settings.config }),\n ...(this.settings.format && { format: this.settings.format }),\n }\n }\n\n private getResponseHeaders(response: Response): Record<string, string> {\n return Object.fromEntries(response.headers.entries())\n }\n\n async doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult> {\n // Always request a stream from the backend and buffer the result.\n // This keeps the HTTP connection alive with incremental data, avoiding\n // 504 gateway timeouts on long-running agent requests.\n const body = this.buildRequestBody(options, true)\n const warnings = this.collectWarnings(options)\n\n const response = await fetchApi({\n url: buildApiUrl(\n this.config.baseURL,\n this.config.apiVersion,\n `/${this.config.organizationId}/threads/${this.threadId}`,\n ),\n body,\n headers: buildHeaders(this.config.headers()),\n signal: options.abortSignal,\n fetch: this.config.fetch,\n })\n\n if (!response.body) {\n throw new Error('No response body for generate request')\n }\n\n const { content, finishReason } = await this.extractContentFromStream(response.body)\n\n return {\n content,\n finishReason,\n usage: createEmptyUsage(),\n request: { body },\n response: { headers: this.getResponseHeaders(response) },\n warnings,\n }\n }\n\n /**\n * Parses a streamed response body into content parts (text and tool calls)\n * and a finish reason. Used by doGenerate to buffer the full response.\n */\n private async extractContentFromStream(responseBody: ReadableStream<Uint8Array>): Promise<{\n content: LanguageModelV3Content[]\n finishReason: LanguageModelV3GenerateResult['finishReason']\n }> {\n const reader = responseBody.getReader()\n const decoder = new TextDecoder()\n const textContentId = 'generate'\n let text = ''\n let hasToolCalls = false\n const content: LanguageModelV3Content[] = []\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n for (const line of chunk.split('\\n')) {\n const parsed = parseStreamLine(line, textContentId)\n if (parsed?.kind === 'part') {\n if (parsed.part.type === 'text-delta') {\n text += parsed.part.delta\n } else if (parsed.part.type === 'tool-call') {\n hasToolCalls = true\n const tc = parsed.part as { toolCallId: string; toolName: string; input: string }\n content.push({\n type: 'tool-call',\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n input: tc.input,\n })\n }\n }\n }\n }\n\n if (text) {\n content.unshift({ type: 'text', text })\n }\n\n const finishReason = hasToolCalls\n ? { unified: 'tool-calls' as const, raw: 'tool-calls' }\n : { unified: 'stop' as const, raw: undefined }\n\n return { content, finishReason }\n }\n\n async doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult> {\n const body = this.buildRequestBody(options, true)\n const warnings = this.collectWarnings(options)\n\n const response = await fetchApi({\n url: buildApiUrl(\n this.config.baseURL,\n this.config.apiVersion,\n `/${this.config.organizationId}/threads/${this.threadId}`,\n ),\n body,\n headers: buildHeaders(this.config.headers()),\n signal: options.abortSignal,\n fetch: this.config.fetch,\n })\n\n if (!response.body) {\n throw new Error('No response body for streaming request')\n }\n\n return {\n stream: createSSEStream(response.body, warnings, this.settings.onStreamData),\n request: { body },\n response: { headers: this.getResponseHeaders(response) },\n }\n }\n}\n","import type { LanguageModelV3 } from '@ai-sdk/provider'\nimport { ContentAgentModel, type ContentAgentModelConfig } from './sanity-agent-language-model'\nimport type {\n AgentSettings,\n Application,\n ContentAgentProviderSettings,\n GenerateOptions,\n GenerateResult,\n GenerateSettings,\n} from './types'\nimport {\n buildApiUrl,\n buildHeaders,\n extractTextFromStream,\n fetchApi,\n SanityAgentError,\n} from './utils'\n\nconst DEFAULT_BASE_URL = 'https://api.sanity.io'\nconst DEFAULT_API_VERSION = 'v2026-01-01'\n\n/**\n * A Content Agent provider instance returned by {@link createContentAgent}.\n *\n * Provides two modes of interaction:\n * - **Conversation threads** via {@link ContentAgentProvider.agent | .agent()} — stateful, multi-turn conversations with server-side message history.\n * - **One-shot prompts** via {@link ContentAgentProvider.prompt | .prompt()} — stateless, single-turn interactions.\n *\n * @category Provider\n */\nexport interface ContentAgentProvider {\n /**\n * Creates a Vercel AI SDK {@link https://sdk.vercel.ai/docs/ai-sdk-core | LanguageModelV1} for a conversation thread.\n *\n * The thread ID identifies the conversation and maintains message history server-side.\n * If a thread with that ID already exists, the conversation continues. If not, a new\n * thread is automatically created.\n *\n * Use the returned model with `generateText` or `streamText` from the `ai` package.\n *\n * @example\n * ```ts\n * import { generateText, streamText } from 'ai'\n *\n * const model = contentAgent.agent('my-thread-id', {\n * application: { key: 'projectId.datasetName' },\n * config: {\n * capabilities: { read: true, write: false },\n * },\n * })\n *\n * // Non-streaming\n * const { text } = await generateText({ model, prompt: 'What blog posts do I have?' })\n *\n * // Streaming\n * const { textStream } = await streamText({ model, prompt: 'Summarize my content' })\n * for await (const chunk of textStream) {\n * process.stdout.write(chunk)\n * }\n * ```\n *\n * @param threadId - Unique identifier for the conversation thread.\n * @param settings - Optional agent settings (application, capabilities, filters, etc.).\n */\n agent(threadId: string, settings?: AgentSettings): LanguageModelV3\n\n /**\n * Lists available applications for the organization.\n *\n * Returns all Sanity Studio applications the authenticated user has access to.\n * Use the `key` from a returned application to target it when creating an agent.\n *\n * @example\n * ```ts\n * const apps = await contentAgent.applications()\n * const app = apps.find((app) => app.title === \"My Studio\")\n *\n * const model = contentAgent.agent(\"my-thread\", {\n * application: { key: app.key },\n * })\n * ```\n */\n applications(): Promise<Application[]>\n\n /**\n * Sends a one-shot prompt to the Content Agent (stateless).\n *\n * Unlike {@link ContentAgentProvider.agent | .agent()}, this does not create or use a conversation thread.\n * Each call is independent with no message history or persistence.\n * Ideal for simple, single-turn interactions.\n *\n * @example\n * ```ts\n * const { text } = await contentAgent.prompt(\n * {\n * application: { key: 'projectId.datasetName' },\n * config: { capabilities: { read: true, write: false } },\n * instructions: 'Be concise',\n * },\n * { message: 'List my 5 most recent posts' },\n * )\n * ```\n *\n * @param settings - Generation settings (application, capabilities, instructions, etc.).\n * @param options - The prompt message and request options.\n */\n prompt(settings: GenerateSettings, options: GenerateOptions): Promise<GenerateResult>\n}\n\n/**\n * Creates a Content Agent provider instance.\n *\n * The provider is the main entry point for interacting with the Sanity Content Agent API.\n * It returns an object with methods for conversation threads and one-shot prompts.\n *\n * @category Provider\n *\n * @example Basic setup\n * ```ts\n * import { createContentAgent } from 'content-agent'\n *\n * const contentAgent = createContentAgent({\n * organizationId: 'your-org-id',\n * token: 'your-sanity-token',\n * })\n * ```\n *\n * @example Using with Vercel AI SDK for conversation threads\n * ```ts\n * import { createContentAgent } from 'content-agent'\n * import { generateText, streamText } from 'ai'\n *\n * const contentAgent = createContentAgent({\n * organizationId: 'your-org-id',\n * token: 'your-sanity-token',\n * })\n *\n * const model = contentAgent.agent('my-thread-id', {\n * application: { key: 'projectId.datasetName' },\n * config: {\n * capabilities: { read: true, write: false },\n * },\n * })\n *\n * // Non-streaming\n * const { text } = await generateText({ model, prompt: 'What blog posts do I have?' })\n *\n * // Streaming\n * const { textStream } = await streamText({ model, prompt: 'Summarize my content' })\n * for await (const chunk of textStream) {\n * process.stdout.write(chunk)\n * }\n * ```\n *\n * @example One-shot generation (stateless, no thread)\n * ```ts\n * const { text } = await contentAgent.prompt(\n * {\n * application: { key: 'projectId.datasetName' },\n * config: { capabilities: { read: true, write: false } },\n * instructions: 'Be concise',\n * },\n * { message: 'List my 5 most recent posts' },\n * )\n * ```\n *\n * @param options - Provider configuration including organization ID, token, and optional overrides.\n */\nexport function createContentAgent(options: ContentAgentProviderSettings): ContentAgentProvider {\n const baseURL = options.baseURL?.replace(/\\/$/, '') ?? DEFAULT_BASE_URL\n const apiVersion = options.apiVersion ?? DEFAULT_API_VERSION\n const { organizationId } = options\n\n const getHeaders = (): Record<string, string | undefined> => ({\n ...(options.token && { Authorization: `Bearer ${options.token}` }),\n ...options.headers,\n })\n\n const config: ContentAgentModelConfig = {\n provider: 'content-agent',\n baseURL,\n apiVersion,\n organizationId,\n headers: getHeaders,\n fetch: options.fetch,\n }\n\n const agent = (threadId: string, settings?: AgentSettings): LanguageModelV3 => {\n return new ContentAgentModel(threadId, settings, config)\n }\n\n const applications = async (): Promise<Application[]> => {\n const fetchFn = options.fetch ?? globalThis.fetch\n const url = buildApiUrl(baseURL, apiVersion, `/${organizationId}/applications`)\n const headers = buildHeaders(getHeaders())\n\n const response = await fetchFn(url, { method: 'GET', headers })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new SanityAgentError(response.status, errorText)\n }\n\n const json = (await response.json()) as { applications?: Application[] }\n return json.applications ?? []\n }\n\n const prompt = async (\n settings: GenerateSettings,\n generateOptions: GenerateOptions,\n ): Promise<GenerateResult> => {\n const body = {\n organizationId,\n message: generateOptions.message,\n stream: generateOptions.stream ?? false,\n ...(settings.application && { application: settings.application }),\n ...(settings.config && { config: settings.config }),\n ...(settings.instructions && { instructions: settings.instructions }),\n ...(settings.format && { format: settings.format }),\n }\n\n const response = await fetchApi({\n url: buildApiUrl(baseURL, apiVersion, '/prompt'),\n body,\n headers: buildHeaders(getHeaders()),\n signal: generateOptions.abortSignal,\n fetch: options.fetch,\n })\n\n if (body.stream) {\n if (!response.body) {\n throw new SanityAgentError(500, 'No response body')\n }\n return { text: await extractTextFromStream(response.body) }\n }\n\n const json = (await response.json()) as { text?: string }\n return { text: json.text ?? '' }\n }\n\n return { agent, applications, prompt }\n}\n"],"names":["text"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "content-agent",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Vercel AI SDK provider for Sanity Content Agent API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -30,12 +30,13 @@
|
|
|
30
30
|
"@ai-sdk/provider": "^3.0.0",
|
|
31
31
|
"@ai-sdk/provider-utils": "^2.2.8",
|
|
32
32
|
"es-toolkit": "^1.32.0",
|
|
33
|
-
"@sanity/agent-types": "0.0.
|
|
33
|
+
"@sanity/agent-types": "0.0.80"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@sanity/pkg-utils": "^10.4.1",
|
|
37
37
|
"@types/node": "^22.19.7",
|
|
38
38
|
"openapi-typescript": "^7.10.1",
|
|
39
|
+
"typedoc": "^0.28.17",
|
|
39
40
|
"typescript": "^5.9.3",
|
|
40
41
|
"vitest": "^4.0.18",
|
|
41
42
|
"@repo/package.config": "0.0.0",
|
|
@@ -58,6 +59,7 @@
|
|
|
58
59
|
"scripts": {
|
|
59
60
|
"build": "pkg build --strict --check --clean",
|
|
60
61
|
"clean": "rm -rf dist",
|
|
62
|
+
"docs:generate": "typedoc",
|
|
61
63
|
"generate-types": "openapi-typescript ../agent/docs/headless/openapi.yaml -o src/generated/openapi.ts --export-type",
|
|
62
64
|
"test": "vitest run --passWithNoTests",
|
|
63
65
|
"test:watch": "vitest"
|