@ai-sdk/anthropic 4.0.0-beta.19 → 4.0.0-beta.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/anthropic",
3
- "version": "4.0.0-beta.19",
3
+ "version": "4.0.0-beta.21",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -36,8 +36,8 @@
36
36
  }
37
37
  },
38
38
  "dependencies": {
39
- "@ai-sdk/provider": "4.0.0-beta.7",
40
- "@ai-sdk/provider-utils": "5.0.0-beta.12"
39
+ "@ai-sdk/provider": "4.0.0-beta.8",
40
+ "@ai-sdk/provider-utils": "5.0.0-beta.14"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "20.17.24",
@@ -31,6 +31,7 @@ import {
31
31
  postJsonToApi,
32
32
  Resolvable,
33
33
  resolve,
34
+ resolveProviderReference,
34
35
  } from '@ai-sdk/provider-utils';
35
36
  import { anthropicFailedResponseHandler } from './anthropic-error';
36
37
  import { AnthropicMessageMetadata } from './anthropic-message-metadata';
@@ -450,7 +451,13 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV4 {
450
451
  id: anthropicOptions.container.id,
451
452
  skills: anthropicOptions.container.skills.map(skill => ({
452
453
  type: skill.type,
453
- skill_id: skill.skillId,
454
+ skill_id:
455
+ skill.type === 'custom'
456
+ ? resolveProviderReference({
457
+ reference: skill.providerReference,
458
+ provider: 'anthropic',
459
+ })
460
+ : skill.skillId,
454
461
  version: skill.version,
455
462
  })),
456
463
  } satisfies AnthropicContainer)
@@ -159,11 +159,18 @@ export const anthropicLanguageModelOptions = z.object({
159
159
  id: z.string().optional(),
160
160
  skills: z
161
161
  .array(
162
- z.object({
163
- type: z.union([z.literal('anthropic'), z.literal('custom')]),
164
- skillId: z.string(),
165
- version: z.string().optional(),
166
- }),
162
+ z.discriminatedUnion('type', [
163
+ z.object({
164
+ type: z.literal('anthropic'),
165
+ skillId: z.string(),
166
+ version: z.string().optional(),
167
+ }),
168
+ z.object({
169
+ type: z.literal('custom'),
170
+ providerReference: z.record(z.string(), z.string()),
171
+ version: z.string().optional(),
172
+ }),
173
+ ]),
167
174
  )
168
175
  .optional(),
169
176
  })
@@ -4,6 +4,7 @@ import {
4
4
  LanguageModelV4,
5
5
  NoSuchModelError,
6
6
  ProviderV4,
7
+ SkillsV4,
7
8
  } from '@ai-sdk/provider';
8
9
  import {
9
10
  FetchFunction,
@@ -17,6 +18,7 @@ import { AnthropicFiles } from './anthropic-files';
17
18
  import { AnthropicMessagesLanguageModel } from './anthropic-messages-language-model';
18
19
  import { AnthropicMessagesModelId } from './anthropic-messages-options';
19
20
  import { anthropicTools } from './anthropic-tools';
21
+ import { AnthropicSkills } from './skills/anthropic-skills';
20
22
  import { VERSION } from './version';
21
23
 
22
24
  export interface AnthropicProvider extends ProviderV4 {
@@ -41,6 +43,11 @@ export interface AnthropicProvider extends ProviderV4 {
41
43
 
42
44
  files(): FilesV4;
43
45
 
46
+ /**
47
+ * Returns a SkillsV4 interface for uploading skills to Anthropic.
48
+ */
49
+ skills(): SkillsV4;
50
+
44
51
  /**
45
52
  * Anthropic-specific computer use tool.
46
53
  */
@@ -147,6 +154,14 @@ export function createAnthropic(
147
154
  }),
148
155
  });
149
156
 
