@tanstack/ai-anthropic 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/adapters/summarize.d.ts +54 -0
- package/dist/esm/adapters/summarize.js +117 -0
- package/dist/esm/adapters/summarize.js.map +1 -0
- package/dist/esm/adapters/text.d.ts +60 -0
- package/dist/esm/{anthropic-adapter.js → adapters/text.js} +109 -146
- package/dist/esm/adapters/text.js.map +1 -0
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +8 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/text/text-provider-options.js.map +1 -1
- package/dist/esm/tools/custom-tool.js +6 -4
- package/dist/esm/tools/custom-tool.js.map +1 -1
- package/dist/esm/utils/client.d.ts +17 -0
- package/dist/esm/utils/client.js +25 -0
- package/dist/esm/utils/client.js.map +1 -0
- package/dist/esm/utils/index.d.ts +1 -0
- package/package.json +5 -5
- package/src/adapters/summarize.ts +200 -0
- package/src/{anthropic-adapter.ts → adapters/text.ts} +223 -262
- package/src/index.ts +25 -5
- package/src/text/text-provider-options.ts +1 -2
- package/src/tools/custom-tool.ts +9 -6
- package/src/utils/client.ts +45 -0
- package/src/utils/index.ts +6 -0
- package/dist/esm/anthropic-adapter.d.ts +0 -69
- package/dist/esm/anthropic-adapter.js.map +0 -1
- package/dist/esm/model-meta.js +0 -42
- package/dist/esm/model-meta.js.map +0 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { BaseSummarizeAdapter } from '@tanstack/ai/adapters';
|
|
2
|
+
import { ANTHROPIC_MODELS } from '../model-meta.js';
|
|
3
|
+
import { StreamChunk, SummarizationOptions, SummarizationResult } from '@tanstack/ai';
|
|
4
|
+
import { AnthropicClientConfig } from '../utils.js';
|
|
5
|
+
/**
|
|
6
|
+
* Configuration for Anthropic summarize adapter
|
|
7
|
+
*/
|
|
8
|
+
export interface AnthropicSummarizeConfig extends AnthropicClientConfig {
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Anthropic-specific provider options for summarization
|
|
12
|
+
*/
|
|
13
|
+
export interface AnthropicSummarizeProviderOptions {
|
|
14
|
+
/** Temperature for response generation (0-1) */
|
|
15
|
+
temperature?: number;
|
|
16
|
+
/** Maximum tokens in the response */
|
|
17
|
+
maxTokens?: number;
|
|
18
|
+
}
|
|
19
|
+
/** Model type for Anthropic summarization */
|
|
20
|
+
export type AnthropicSummarizeModel = (typeof ANTHROPIC_MODELS)[number];
|
|
21
|
+
/**
|
|
22
|
+
* Anthropic Summarize Adapter
|
|
23
|
+
*
|
|
24
|
+
* Tree-shakeable adapter for Anthropic summarization functionality.
|
|
25
|
+
* Import only what you need for smaller bundle sizes.
|
|
26
|
+
*/
|
|
27
|
+
export declare class AnthropicSummarizeAdapter<TModel extends AnthropicSummarizeModel> extends BaseSummarizeAdapter<TModel, AnthropicSummarizeProviderOptions> {
|
|
28
|
+
readonly kind: "summarize";
|
|
29
|
+
readonly name: "anthropic";
|
|
30
|
+
private client;
|
|
31
|
+
constructor(config: AnthropicSummarizeConfig, model: TModel);
|
|
32
|
+
summarize(options: SummarizationOptions): Promise<SummarizationResult>;
|
|
33
|
+
summarizeStream(options: SummarizationOptions): AsyncIterable<StreamChunk>;
|
|
34
|
+
private buildSummarizationPrompt;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates an Anthropic summarize adapter with explicit API key.
|
|
38
|
+
* Type resolution happens here at the call site.
|
|
39
|
+
*
|
|
40
|
+
* @param model - The model name (e.g., 'claude-sonnet-4-5', 'claude-3-5-haiku-latest')
|
|
41
|
+
* @param apiKey - Your Anthropic API key
|
|
42
|
+
* @param config - Optional additional configuration
|
|
43
|
+
* @returns Configured Anthropic summarize adapter instance with resolved types
|
|
44
|
+
*/
|
|
45
|
+
export declare function createAnthropicSummarize<TModel extends AnthropicSummarizeModel>(model: TModel, apiKey: string, config?: Omit<AnthropicSummarizeConfig, 'apiKey'>): AnthropicSummarizeAdapter<TModel>;
|
|
46
|
+
/**
|
|
47
|
+
* Creates an Anthropic summarize adapter with automatic API key detection.
|
|
48
|
+
* Type resolution happens here at the call site.
|
|
49
|
+
*
|
|
50
|
+
* @param model - The model name (e.g., 'claude-sonnet-4-5', 'claude-3-5-haiku-latest')
|
|
51
|
+
* @param config - Optional configuration (excluding apiKey which is auto-detected)
|
|
52
|
+
* @returns Configured Anthropic summarize adapter instance with resolved types
|
|
53
|
+
*/
|
|
54
|
+
export declare function anthropicSummarize<TModel extends AnthropicSummarizeModel>(model: TModel, config?: Omit<AnthropicSummarizeConfig, 'apiKey'>): AnthropicSummarizeAdapter<TModel>;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { BaseSummarizeAdapter } from "@tanstack/ai/adapters";
|
|
2
|
+
import { createAnthropicClient, generateId, getAnthropicApiKeyFromEnv } from "../utils/client.js";
|
|
3
|
+
class AnthropicSummarizeAdapter extends BaseSummarizeAdapter {
|
|
4
|
+
constructor(config, model) {
|
|
5
|
+
super({}, model);
|
|
6
|
+
this.kind = "summarize";
|
|
7
|
+
this.name = "anthropic";
|
|
8
|
+
this.client = createAnthropicClient(config);
|
|
9
|
+
}
|
|
10
|
+
async summarize(options) {
|
|
11
|
+
const systemPrompt = this.buildSummarizationPrompt(options);
|
|
12
|
+
const response = await this.client.messages.create({
|
|
13
|
+
model: options.model,
|
|
14
|
+
messages: [{ role: "user", content: options.text }],
|
|
15
|
+
system: systemPrompt,
|
|
16
|
+
max_tokens: options.maxLength || 500,
|
|
17
|
+
temperature: 0.3,
|
|
18
|
+
stream: false
|
|
19
|
+
});
|
|
20
|
+
const content = response.content.map((c) => c.type === "text" ? c.text : "").join("");
|
|
21
|
+
return {
|
|
22
|
+
id: response.id,
|
|
23
|
+
model: response.model,
|
|
24
|
+
summary: content,
|
|
25
|
+
usage: {
|
|
26
|
+
promptTokens: response.usage.input_tokens,
|
|
27
|
+
completionTokens: response.usage.output_tokens,
|
|
28
|
+
totalTokens: response.usage.input_tokens + response.usage.output_tokens
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async *summarizeStream(options) {
|
|
33
|
+
const systemPrompt = this.buildSummarizationPrompt(options);
|
|
34
|
+
const id = generateId(this.name);
|
|
35
|
+
const model = options.model;
|
|
36
|
+
let accumulatedContent = "";
|
|
37
|
+
let inputTokens = 0;
|
|
38
|
+
let outputTokens = 0;
|
|
39
|
+
const stream = await this.client.messages.create({
|
|
40
|
+
model: options.model,
|
|
41
|
+
messages: [{ role: "user", content: options.text }],
|
|
42
|
+
system: systemPrompt,
|
|
43
|
+
max_tokens: options.maxLength || 500,
|
|
44
|
+
temperature: 0.3,
|
|
45
|
+
stream: true
|
|
46
|
+
});
|
|
47
|
+
for await (const event of stream) {
|
|
48
|
+
if (event.type === "message_start") {
|
|
49
|
+
inputTokens = event.message.usage.input_tokens;
|
|
50
|
+
} else if (event.type === "content_block_delta") {
|
|
51
|
+
if (event.delta.type === "text_delta") {
|
|
52
|
+
const delta = event.delta.text;
|
|
53
|
+
accumulatedContent += delta;
|
|
54
|
+
yield {
|
|
55
|
+
type: "content",
|
|
56
|
+
id,
|
|
57
|
+
model,
|
|
58
|
+
timestamp: Date.now(),
|
|
59
|
+
delta,
|
|
60
|
+
content: accumulatedContent,
|
|
61
|
+
role: "assistant"
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
} else if (event.type === "message_delta") {
|
|
65
|
+
outputTokens = event.usage.output_tokens;
|
|
66
|
+
yield {
|
|
67
|
+
type: "done",
|
|
68
|
+
id,
|
|
69
|
+
model,
|
|
70
|
+
timestamp: Date.now(),
|
|
71
|
+
finishReason: event.delta.stop_reason,
|
|
72
|
+
usage: {
|
|
73
|
+
promptTokens: inputTokens,
|
|
74
|
+
completionTokens: outputTokens,
|
|
75
|
+
totalTokens: inputTokens + outputTokens
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
buildSummarizationPrompt(options) {
|
|
82
|
+
let prompt = "You are a professional summarizer. ";
|
|
83
|
+
switch (options.style) {
|
|
84
|
+
case "bullet-points":
|
|
85
|
+
prompt += "Provide a summary in bullet point format. ";
|
|
86
|
+
break;
|
|
87
|
+
case "paragraph":
|
|
88
|
+
prompt += "Provide a summary in paragraph format. ";
|
|
89
|
+
break;
|
|
90
|
+
case "concise":
|
|
91
|
+
prompt += "Provide a very concise summary in 1-2 sentences. ";
|
|
92
|
+
break;
|
|
93
|
+
default:
|
|
94
|
+
prompt += "Provide a clear and concise summary. ";
|
|
95
|
+
}
|
|
96
|
+
if (options.focus && options.focus.length > 0) {
|
|
97
|
+
prompt += `Focus on the following aspects: ${options.focus.join(", ")}. `;
|
|
98
|
+
}
|
|
99
|
+
if (options.maxLength) {
|
|
100
|
+
prompt += `Keep the summary under ${options.maxLength} tokens. `;
|
|
101
|
+
}
|
|
102
|
+
return prompt;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function createAnthropicSummarize(model, apiKey, config) {
|
|
106
|
+
return new AnthropicSummarizeAdapter({ apiKey, ...config }, model);
|
|
107
|
+
}
|
|
108
|
+
function anthropicSummarize(model, config) {
|
|
109
|
+
const apiKey = getAnthropicApiKeyFromEnv();
|
|
110
|
+
return createAnthropicSummarize(model, apiKey, config);
|
|
111
|
+
}
|
|
112
|
+
export {
|
|
113
|
+
AnthropicSummarizeAdapter,
|
|
114
|
+
anthropicSummarize,
|
|
115
|
+
createAnthropicSummarize
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=summarize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summarize.js","sources":["../../../src/adapters/summarize.ts"],"sourcesContent":["import { BaseSummarizeAdapter } from '@tanstack/ai/adapters'\nimport {\n createAnthropicClient,\n generateId,\n getAnthropicApiKeyFromEnv,\n} from '../utils'\nimport type { ANTHROPIC_MODELS } from '../model-meta'\nimport type {\n StreamChunk,\n SummarizationOptions,\n SummarizationResult,\n} from '@tanstack/ai'\nimport type { AnthropicClientConfig } from '../utils'\n\n/**\n * Configuration for Anthropic summarize adapter\n */\nexport interface AnthropicSummarizeConfig extends AnthropicClientConfig {}\n\n/**\n * Anthropic-specific provider options for summarization\n */\nexport interface AnthropicSummarizeProviderOptions {\n /** Temperature for response generation (0-1) */\n temperature?: number\n /** Maximum tokens in the response */\n maxTokens?: number\n}\n\n/** Model type for Anthropic summarization */\nexport type AnthropicSummarizeModel = (typeof ANTHROPIC_MODELS)[number]\n\n/**\n * Anthropic Summarize Adapter\n *\n * Tree-shakeable adapter for Anthropic summarization functionality.\n * Import only what you need for smaller bundle sizes.\n */\nexport class AnthropicSummarizeAdapter<\n TModel extends AnthropicSummarizeModel,\n> extends BaseSummarizeAdapter<TModel, AnthropicSummarizeProviderOptions> {\n readonly kind = 'summarize' as const\n readonly name = 'anthropic' as const\n\n private client: ReturnType<typeof createAnthropicClient>\n\n constructor(config: AnthropicSummarizeConfig, model: TModel) {\n super({}, model)\n this.client = createAnthropicClient(config)\n }\n\n async summarize(options: SummarizationOptions): Promise<SummarizationResult> {\n const systemPrompt = this.buildSummarizationPrompt(options)\n\n const response = await this.client.messages.create({\n model: options.model,\n messages: [{ role: 'user', content: options.text }],\n system: systemPrompt,\n max_tokens: options.maxLength || 500,\n temperature: 0.3,\n stream: false,\n })\n\n const content = response.content\n .map((c) => (c.type === 'text' ? c.text : ''))\n .join('')\n\n return {\n id: response.id,\n model: response.model,\n summary: content,\n usage: {\n promptTokens: response.usage.input_tokens,\n completionTokens: response.usage.output_tokens,\n totalTokens: response.usage.input_tokens + response.usage.output_tokens,\n },\n }\n }\n\n async *summarizeStream(\n options: SummarizationOptions,\n ): AsyncIterable<StreamChunk> {\n const systemPrompt = this.buildSummarizationPrompt(options)\n const id = generateId(this.name)\n const model = options.model\n let accumulatedContent = ''\n let inputTokens = 0\n let outputTokens = 0\n\n const stream = await this.client.messages.create({\n model: options.model,\n messages: [{ role: 'user', content: options.text }],\n system: systemPrompt,\n max_tokens: options.maxLength || 500,\n temperature: 0.3,\n stream: true,\n })\n\n for await (const event of stream) {\n if (event.type === 'message_start') {\n inputTokens = event.message.usage.input_tokens\n } else if (event.type === 'content_block_delta') {\n if (event.delta.type === 'text_delta') {\n const delta = event.delta.text\n accumulatedContent += delta\n yield {\n type: 'content',\n id,\n model,\n timestamp: Date.now(),\n delta,\n content: accumulatedContent,\n role: 'assistant',\n }\n }\n } else if (event.type === 'message_delta') {\n outputTokens = event.usage.output_tokens\n yield {\n type: 'done',\n id,\n model,\n timestamp: Date.now(),\n finishReason: event.delta.stop_reason as\n | 'stop'\n | 'length'\n | 'content_filter'\n | null,\n usage: {\n promptTokens: inputTokens,\n completionTokens: outputTokens,\n totalTokens: inputTokens + outputTokens,\n },\n }\n }\n }\n }\n\n private buildSummarizationPrompt(options: SummarizationOptions): string {\n let prompt = 'You are a professional summarizer. '\n\n switch (options.style) {\n case 'bullet-points':\n prompt += 'Provide a summary in bullet point format. '\n break\n case 'paragraph':\n prompt += 'Provide a summary in paragraph format. '\n break\n case 'concise':\n prompt += 'Provide a very concise summary in 1-2 sentences. '\n break\n default:\n prompt += 'Provide a clear and concise summary. '\n }\n\n if (options.focus && options.focus.length > 0) {\n prompt += `Focus on the following aspects: ${options.focus.join(', ')}. `\n }\n\n if (options.maxLength) {\n prompt += `Keep the summary under ${options.maxLength} tokens. `\n }\n\n return prompt\n }\n}\n\n/**\n * Creates an Anthropic summarize adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'claude-sonnet-4-5', 'claude-3-5-haiku-latest')\n * @param apiKey - Your Anthropic API key\n * @param config - Optional additional configuration\n * @returns Configured Anthropic summarize adapter instance with resolved types\n */\nexport function createAnthropicSummarize<\n TModel extends AnthropicSummarizeModel,\n>(\n model: TModel,\n apiKey: string,\n config?: Omit<AnthropicSummarizeConfig, 'apiKey'>,\n): AnthropicSummarizeAdapter<TModel> {\n return new AnthropicSummarizeAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates an Anthropic summarize adapter with automatic API key detection.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'claude-sonnet-4-5', 'claude-3-5-haiku-latest')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Anthropic summarize adapter instance with resolved types\n */\nexport function anthropicSummarize<TModel extends AnthropicSummarizeModel>(\n model: TModel,\n config?: Omit<AnthropicSummarizeConfig, 'apiKey'>,\n): AnthropicSummarizeAdapter<TModel> {\n const apiKey = getAnthropicApiKeyFromEnv()\n return createAnthropicSummarize(model, apiKey, config)\n}\n"],"names":[],"mappings":";;AAsCO,MAAM,kCAEH,qBAAgE;AAAA,EAMxE,YAAY,QAAkC,OAAe;AAC3D,UAAM,CAAA,GAAI,KAAK;AANjB,SAAS,OAAO;AAChB,SAAS,OAAO;AAMd,SAAK,SAAS,sBAAsB,MAAM;AAAA,EAC5C;AAAA,EAEA,MAAM,UAAU,SAA6D;AAC3E,UAAM,eAAe,KAAK,yBAAyB,OAAO;AAE1D,UAAM,WAAW,MAAM,KAAK,OAAO,SAAS,OAAO;AAAA,MACjD,OAAO,QAAQ;AAAA,MACf,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,QAAQ,MAAM;AAAA,MAClD,QAAQ;AAAA,MACR,YAAY,QAAQ,aAAa;AAAA,MACjC,aAAa;AAAA,MACb,QAAQ;AAAA,IAAA,CACT;AAED,UAAM,UAAU,SAAS,QACtB,IAAI,CAAC,MAAO,EAAE,SAAS,SAAS,EAAE,OAAO,EAAG,EAC5C,KAAK,EAAE;AAEV,WAAO;AAAA,MACL,IAAI,SAAS;AAAA,MACb,OAAO,SAAS;AAAA,MAChB,SAAS;AAAA,MACT,OAAO;AAAA,QACL,cAAc,SAAS,MAAM;AAAA,QAC7B,kBAAkB,SAAS,MAAM;AAAA,QACjC,aAAa,SAAS,MAAM,eAAe,SAAS,MAAM;AAAA,MAAA;AAAA,IAC5D;AAAA,EAEJ;AAAA,EAEA,OAAO,gBACL,SAC4B;AAC5B,UAAM,eAAe,KAAK,yBAAyB,OAAO;AAC1D,UAAM,KAAK,WAAW,KAAK,IAAI;AAC/B,UAAM,QAAQ,QAAQ;AACtB,QAAI,qBAAqB;AACzB,QAAI,cAAc;AAClB,QAAI,eAAe;AAEnB,UAAM,SAAS,MAAM,KAAK,OAAO,SAAS,OAAO;AAAA,MAC/C,OAAO,QAAQ;AAAA,MACf,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,QAAQ,MAAM;AAAA,MAClD,QAAQ;AAAA,MACR,YAAY,QAAQ,aAAa;AAAA,MACjC,aAAa;AAAA,MACb,QAAQ;AAAA,IAAA,CACT;AAED,qBAAiB,SAAS,QAAQ;AAChC,UAAI,MAAM,SAAS,iBAAiB;AAClC,sBAAc,MAAM,QAAQ,MAAM;AAAA,MACpC,WAAW,MAAM,SAAS,uBAAuB;AAC/C,YAAI,MAAM,MAAM,SAAS,cAAc;AACrC,gBAAM,QAAQ,MAAM,MAAM;AAC1B,gCAAsB;AACtB,gBAAM;AAAA,YACJ,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA,WAAW,KAAK,IAAA;AAAA,YAChB;AAAA,YACA,SAAS;AAAA,YACT,MAAM;AAAA,UAAA;AAAA,QAEV;AAAA,MACF,WAAW,MAAM,SAAS,iBAAiB;AACzC,uBAAe,MAAM,MAAM;AAC3B,cAAM;AAAA,UACJ,MAAM;AAAA,UACN;AAAA,UACA;AAAA,UACA,WAAW,KAAK,IAAA;AAAA,UAChB,cAAc,MAAM,MAAM;AAAA,UAK1B,OAAO;AAAA,YACL,cAAc;AAAA,YACd,kBAAkB;AAAA,YAClB,aAAa,cAAc;AAAA,UAAA;AAAA,QAC7B;AAAA,MAEJ;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,yBAAyB,SAAuC;AACtE,QAAI,SAAS;AAEb,YAAQ,QAAQ,OAAA;AAAA,MACd,KAAK;AACH,kBAAU;AACV;AAAA,MACF,KAAK;AACH,kBAAU;AACV;AAAA,MACF,KAAK;AACH,kBAAU;AACV;AAAA,MACF;AACE,kBAAU;AAAA,IAAA;AAGd,QAAI,QAAQ,SAAS,QAAQ,MAAM,SAAS,GAAG;AAC7C,gBAAU,mCAAmC,QAAQ,MAAM,KAAK,IAAI,CAAC;AAAA,IACvE;AAEA,QAAI,QAAQ,WAAW;AACrB,gBAAU,0BAA0B,QAAQ,SAAS;AAAA,IACvD;AAEA,WAAO;AAAA,EACT;AACF;AAWO,SAAS,yBAGd,OACA,QACA,QACmC;AACnC,SAAO,IAAI,0BAA0B,EAAE,QAAQ,GAAG,OAAA,GAAU,KAAK;AACnE;AAUO,SAAS,mBACd,OACA,QACmC;AACnC,QAAM,SAAS,0BAAA;AACf,SAAO,yBAAyB,OAAO,QAAQ,MAAM;AACvD;"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { BaseTextAdapter, StructuredOutputOptions, StructuredOutputResult } from '@tanstack/ai/adapters';
|
|
2
|
+
import { ANTHROPIC_MODELS, AnthropicChatModelProviderOptionsByName, AnthropicModelInputModalitiesByName } from '../model-meta.js';
|
|
3
|
+
import { Modality, StreamChunk, TextOptions } from '@tanstack/ai';
|
|
4
|
+
import { ExternalTextProviderOptions } from '../text/text-provider-options.js';
|
|
5
|
+
import { AnthropicMessageMetadataByModality } from '../message-types.js';
|
|
6
|
+
import { AnthropicClientConfig } from '../utils.js';
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for Anthropic text adapter
|
|
9
|
+
*/
|
|
10
|
+
export interface AnthropicTextConfig extends AnthropicClientConfig {
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Anthropic-specific provider options for text/chat
|
|
14
|
+
*/
|
|
15
|
+
export type AnthropicTextProviderOptions = ExternalTextProviderOptions;
|
|
16
|
+
/**
|
|
17
|
+
* Resolve provider options for a specific model.
|
|
18
|
+
* If the model has explicit options in the map, use those; otherwise use base options.
|
|
19
|
+
*/
|
|
20
|
+
type ResolveProviderOptions<TModel extends string> = TModel extends keyof AnthropicChatModelProviderOptionsByName ? AnthropicChatModelProviderOptionsByName[TModel] : AnthropicTextProviderOptions;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve input modalities for a specific model.
|
|
23
|
+
* If the model has explicit modalities in the map, use those; otherwise use default.
|
|
24
|
+
*/
|
|
25
|
+
type ResolveInputModalities<TModel extends string> = TModel extends keyof AnthropicModelInputModalitiesByName ? AnthropicModelInputModalitiesByName[TModel] : readonly ['text', 'image', 'document'];
|
|
26
|
+
/**
|
|
27
|
+
* Anthropic Text (Chat) Adapter
|
|
28
|
+
*
|
|
29
|
+
* Tree-shakeable adapter for Anthropic chat/text completion functionality.
|
|
30
|
+
* Import only what you need for smaller bundle sizes.
|
|
31
|
+
*/
|
|
32
|
+
export declare class AnthropicTextAdapter<TModel extends (typeof ANTHROPIC_MODELS)[number], TProviderOptions extends object = ResolveProviderOptions<TModel>, TInputModalities extends ReadonlyArray<Modality> = ResolveInputModalities<TModel>> extends BaseTextAdapter<TModel, TProviderOptions, TInputModalities, AnthropicMessageMetadataByModality> {
|
|
33
|
+
readonly kind: "text";
|
|
34
|
+
readonly name: "anthropic";
|
|
35
|
+
private client;
|
|
36
|
+
constructor(config: AnthropicTextConfig, model: TModel);
|
|
37
|
+
chatStream(options: TextOptions<AnthropicTextProviderOptions>): AsyncIterable<StreamChunk>;
|
|
38
|
+
/**
|
|
39
|
+
* Generate structured output using Anthropic's tool-based approach.
|
|
40
|
+
* Anthropic doesn't have native structured output, so we use a tool with the schema
|
|
41
|
+
* and force the model to call it.
|
|
42
|
+
* The outputSchema is already JSON Schema (converted in the ai layer).
|
|
43
|
+
*/
|
|
44
|
+
structuredOutput(options: StructuredOutputOptions<AnthropicTextProviderOptions>): Promise<StructuredOutputResult<unknown>>;
|
|
45
|
+
private mapCommonOptionsToAnthropic;
|
|
46
|
+
private convertContentPartToAnthropic;
|
|
47
|
+
private formatMessages;
|
|
48
|
+
private processAnthropicStream;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Creates an Anthropic chat adapter with explicit API key.
|
|
52
|
+
* Type resolution happens here at the call site.
|
|
53
|
+
*/
|
|
54
|
+
export declare function createAnthropicChat<TModel extends (typeof ANTHROPIC_MODELS)[number]>(model: TModel, apiKey: string, config?: Omit<AnthropicTextConfig, 'apiKey'>): AnthropicTextAdapter<TModel, ResolveProviderOptions<TModel>, ResolveInputModalities<TModel>>;
|
|
55
|
+
/**
|
|
56
|
+
* Creates an Anthropic text adapter with automatic API key detection.
|
|
57
|
+
* Type resolution happens here at the call site.
|
|
58
|
+
*/
|
|
59
|
+
export declare function anthropicText<TModel extends (typeof ANTHROPIC_MODELS)[number]>(model: TModel, config?: Omit<AnthropicTextConfig, 'apiKey'>): AnthropicTextAdapter<TModel, ResolveProviderOptions<TModel>, ResolveInputModalities<TModel>>;
|
|
60
|
+
export {};
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { BaseTextAdapter } from "@tanstack/ai/adapters";
|
|
2
|
+
import { convertToolsToProviderFormat } from "../tools/tool-converter.js";
|
|
3
|
+
import { validateTextProviderOptions } from "../text/text-provider-options.js";
|
|
4
|
+
import { createAnthropicClient, generateId, getAnthropicApiKeyFromEnv } from "../utils/client.js";
|
|
5
|
+
class AnthropicTextAdapter extends BaseTextAdapter {
|
|
6
|
+
constructor(config, model) {
|
|
7
|
+
super({}, model);
|
|
8
|
+
this.kind = "text";
|
|
9
9
|
this.name = "anthropic";
|
|
10
|
-
this.
|
|
11
|
-
this.client = new Anthropic_SDK({
|
|
12
|
-
apiKey: config.apiKey
|
|
13
|
-
});
|
|
10
|
+
this.client = createAnthropicClient(config);
|
|
14
11
|
}
|
|
15
12
|
async *chatStream(options) {
|
|
16
13
|
try {
|
|
@@ -25,90 +22,94 @@ class Anthropic extends BaseAdapter {
|
|
|
25
22
|
yield* this.processAnthropicStream(
|
|
26
23
|
stream,
|
|
27
24
|
options.model,
|
|
28
|
-
() => this.
|
|
25
|
+
() => generateId(this.name)
|
|
29
26
|
);
|
|
30
27
|
} catch (error) {
|
|
31
|
-
|
|
32
|
-
message: error?.message,
|
|
33
|
-
status: error?.status,
|
|
34
|
-
statusText: error?.statusText,
|
|
35
|
-
code: error?.code,
|
|
36
|
-
type: error?.type,
|
|
37
|
-
error,
|
|
38
|
-
stack: error?.stack
|
|
39
|
-
});
|
|
28
|
+
const err = error;
|
|
40
29
|
yield {
|
|
41
30
|
type: "error",
|
|
42
|
-
id: this.
|
|
31
|
+
id: generateId(this.name),
|
|
43
32
|
model: options.model,
|
|
44
33
|
timestamp: Date.now(),
|
|
45
34
|
error: {
|
|
46
|
-
message:
|
|
47
|
-
code:
|
|
35
|
+
message: err.message || "Unknown error occurred",
|
|
36
|
+
code: err.code || String(err.status)
|
|
48
37
|
}
|
|
49
38
|
};
|
|
50
39
|
}
|
|
51
40
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
promptTokens: response.usage.input_tokens,
|
|
69
|
-
completionTokens: response.usage.output_tokens,
|
|
70
|
-
totalTokens: response.usage.input_tokens + response.usage.output_tokens
|
|
41
|
+
/**
|
|
42
|
+
* Generate structured output using Anthropic's tool-based approach.
|
|
43
|
+
* Anthropic doesn't have native structured output, so we use a tool with the schema
|
|
44
|
+
* and force the model to call it.
|
|
45
|
+
* The outputSchema is already JSON Schema (converted in the ai layer).
|
|
46
|
+
*/
|
|
47
|
+
async structuredOutput(options) {
|
|
48
|
+
const { chatOptions, outputSchema } = options;
|
|
49
|
+
const requestParams = this.mapCommonOptionsToAnthropic(chatOptions);
|
|
50
|
+
const structuredOutputTool = {
|
|
51
|
+
name: "structured_output",
|
|
52
|
+
description: "Use this tool to provide your response in the required structured format.",
|
|
53
|
+
input_schema: {
|
|
54
|
+
type: "object",
|
|
55
|
+
properties: outputSchema.properties ?? {},
|
|
56
|
+
required: outputSchema.required ?? []
|
|
71
57
|
}
|
|
72
58
|
};
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
59
|
+
try {
|
|
60
|
+
const response = await this.client.messages.create(
|
|
61
|
+
{
|
|
62
|
+
...requestParams,
|
|
63
|
+
stream: false,
|
|
64
|
+
tools: [structuredOutputTool],
|
|
65
|
+
tool_choice: { type: "tool", name: "structured_output" }
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
signal: chatOptions.request?.signal,
|
|
69
|
+
headers: chatOptions.request?.headers
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
let parsed = null;
|
|
73
|
+
let rawText = "";
|
|
74
|
+
for (const block of response.content) {
|
|
75
|
+
if (block.type === "tool_use" && block.name === "structured_output") {
|
|
76
|
+
parsed = block.input;
|
|
77
|
+
rawText = JSON.stringify(block.input);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (parsed === null) {
|
|
82
|
+
rawText = response.content.map((b) => {
|
|
83
|
+
if (b.type === "text") {
|
|
84
|
+
return b.text;
|
|
85
|
+
}
|
|
86
|
+
return "";
|
|
87
|
+
}).join("");
|
|
88
|
+
try {
|
|
89
|
+
parsed = JSON.parse(rawText);
|
|
90
|
+
} catch {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Failed to extract structured output from response. Content: ${rawText.slice(0, 200)}${rawText.length > 200 ? "..." : ""}`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
data: parsed,
|
|
98
|
+
rawText
|
|
99
|
+
};
|
|
100
|
+
} catch (error) {
|
|
101
|
+
const err = error;
|
|
102
|
+
throw new Error(
|
|
103
|
+
`Structured output generation failed: ${err.message || "Unknown error occurred"}`
|
|
104
|
+
);
|
|
99
105
|
}
|
|
100
|
-
return prompt;
|
|
101
106
|
}
|
|
102
|
-
/**
|
|
103
|
-
* Maps common options to Anthropic-specific format
|
|
104
|
-
* Handles translation of normalized options to Anthropic's API format
|
|
105
|
-
*/
|
|
106
107
|
mapCommonOptionsToAnthropic(options) {
|
|
107
|
-
const
|
|
108
|
+
const modelOptions = options.modelOptions;
|
|
108
109
|
const formattedMessages = this.formatMessages(options.messages);
|
|
109
110
|
const tools = options.tools ? convertToolsToProviderFormat(options.tools) : void 0;
|
|
110
111
|
const validProviderOptions = {};
|
|
111
|
-
if (
|
|
112
|
+
if (modelOptions) {
|
|
112
113
|
const validKeys = [
|
|
113
114
|
"container",
|
|
114
115
|
"context_management",
|
|
@@ -121,10 +122,12 @@ class Anthropic extends BaseAdapter {
|
|
|
121
122
|
"top_k"
|
|
122
123
|
];
|
|
123
124
|
for (const key of validKeys) {
|
|
124
|
-
if (key in
|
|
125
|
-
const value =
|
|
125
|
+
if (key in modelOptions) {
|
|
126
|
+
const value = modelOptions[key];
|
|
126
127
|
if (key === "tool_choice" && typeof value === "string") {
|
|
127
|
-
validProviderOptions[key] = {
|
|
128
|
+
validProviderOptions[key] = {
|
|
129
|
+
type: value
|
|
130
|
+
};
|
|
128
131
|
} else {
|
|
129
132
|
validProviderOptions[key] = value;
|
|
130
133
|
}
|
|
@@ -132,13 +135,13 @@ class Anthropic extends BaseAdapter {
|
|
|
132
135
|
}
|
|
133
136
|
}
|
|
134
137
|
const thinkingBudget = validProviderOptions.thinking?.type === "enabled" ? validProviderOptions.thinking.budget_tokens : void 0;
|
|
135
|
-
const defaultMaxTokens = options.
|
|
138
|
+
const defaultMaxTokens = options.maxTokens || 1024;
|
|
136
139
|
const maxTokens = thinkingBudget && thinkingBudget >= defaultMaxTokens ? thinkingBudget + 1 : defaultMaxTokens;
|
|
137
140
|
const requestParams = {
|
|
138
141
|
model: options.model,
|
|
139
142
|
max_tokens: maxTokens,
|
|
140
|
-
temperature: options.
|
|
141
|
-
top_p: options.
|
|
143
|
+
temperature: options.temperature,
|
|
144
|
+
top_p: options.topP,
|
|
142
145
|
messages: formattedMessages,
|
|
143
146
|
system: options.systemPrompts?.join("\n"),
|
|
144
147
|
tools,
|
|
@@ -167,7 +170,7 @@ class Anthropic extends BaseAdapter {
|
|
|
167
170
|
type: "url",
|
|
168
171
|
url: part.source.value
|
|
169
172
|
};
|
|
170
|
-
const { mediaType, ...meta } = metadata || {};
|
|
173
|
+
const { mediaType: _mediaType, ...meta } = metadata || {};
|
|
171
174
|
return {
|
|
172
175
|
type: "image",
|
|
173
176
|
source: imageSource,
|
|
@@ -270,7 +273,7 @@ class Anthropic extends BaseAdapter {
|
|
|
270
273
|
}
|
|
271
274
|
return formattedMessages;
|
|
272
275
|
}
|
|
273
|
-
async *processAnthropicStream(stream, model,
|
|
276
|
+
async *processAnthropicStream(stream, model, genId) {
|
|
274
277
|
let accumulatedContent = "";
|
|
275
278
|
let accumulatedThinking = "";
|
|
276
279
|
const timestamp = Date.now();
|
|
@@ -295,7 +298,7 @@ class Anthropic extends BaseAdapter {
|
|
|
295
298
|
accumulatedContent += delta;
|
|
296
299
|
yield {
|
|
297
300
|
type: "content",
|
|
298
|
-
id:
|
|
301
|
+
id: genId(),
|
|
299
302
|
model,
|
|
300
303
|
timestamp,
|
|
301
304
|
delta,
|
|
@@ -307,7 +310,7 @@ class Anthropic extends BaseAdapter {
|
|
|
307
310
|
accumulatedThinking += delta;
|
|
308
311
|
yield {
|
|
309
312
|
type: "thinking",
|
|
310
|
-
id:
|
|
313
|
+
id: genId(),
|
|
311
314
|
model,
|
|
312
315
|
timestamp,
|
|
313
316
|
delta,
|
|
@@ -319,7 +322,7 @@ class Anthropic extends BaseAdapter {
|
|
|
319
322
|
existing.input += event.delta.partial_json;
|
|
320
323
|
yield {
|
|
321
324
|
type: "tool_call",
|
|
322
|
-
id:
|
|
325
|
+
id: genId(),
|
|
323
326
|
model,
|
|
324
327
|
timestamp,
|
|
325
328
|
toolCall: {
|
|
@@ -339,7 +342,7 @@ class Anthropic extends BaseAdapter {
|
|
|
339
342
|
if (existing && existing.input === "") {
|
|
340
343
|
yield {
|
|
341
344
|
type: "tool_call",
|
|
342
|
-
id:
|
|
345
|
+
id: genId(),
|
|
343
346
|
model,
|
|
344
347
|
timestamp,
|
|
345
348
|
toolCall: {
|
|
@@ -356,7 +359,7 @@ class Anthropic extends BaseAdapter {
|
|
|
356
359
|
} else if (event.type === "message_stop") {
|
|
357
360
|
yield {
|
|
358
361
|
type: "done",
|
|
359
|
-
id:
|
|
362
|
+
id: genId(),
|
|
360
363
|
model,
|
|
361
364
|
timestamp,
|
|
362
365
|
finishReason: "stop"
|
|
@@ -367,7 +370,7 @@ class Anthropic extends BaseAdapter {
|
|
|
367
370
|
case "tool_use": {
|
|
368
371
|
yield {
|
|
369
372
|
type: "done",
|
|
370
|
-
id:
|
|
373
|
+
id: genId(),
|
|
371
374
|
model,
|
|
372
375
|
timestamp,
|
|
373
376
|
finishReason: "tool_calls",
|
|
@@ -382,7 +385,7 @@ class Anthropic extends BaseAdapter {
|
|
|
382
385
|
case "max_tokens": {
|
|
383
386
|
yield {
|
|
384
387
|
type: "error",
|
|
385
|
-
id:
|
|
388
|
+
id: genId(),
|
|
386
389
|
model,
|
|
387
390
|
timestamp,
|
|
388
391
|
error: {
|
|
@@ -392,36 +395,10 @@ class Anthropic extends BaseAdapter {
|
|
|
392
395
|
};
|
|
393
396
|
break;
|
|
394
397
|
}
|
|
395
|
-
case "model_context_window_exceeded": {
|
|
396
|
-
yield {
|
|
397
|
-
type: "error",
|
|
398
|
-
id: generateId(),
|
|
399
|
-
model,
|
|
400
|
-
timestamp,
|
|
401
|
-
error: {
|
|
402
|
-
message: "The response was cut off because the model's context window was exceeded.",
|
|
403
|
-
code: "context_window_exceeded"
|
|
404
|
-
}
|
|
405
|
-
};
|
|
406
|
-
break;
|
|
407
|
-
}
|
|
408
|
-
case "refusal": {
|
|
409
|
-
yield {
|
|
410
|
-
type: "error",
|
|
411
|
-
id: generateId(),
|
|
412
|
-
model,
|
|
413
|
-
timestamp,
|
|
414
|
-
error: {
|
|
415
|
-
message: "The model refused to complete the request.",
|
|
416
|
-
code: "refusal"
|
|
417
|
-
}
|
|
418
|
-
};
|
|
419
|
-
break;
|
|
420
|
-
}
|
|
421
398
|
default: {
|
|
422
399
|
yield {
|
|
423
400
|
type: "done",
|
|
424
|
-
id:
|
|
401
|
+
id: genId(),
|
|
425
402
|
model,
|
|
426
403
|
timestamp,
|
|
427
404
|
finishReason: "stop",
|
|
@@ -437,44 +414,30 @@ class Anthropic extends BaseAdapter {
|
|
|
437
414
|
}
|
|
438
415
|
}
|
|
439
416
|
} catch (error) {
|
|
440
|
-
|
|
441
|
-
message: error?.message,
|
|
442
|
-
status: error?.status,
|
|
443
|
-
statusText: error?.statusText,
|
|
444
|
-
code: error?.code,
|
|
445
|
-
type: error?.type,
|
|
446
|
-
error,
|
|
447
|
-
stack: error?.stack
|
|
448
|
-
});
|
|
417
|
+
const err = error;
|
|
449
418
|
yield {
|
|
450
419
|
type: "error",
|
|
451
|
-
id:
|
|
420
|
+
id: genId(),
|
|
452
421
|
model,
|
|
453
422
|
timestamp,
|
|
454
423
|
error: {
|
|
455
|
-
message:
|
|
456
|
-
code:
|
|
424
|
+
message: err.message || "Unknown error occurred",
|
|
425
|
+
code: err.code || String(err.status)
|
|
457
426
|
}
|
|
458
427
|
};
|
|
459
428
|
}
|
|
460
429
|
}
|
|
461
430
|
}
|
|
462
|
-
function
|
|
463
|
-
return new
|
|
431
|
+
function createAnthropicChat(model, apiKey, config) {
|
|
432
|
+
return new AnthropicTextAdapter({ apiKey, ...config }, model);
|
|
464
433
|
}
|
|
465
|
-
function
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
if (!key) {
|
|
469
|
-
throw new Error(
|
|
470
|
-
"ANTHROPIC_API_KEY is required. Please set it in your environment variables or use createAnthropic(apiKey, config) instead."
|
|
471
|
-
);
|
|
472
|
-
}
|
|
473
|
-
return createAnthropic(key, config);
|
|
434
|
+
function anthropicText(model, config) {
|
|
435
|
+
const apiKey = getAnthropicApiKeyFromEnv();
|
|
436
|
+
return createAnthropicChat(model, apiKey, config);
|
|
474
437
|
}
|
|
475
438
|
export {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
439
|
+
AnthropicTextAdapter,
|
|
440
|
+
anthropicText,
|
|
441
|
+
createAnthropicChat
|
|
479
442
|
};
|
|
480
|
-
//# sourceMappingURL=
|
|
443
|
+
//# sourceMappingURL=text.js.map
|