157
+ const createSkills = () =>
158
+ new AnthropicSkills({
159
+ provider: `${providerName.replace('.messages', '')}.skills`,
160
+ baseURL,
161
+ headers: getHeaders,
162
+ fetch: options.fetch,
163
+ });
164
+
150
165
  const provider = function (modelId: AnthropicMessagesModelId) {
151
166
  if (new.target) {
152
167
  throw new Error(
@@ -178,6 +193,8 @@ export function createAnthropic(
178
193
  fetch: options.fetch,
179
194
  });
180
195
 
196
+ provider.skills = createSkills;
197
+
181
198
  provider.tools = anthropicTools;
182
199
 
183
200
  return provider;
@@ -0,0 +1,44 @@
1
+ import { lazySchema, zodSchema } from '@ai-sdk/provider-utils';
2
+ import { z } from 'zod/v4';
3
+
4
+ export const anthropicSkillResponseSchema = lazySchema(() =>
5
+ zodSchema(
6
+ z.object({
7
+ id: z.string(),
8
+ display_title: z.string().nullish(),
9
+ name: z.string().nullish(),
10
+ description: z.string().nullish(),
11
+ latest_version: z.string().nullish(),
12
+ source: z.string(),
13
+ created_at: z.string(),
14
+ updated_at: z.string(),
15
+ }),
16
+ ),
17
+ );
18
+
19
+ export type AnthropicSkillResponse = ReturnType<
20
+ typeof anthropicSkillResponseSchema
21
+ >['_type'];
22
+
23
+ export const anthropicSkillVersionListResponseSchema = lazySchema(() =>
24
+ zodSchema(
25
+ z.object({
26
+ data: z.array(
27
+ z.object({
28
+ version: z.string(),
29
+ }),
30
+ ),
31
+ }),
32
+ ),
33
+ );
34
+
35
+ export const anthropicSkillVersionResponseSchema = lazySchema(() =>
36
+ zodSchema(
37
+ z.object({
38
+ type: z.string(),
39
+ skill_id: z.string(),
40
+ name: z.string().nullish(),
41
+ description: z.string().nullish(),
42
+ }),
43
+ ),
44
+ );
@@ -0,0 +1,136 @@
1
+ import { SkillsV4, SharedV4Warning } from '@ai-sdk/provider';
2
+ import {
3
+ combineHeaders,
4
+ convertBase64ToUint8Array,
5
+ createJsonResponseHandler,
6
+ FetchFunction,
7
+ getFromApi,
8
+ postFormDataToApi,
9
+ Resolvable,
10
+ resolve,
11
+ } from '@ai-sdk/provider-utils';
12
+ import { anthropicFailedResponseHandler } from '../anthropic-error';
13
+ import {
14
+ anthropicSkillResponseSchema,
15
+ anthropicSkillVersionResponseSchema,
16
+ } from './anthropic-skills-api';
17
+
18
+ interface AnthropicSkillsConfig {
19
+ provider: string;
20
+ baseURL: string;
21
+ headers: Resolvable<Record<string, string | undefined>>;
22
+ fetch?: FetchFunction;
23
+ }
24
+
25
+ export class AnthropicSkills implements SkillsV4 {
26
+ readonly specificationVersion = 'v4';
27
+
28
+ get provider(): string {
29
+ return this.config.provider;
30
+ }
31
+
32
+ constructor(private readonly config: AnthropicSkillsConfig) {}
33
+
34
+ private async getHeaders(): Promise<Record<string, string | undefined>> {
35
+ return combineHeaders(await resolve(this.config.headers), {
36
+ 'anthropic-beta': 'skills-2025-10-02',
37
+ });
38
+ }
39
+
40
+ private async fetchVersionMetadata({
41
+ skillId,
42
+ version,
43
+ headers,
44
+ }: {
45
+ skillId: string;
46
+ version: string;
47
+ headers: Record<string, string | undefined>;
48
+ }): Promise<{ name?: string; description?: string }> {
49
+ const { value: versionResponse } = await getFromApi({
50
+ url: `${this.config.baseURL}/skills/${skillId}/versions/${version}`,
51
+ headers,
52
+ failedResponseHandler: anthropicFailedResponseHandler,
53
+ successfulResponseHandler: createJsonResponseHandler(
54
+ anthropicSkillVersionResponseSchema,
55
+ ),
56
+ fetch: this.config.fetch,
57
+ });
58
+
59
+ return {
60
+ ...(versionResponse.name != null ? { name: versionResponse.name } : {}),
61
+ ...(versionResponse.description != null
62
+ ? { description: versionResponse.description }
63
+ : {}),
64
+ };
65
+ }
66
+
67
+ async upload(
68
+ params: Parameters<SkillsV4['upload']>[0],
69
+ ): Promise<Awaited<ReturnType<SkillsV4['upload']>>> {
70
+ const warnings: SharedV4Warning[] = [];
71
+
72
+ const formData = new FormData();
73
+
74
+ if (params.displayTitle != null) {
75
+ formData.append('display_title', params.displayTitle);
76
+ }
77
+
78
+ for (const file of params.files) {
79
+ const content =
80
+ typeof file.content === 'string'
81
+ ? convertBase64ToUint8Array(file.content)
82
+ : file.content;
83
+
84
+ formData.append('files[]', new Blob([content]), file.path);
85
+ }
86
+
87
+ const headers = await this.getHeaders();
88
+
89
+ const { value: response } = await postFormDataToApi({
90
+ url: `${this.config.baseURL}/skills`,
91
+ headers,
92
+ formData,
93
+ failedResponseHandler: anthropicFailedResponseHandler,
94
+ successfulResponseHandler: createJsonResponseHandler(
95
+ anthropicSkillResponseSchema,
96
+ ),
97
+ fetch: this.config.fetch,
98
+ });
99
+
100
+ const versionMetadata =
101
+ response.latest_version != null
102
+ ? await this.fetchVersionMetadata({
103
+ skillId: response.id,
104
+ version: response.latest_version,
105
+ headers,
106
+ })
107
+ : {};
108
+
109
+ const name = versionMetadata.name ?? response.name;
110
+ const description = versionMetadata.description ?? response.description;
111
+
112
+ return {
113
+ providerReference: { anthropic: response.id },
114
+ ...(response.display_title != null
115
+ ? { displayTitle: response.display_title }
116
+ : {}),
117
+ ...(name != null ? { name } : {}),
118
+ ...(description != null ? { description } : {}),
119
+ ...(response.latest_version != null
120
+ ? { latestVersion: response.latest_version }
121
+ : {}),
122
+ providerMetadata: {
123
+ anthropic: {
124
+ ...(response.source != null ? { source: response.source } : {}),
125
+ ...(response.created_at != null
126
+ ? { createdAt: response.created_at }
127
+ : {}),
128
+ ...(response.updated_at != null
129
+ ? { updatedAt: response.updated_at }
130
+ : {}),
131
+ },
132
+ },
133
+ warnings,
134
+ };
135
+ }
136
+ }