@tanstack/ai-anthropic 0.8.0 → 0.8.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.
|
@@ -9,73 +9,103 @@ class AnthropicSummarizeAdapter extends BaseSummarizeAdapter {
|
|
|
9
9
|
this.client = createAnthropicClient(config);
|
|
10
10
|
}
|
|
11
11
|
async summarize(options) {
|
|
12
|
+
const { logger } = options;
|
|
12
13
|
const systemPrompt = this.buildSummarizationPrompt(options);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
system: systemPrompt,
|
|
17
|
-
max_tokens: options.maxLength || 500,
|
|
18
|
-
temperature: 0.3,
|
|
19
|
-
stream: false
|
|
14
|
+
logger.request(`activity=summarize provider=anthropic`, {
|
|
15
|
+
provider: "anthropic",
|
|
16
|
+
model: options.model
|
|
20
17
|
});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
18
|
+
try {
|
|
19
|
+
const response = await this.client.messages.create({
|
|
20
|
+
model: options.model,
|
|
21
|
+
messages: [{ role: "user", content: options.text }],
|
|
22
|
+
system: systemPrompt,
|
|
23
|
+
max_tokens: options.maxLength || 500,
|
|
24
|
+
temperature: 0.3,
|
|
25
|
+
stream: false
|
|
26
|
+
});
|
|
27
|
+
const content = response.content.map((c) => c.type === "text" ? c.text : "").join("");
|
|
28
|
+
return {
|
|
29
|
+
id: response.id,
|
|
30
|
+
model: response.model,
|
|
31
|
+
summary: content,
|
|
32
|
+
usage: {
|
|
33
|
+
promptTokens: response.usage.input_tokens,
|
|
34
|
+
completionTokens: response.usage.output_tokens,
|
|
35
|
+
totalTokens: response.usage.input_tokens + response.usage.output_tokens
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
} catch (error) {
|
|
39
|
+
logger.errors("anthropic.summarize fatal", {
|
|
40
|
+
error,
|
|
41
|
+
source: "anthropic.summarize"
|
|
42
|
+
});
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
32
45
|
}
|
|
33
46
|
async *summarizeStream(options) {
|
|
47
|
+
const { logger } = options;
|
|
34
48
|
const systemPrompt = this.buildSummarizationPrompt(options);
|
|
35
49
|
const id = generateId(this.name);
|
|
36
50
|
const model = options.model;
|
|
37
51
|
let accumulatedContent = "";
|
|
38
52
|
let inputTokens = 0;
|
|
39
53
|
let outputTokens = 0;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
system: systemPrompt,
|
|
44
|
-
max_tokens: options.maxLength || 500,
|
|
45
|
-
temperature: 0.3,
|
|
54
|
+
logger.request(`activity=summarize provider=anthropic`, {
|
|
55
|
+
provider: "anthropic",
|
|
56
|
+
model,
|
|
46
57
|
stream: true
|
|
47
58
|
});
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
59
|
+
try {
|
|
60
|
+
const stream = await this.client.messages.create({
|
|
61
|
+
model: options.model,
|
|
62
|
+
messages: [{ role: "user", content: options.text }],
|
|
63
|
+
system: systemPrompt,
|
|
64
|
+
max_tokens: options.maxLength || 500,
|
|
65
|
+
temperature: 0.3,
|
|
66
|
+
stream: true
|
|
67
|
+
});
|
|
68
|
+
for await (const event of stream) {
|
|
69
|
+
logger.provider(`provider=anthropic type=${event.type}`, {
|
|
70
|
+
chunk: event
|
|
71
|
+
});
|
|
72
|
+
if (event.type === "message_start") {
|
|
73
|
+
inputTokens = event.message.usage.input_tokens;
|
|
74
|
+
} else if (event.type === "content_block_delta") {
|
|
75
|
+
if (event.delta.type === "text_delta") {
|
|
76
|
+
const delta = event.delta.text;
|
|
77
|
+
accumulatedContent += delta;
|
|
78
|
+
yield asChunk({
|
|
79
|
+
type: "TEXT_MESSAGE_CONTENT",
|
|
80
|
+
messageId: id,
|
|
81
|
+
model,
|
|
82
|
+
timestamp: Date.now(),
|
|
83
|
+
delta,
|
|
84
|
+
content: accumulatedContent
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
} else if (event.type === "message_delta") {
|
|
88
|
+
outputTokens = event.usage.output_tokens;
|
|
55
89
|
yield asChunk({
|
|
56
|
-
type: "
|
|
57
|
-
|
|
90
|
+
type: "RUN_FINISHED",
|
|
91
|
+
runId: id,
|
|
58
92
|
model,
|
|
59
93
|
timestamp: Date.now(),
|
|
60
|
-
delta,
|
|
61
|
-
|
|
94
|
+
finishReason: event.delta.stop_reason,
|
|
95
|
+
usage: {
|
|
96
|
+
promptTokens: inputTokens,
|
|
97
|
+
completionTokens: outputTokens,
|
|
98
|
+
totalTokens: inputTokens + outputTokens
|
|
99
|
+
}
|
|
62
100
|
});
|
|
63
101
|
}
|
|
64
|
-
} else if (event.type === "message_delta") {
|
|
65
|
-
outputTokens = event.usage.output_tokens;
|
|
66
|
-
yield asChunk({
|
|
67
|
-
type: "RUN_FINISHED",
|
|
68
|
-
runId: 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
102
|
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
logger.errors("anthropic.summarize fatal", {
|
|
105
|
+
error,
|
|
106
|
+
source: "anthropic.summarize"
|
|
107
|
+
});
|
|
108
|
+
throw error;
|
|
79
109
|
}
|
|
80
110
|
}
|
|
81
111
|
buildSummarizationPrompt(options) {
|
|
@@ -1 +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/** Cast an event object to StreamChunk. */\nconst asChunk = (chunk: Record<string, unknown>) =>\n chunk as unknown as StreamChunk\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 asChunk({\n type: 'TEXT_MESSAGE_CONTENT',\n messageId: id,\n model,\n timestamp: Date.now(),\n delta,\n content: accumulatedContent,\n })\n }\n } else if (event.type === 'message_delta') {\n outputTokens = event.usage.output_tokens\n yield asChunk({\n type: 'RUN_FINISHED',\n runId: 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":"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"}
|
|
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/** Cast an event object to StreamChunk. */\nconst asChunk = (chunk: Record<string, unknown>) =>\n chunk as unknown as StreamChunk\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 { logger } = options\n const systemPrompt = this.buildSummarizationPrompt(options)\n\n logger.request(`activity=summarize provider=anthropic`, {\n provider: 'anthropic',\n model: options.model,\n })\n\n try {\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:\n response.usage.input_tokens + response.usage.output_tokens,\n },\n }\n } catch (error) {\n logger.errors('anthropic.summarize fatal', {\n error,\n source: 'anthropic.summarize',\n })\n throw error\n }\n }\n\n async *summarizeStream(\n options: SummarizationOptions,\n ): AsyncIterable<StreamChunk> {\n const { logger } = options\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 logger.request(`activity=summarize provider=anthropic`, {\n provider: 'anthropic',\n model,\n stream: true,\n })\n\n try {\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 logger.provider(`provider=anthropic type=${event.type}`, {\n chunk: event,\n })\n\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 asChunk({\n type: 'TEXT_MESSAGE_CONTENT',\n messageId: id,\n model,\n timestamp: Date.now(),\n delta,\n content: accumulatedContent,\n })\n }\n } else if (event.type === 'message_delta') {\n outputTokens = event.usage.output_tokens\n yield asChunk({\n type: 'RUN_FINISHED',\n runId: 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 } catch (error) {\n logger.errors('anthropic.summarize fatal', {\n error,\n source: 'anthropic.summarize',\n })\n throw error\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":"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"}
|
|
@@ -11,8 +11,13 @@ class AnthropicTextAdapter extends BaseTextAdapter {
|
|
|
11
11
|
this.client = createAnthropicClient(config);
|
|
12
12
|
}
|
|
13
13
|
async *chatStream(options) {
|
|
14
|
+
const { logger } = options;
|
|
14
15
|
try {
|
|
15
16
|
const requestParams = this.mapCommonOptionsToAnthropic(options);
|
|
17
|
+
logger.request(
|
|
18
|
+
`activity=chat provider=anthropic model=${this.model} messages=${options.messages.length} tools=${options.tools?.length ?? 0} stream=true`,
|
|
19
|
+
{ provider: "anthropic", model: this.model }
|
|
20
|
+
);
|
|
16
21
|
const stream = await this.client.beta.messages.create(
|
|
17
22
|
{ ...requestParams, stream: true },
|
|
18
23
|
{
|
|
@@ -23,10 +28,15 @@ class AnthropicTextAdapter extends BaseTextAdapter {
|
|
|
23
28
|
yield* this.processAnthropicStream(
|
|
24
29
|
stream,
|
|
25
30
|
options,
|
|
26
|
-
() => generateId(this.name)
|
|
31
|
+
() => generateId(this.name),
|
|
32
|
+
logger
|
|
27
33
|
);
|
|
28
34
|
} catch (error) {
|
|
29
35
|
const err = error;
|
|
36
|
+
logger.errors("anthropic.chatStream fatal", {
|
|
37
|
+
error,
|
|
38
|
+
source: "anthropic.chatStream"
|
|
39
|
+
});
|
|
30
40
|
yield asChunk({
|
|
31
41
|
type: "RUN_ERROR",
|
|
32
42
|
model: options.model,
|
|
@@ -48,6 +58,7 @@ class AnthropicTextAdapter extends BaseTextAdapter {
|
|
|
48
58
|
*/
|
|
49
59
|
async structuredOutput(options) {
|
|
50
60
|
const { chatOptions, outputSchema } = options;
|
|
61
|
+
const { logger } = chatOptions;
|
|
51
62
|
const requestParams = this.mapCommonOptionsToAnthropic(chatOptions);
|
|
52
63
|
const structuredOutputTool = {
|
|
53
64
|
name: "structured_output",
|
|
@@ -59,6 +70,10 @@ class AnthropicTextAdapter extends BaseTextAdapter {
|
|
|
59
70
|
}
|
|
60
71
|
};
|
|
61
72
|
try {
|
|
73
|
+
logger.request(
|
|
74
|
+
`activity=chat provider=anthropic model=${this.model} messages=${chatOptions.messages.length} tools=${chatOptions.tools?.length ?? 0} stream=false`,
|
|
75
|
+
{ provider: "anthropic", model: this.model }
|
|
76
|
+
);
|
|
62
77
|
const response = await this.client.messages.create(
|
|
63
78
|
{
|
|
64
79
|
...requestParams,
|
|
@@ -101,6 +116,10 @@ class AnthropicTextAdapter extends BaseTextAdapter {
|
|
|
101
116
|
};
|
|
102
117
|
} catch (error) {
|
|
103
118
|
const err = error;
|
|
119
|
+
logger.errors("anthropic.structuredOutput fatal", {
|
|
120
|
+
error,
|
|
121
|
+
source: "anthropic.structuredOutput"
|
|
122
|
+
});
|
|
104
123
|
throw new Error(
|
|
105
124
|
`Structured output generation failed: ${err.message || "Unknown error occurred"}`
|
|
106
125
|
);
|
|
@@ -318,7 +337,7 @@ class AnthropicTextAdapter extends BaseTextAdapter {
|
|
|
318
337
|
}
|
|
319
338
|
return merged;
|
|
320
339
|
}
|
|
321
|
-
async *processAnthropicStream(stream, options, genId) {
|
|
340
|
+
async *processAnthropicStream(stream, options, genId, logger) {
|
|
322
341
|
const model = options.model;
|
|
323
342
|
let accumulatedContent = "";
|
|
324
343
|
let accumulatedThinking = "";
|
|
@@ -337,6 +356,9 @@ class AnthropicTextAdapter extends BaseTextAdapter {
|
|
|
337
356
|
let currentBlockType = null;
|
|
338
357
|
try {
|
|
339
358
|
for await (const event of stream) {
|
|
359
|
+
logger.provider(`provider=anthropic type=${event.type}`, {
|
|
360
|
+
chunk: event
|
|
361
|
+
});
|
|
340
362
|
if (!hasEmittedRunStarted) {
|
|
341
363
|
hasEmittedRunStarted = true;
|
|
342
364
|
yield asChunk({
|
|
@@ -607,6 +629,10 @@ class AnthropicTextAdapter extends BaseTextAdapter {
|
|
|
607
629
|
}
|
|
608
630
|
} catch (error) {
|
|
609
631
|
const err = error;
|
|
632
|
+
logger.errors("anthropic.processAnthropicStream fatal", {
|
|
633
|
+
error,
|
|
634
|
+
source: "anthropic.processAnthropicStream"
|
|
635
|
+
});
|
|
610
636
|
yield asChunk({
|
|
611
637
|
type: "RUN_ERROR",
|
|
612
638
|
runId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","sources":["../../../src/adapters/text.ts"],"sourcesContent":["import { BaseTextAdapter } from '@tanstack/ai/adapters'\nimport { convertToolsToProviderFormat } from '../tools/tool-converter'\nimport { validateTextProviderOptions } from '../text/text-provider-options'\nimport {\n createAnthropicClient,\n generateId,\n getAnthropicApiKeyFromEnv,\n} from '../utils'\nimport type {\n ANTHROPIC_MODELS,\n AnthropicChatModelProviderOptionsByName,\n AnthropicChatModelToolCapabilitiesByName,\n AnthropicModelInputModalitiesByName,\n} from '../model-meta'\nimport type {\n StructuredOutputOptions,\n StructuredOutputResult,\n} from '@tanstack/ai/adapters'\nimport type {\n Base64ImageSource,\n Base64PDFSource,\n DocumentBlockParam,\n ImageBlockParam,\n MessageParam,\n TextBlockParam,\n URLImageSource,\n URLPDFSource,\n} from '@anthropic-ai/sdk/resources/messages'\nimport type Anthropic_SDK from '@anthropic-ai/sdk'\nimport type {\n ContentPart,\n Modality,\n ModelMessage,\n StreamChunk,\n TextOptions,\n} from '@tanstack/ai'\nimport type {\n ExternalTextProviderOptions,\n InternalTextProviderOptions,\n} from '../text/text-provider-options'\nimport type {\n AnthropicDocumentMetadata,\n AnthropicImageMetadata,\n AnthropicMessageMetadataByModality,\n AnthropicTextMetadata,\n} from '../message-types'\nimport type { AnthropicClientConfig } from '../utils'\n\n/** Cast an event object to StreamChunk. Adapters construct events with string\n * literal types which are structurally compatible with the EventType enum. */\nconst asChunk = (chunk: Record<string, unknown>) =>\n chunk as unknown as StreamChunk\n\n/**\n * Configuration for Anthropic text adapter\n */\nexport interface AnthropicTextConfig extends AnthropicClientConfig {}\n\n/**\n * Anthropic-specific provider options for text/chat\n */\nexport type AnthropicTextProviderOptions = ExternalTextProviderOptions\n\ntype AnthropicContentBlocks =\n Extract<MessageParam['content'], Array<unknown>> extends Array<infer Block>\n ? Array<Block>\n : never\ntype AnthropicContentBlock =\n AnthropicContentBlocks extends Array<infer Block> ? Block : never\n\n// ===========================\n// Type Resolution Helpers\n// ===========================\n\n/**\n * Resolve provider options for a specific model.\n * If the model has explicit options in the map, use those; otherwise use base options.\n */\ntype ResolveProviderOptions<TModel extends string> =\n TModel extends keyof AnthropicChatModelProviderOptionsByName\n ? AnthropicChatModelProviderOptionsByName[TModel]\n : AnthropicTextProviderOptions\n\n/**\n * Resolve input modalities for a specific model.\n * If the model has explicit modalities in the map, use those; otherwise use default.\n */\ntype ResolveInputModalities<TModel extends string> =\n TModel extends keyof AnthropicModelInputModalitiesByName\n ? AnthropicModelInputModalitiesByName[TModel]\n : readonly ['text', 'image', 'document']\n\ntype ResolveToolCapabilities<TModel extends string> =\n TModel extends keyof AnthropicChatModelToolCapabilitiesByName\n ? NonNullable<AnthropicChatModelToolCapabilitiesByName[TModel]>\n : readonly []\n\n// ===========================\n// Adapter Implementation\n// ===========================\n\n/**\n * Anthropic Text (Chat) Adapter\n *\n * Tree-shakeable adapter for Anthropic chat/text completion functionality.\n * Import only what you need for smaller bundle sizes.\n */\nexport class AnthropicTextAdapter<\n TModel extends (typeof ANTHROPIC_MODELS)[number],\n TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>,\n TInputModalities extends ReadonlyArray<Modality> =\n ResolveInputModalities<TModel>,\n TToolCapabilities extends ReadonlyArray<string> =\n ResolveToolCapabilities<TModel>,\n> extends BaseTextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n AnthropicMessageMetadataByModality,\n TToolCapabilities\n> {\n readonly kind = 'text' as const\n readonly name = 'anthropic' as const\n\n private client: Anthropic_SDK\n\n constructor(config: AnthropicTextConfig, model: TModel) {\n super({}, model)\n this.client = createAnthropicClient(config)\n }\n\n async *chatStream(\n options: TextOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n try {\n const requestParams = this.mapCommonOptionsToAnthropic(options)\n\n const stream = await this.client.beta.messages.create(\n { ...requestParams, stream: true },\n {\n signal: options.request?.signal,\n headers: options.request?.headers,\n },\n )\n\n yield* this.processAnthropicStream(stream, options, () =>\n generateId(this.name),\n )\n } catch (error: unknown) {\n const err = error as Error & { status?: number; code?: string }\n yield asChunk({\n type: 'RUN_ERROR',\n model: options.model,\n timestamp: Date.now(),\n message: err.message || 'Unknown error occurred',\n code: err.code || String(err.status),\n error: {\n message: err.message || 'Unknown error occurred',\n code: err.code || String(err.status),\n },\n })\n }\n }\n\n /**\n * Generate structured output using Anthropic's tool-based approach.\n * Anthropic doesn't have native structured output, so we use a tool with the schema\n * and force the model to call it.\n * The outputSchema is already JSON Schema (converted in the ai layer).\n */\n async structuredOutput(\n options: StructuredOutputOptions<TProviderOptions>,\n ): Promise<StructuredOutputResult<unknown>> {\n const { chatOptions, outputSchema } = options\n\n const requestParams = this.mapCommonOptionsToAnthropic(chatOptions)\n\n // Create a tool that will capture the structured output\n // Anthropic's SDK requires input_schema with type: 'object' literal\n const structuredOutputTool = {\n name: 'structured_output',\n description:\n 'Use this tool to provide your response in the required structured format.',\n input_schema: {\n type: 'object' as const,\n properties: outputSchema.properties ?? {},\n required: outputSchema.required ?? [],\n },\n }\n\n try {\n // Make non-streaming request with tool_choice forced to our structured output tool\n const response = await this.client.messages.create(\n {\n ...requestParams,\n stream: false,\n tools: [structuredOutputTool],\n tool_choice: { type: 'tool', name: 'structured_output' },\n },\n {\n signal: chatOptions.request?.signal,\n headers: chatOptions.request?.headers,\n },\n )\n\n // Extract the tool use content from the response\n let parsed: unknown = null\n let rawText = ''\n\n for (const block of response.content) {\n if (block.type === 'tool_use' && block.name === 'structured_output') {\n parsed = block.input\n rawText = JSON.stringify(block.input)\n break\n }\n }\n\n if (parsed === null) {\n // Fallback: try to extract text content and parse as JSON\n rawText = response.content\n .map((b) => {\n if (b.type === 'text') {\n return b.text\n }\n return ''\n })\n .join('')\n try {\n parsed = JSON.parse(rawText)\n } catch {\n throw new Error(\n `Failed to extract structured output from response. Content: ${rawText.slice(0, 200)}${rawText.length > 200 ? '...' : ''}`,\n )\n }\n }\n\n return {\n data: parsed,\n rawText,\n }\n } catch (error: unknown) {\n const err = error as Error\n throw new Error(\n `Structured output generation failed: ${err.message || 'Unknown error occurred'}`,\n )\n }\n }\n\n private mapCommonOptionsToAnthropic(\n options: TextOptions<AnthropicTextProviderOptions>,\n ) {\n const modelOptions = options.modelOptions as\n | InternalTextProviderOptions\n | undefined\n\n const formattedMessages = this.formatMessages(options.messages)\n const tools = options.tools\n ? convertToolsToProviderFormat(options.tools)\n : undefined\n\n const validProviderOptions: Partial<InternalTextProviderOptions> = {}\n if (modelOptions) {\n const validKeys: Array<keyof InternalTextProviderOptions> = [\n 'container',\n 'context_management',\n 'effort',\n 'mcp_servers',\n 'service_tier',\n 'stop_sequences',\n 'system',\n 'thinking',\n 'tool_choice',\n 'top_k',\n ]\n for (const key of validKeys) {\n if (key in modelOptions) {\n const value = modelOptions[key]\n if (key === 'tool_choice' && typeof value === 'string') {\n ;(validProviderOptions as Record<string, unknown>)[key] = {\n type: value,\n }\n } else {\n ;(validProviderOptions as Record<string, unknown>)[key] = value\n }\n }\n }\n }\n\n const thinkingBudget =\n validProviderOptions.thinking?.type === 'enabled'\n ? validProviderOptions.thinking.budget_tokens\n : undefined\n const defaultMaxTokens = options.maxTokens || 1024\n const maxTokens =\n thinkingBudget && thinkingBudget >= defaultMaxTokens\n ? thinkingBudget + 1\n : defaultMaxTokens\n\n const requestParams: InternalTextProviderOptions = {\n model: options.model,\n max_tokens: maxTokens,\n temperature: options.temperature,\n top_p: options.topP,\n messages: formattedMessages,\n system: options.systemPrompts?.join('\\n'),\n tools: tools,\n ...validProviderOptions,\n }\n validateTextProviderOptions(requestParams)\n return requestParams\n }\n\n private convertContentPartToAnthropic(\n part: ContentPart,\n ): TextBlockParam | ImageBlockParam | DocumentBlockParam {\n switch (part.type) {\n case 'text': {\n const metadata = part.metadata as AnthropicTextMetadata | undefined\n return {\n type: 'text',\n text: part.content,\n ...metadata,\n }\n }\n\n case 'image': {\n const metadata = part.metadata as AnthropicImageMetadata | undefined\n const imageSource: Base64ImageSource | URLImageSource =\n part.source.type === 'data'\n ? {\n type: 'base64',\n data: part.source.value,\n media_type: part.source.mimeType as\n | 'image/jpeg'\n | 'image/png'\n | 'image/gif'\n | 'image/webp',\n }\n : {\n type: 'url',\n url: part.source.value,\n }\n return {\n type: 'image',\n source: imageSource,\n ...metadata,\n }\n }\n case 'document': {\n const metadata = part.metadata as AnthropicDocumentMetadata | undefined\n const docSource: Base64PDFSource | URLPDFSource =\n part.source.type === 'data'\n ? {\n type: 'base64',\n data: part.source.value,\n media_type: part.source.mimeType as 'application/pdf',\n }\n : {\n type: 'url',\n url: part.source.value,\n }\n return {\n type: 'document',\n source: docSource,\n ...metadata,\n }\n }\n case 'audio':\n case 'video':\n throw new Error(\n `Anthropic does not support ${part.type} content directly`,\n )\n default: {\n const _exhaustiveCheck: never = part\n throw new Error(\n `Unsupported content part type: ${(_exhaustiveCheck as ContentPart).type}`,\n )\n }\n }\n }\n\n private formatMessages(\n messages: Array<ModelMessage>,\n ): InternalTextProviderOptions['messages'] {\n const formattedMessages: InternalTextProviderOptions['messages'] = []\n\n for (const message of messages) {\n const role = message.role\n\n if (role === 'tool' && message.toolCallId) {\n formattedMessages.push({\n role: 'user',\n content: [\n {\n type: 'tool_result',\n tool_use_id: message.toolCallId,\n content:\n typeof message.content === 'string' ? message.content : '',\n },\n ],\n })\n continue\n }\n\n if (role === 'assistant' && message.toolCalls?.length) {\n const contentBlocks: AnthropicContentBlocks = []\n\n if (message.content) {\n const content =\n typeof message.content === 'string' ? message.content : ''\n const textBlock: AnthropicContentBlock = {\n type: 'text',\n text: content,\n }\n contentBlocks.push(textBlock)\n }\n\n for (const toolCall of message.toolCalls) {\n let parsedInput: unknown = {}\n try {\n const parsed = toolCall.function.arguments\n ? JSON.parse(toolCall.function.arguments)\n : {}\n parsedInput = parsed && typeof parsed === 'object' ? parsed : {}\n } catch {\n parsedInput = toolCall.function.arguments\n }\n\n const toolUseBlock: AnthropicContentBlock = {\n type: 'tool_use',\n id: toolCall.id,\n name: toolCall.function.name,\n input: parsedInput,\n }\n contentBlocks.push(toolUseBlock)\n }\n\n formattedMessages.push({\n role: 'assistant',\n content: contentBlocks,\n })\n\n continue\n }\n\n if (role === 'user' && Array.isArray(message.content)) {\n const contentBlocks = message.content.map((part) =>\n this.convertContentPartToAnthropic(part),\n )\n formattedMessages.push({\n role: 'user',\n content: contentBlocks,\n })\n continue\n }\n\n formattedMessages.push({\n role: role === 'assistant' ? 'assistant' : 'user',\n content:\n typeof message.content === 'string'\n ? message.content\n : message.content\n ? message.content.map((c) =>\n this.convertContentPartToAnthropic(c),\n )\n : '',\n })\n }\n\n // Post-process: Anthropic requires strictly alternating user/assistant roles.\n // Tool results are sent as role:'user' messages, which can create consecutive\n // user messages when followed by a new user message. Merge them.\n return this.mergeConsecutiveSameRoleMessages(formattedMessages)\n }\n\n /**\n * Merge consecutive messages of the same role into a single message.\n * Anthropic's API requires strictly alternating user/assistant roles.\n * Tool results are wrapped as role:'user' messages, which can collide\n * with actual user messages in multi-turn conversations.\n *\n * Also filters out empty assistant messages (e.g., from a previous failed request).\n */\n private mergeConsecutiveSameRoleMessages(\n messages: InternalTextProviderOptions['messages'],\n ): InternalTextProviderOptions['messages'] {\n const merged: InternalTextProviderOptions['messages'] = []\n\n for (const msg of messages) {\n // Skip empty assistant messages (no content or empty string)\n if (msg.role === 'assistant') {\n const hasContent = Array.isArray(msg.content)\n ? msg.content.length > 0\n : typeof msg.content === 'string' && msg.content.length > 0\n if (!hasContent) {\n continue\n }\n }\n\n const prev = merged[merged.length - 1]\n if (prev && prev.role === msg.role) {\n // Normalize both contents to arrays and concatenate\n const prevBlocks = Array.isArray(prev.content)\n ? prev.content\n : typeof prev.content === 'string' && prev.content\n ? [{ type: 'text' as const, text: prev.content }]\n : []\n const msgBlocks = Array.isArray(msg.content)\n ? msg.content\n : typeof msg.content === 'string' && msg.content\n ? [{ type: 'text' as const, text: msg.content }]\n : []\n prev.content = [...prevBlocks, ...msgBlocks]\n } else {\n merged.push({ ...msg })\n }\n }\n\n // De-duplicate tool_result blocks with the same tool_use_id.\n // This can happen when the core layer generates tool results from both\n // the tool-result part and the tool-call part's output field.\n for (const msg of merged) {\n if (Array.isArray(msg.content)) {\n const seenToolResultIds = new Set<string>()\n msg.content = msg.content.filter((block: any) => {\n if (block.type === 'tool_result' && block.tool_use_id) {\n if (seenToolResultIds.has(block.tool_use_id)) {\n return false // Remove duplicate\n }\n seenToolResultIds.add(block.tool_use_id)\n }\n return true\n })\n }\n }\n\n return merged\n }\n\n private async *processAnthropicStream(\n stream: AsyncIterable<Anthropic_SDK.Beta.BetaRawMessageStreamEvent>,\n options: TextOptions<AnthropicTextProviderOptions>,\n genId: () => string,\n ): AsyncIterable<StreamChunk> {\n const model = options.model\n let accumulatedContent = ''\n let accumulatedThinking = ''\n const timestamp = Date.now()\n const toolCallsMap = new Map<\n number,\n { id: string; name: string; input: string; started: boolean }\n >()\n let currentToolIndex = -1\n\n // AG-UI lifecycle tracking\n const runId = options.runId ?? genId()\n const threadId = options.threadId ?? genId()\n const messageId = genId()\n let stepId: string | null = null\n let reasoningMessageId: string | null = null\n let hasClosedReasoning = false\n let hasEmittedRunStarted = false\n let hasEmittedTextMessageStart = false\n let hasEmittedRunFinished = false\n // Track current content block type for proper content_block_stop handling\n let currentBlockType: string | null = null\n\n try {\n for await (const event of stream) {\n // Emit RUN_STARTED on first event\n if (!hasEmittedRunStarted) {\n hasEmittedRunStarted = true\n yield asChunk({\n type: 'RUN_STARTED',\n runId,\n threadId,\n model,\n timestamp,\n })\n }\n\n if (event.type === 'content_block_start') {\n currentBlockType = event.content_block.type\n if (event.content_block.type === 'tool_use') {\n currentToolIndex++\n toolCallsMap.set(currentToolIndex, {\n id: event.content_block.id,\n name: event.content_block.name,\n input: '',\n started: false,\n })\n } else if (event.content_block.type === 'thinking') {\n accumulatedThinking = ''\n // Emit REASONING and STEP_STARTED for thinking\n stepId = genId()\n reasoningMessageId = genId()\n\n // Spec REASONING events\n yield asChunk({\n type: 'REASONING_START',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n yield asChunk({\n type: 'REASONING_MESSAGE_START',\n messageId: reasoningMessageId,\n role: 'reasoning' as const,\n model,\n timestamp,\n })\n\n // Legacy STEP events (kept during transition)\n yield asChunk({\n type: 'STEP_STARTED',\n stepName: stepId,\n stepId,\n model,\n timestamp,\n stepType: 'thinking',\n })\n }\n } else if (event.type === 'content_block_delta') {\n if (event.delta.type === 'text_delta') {\n // Close reasoning before text starts\n if (reasoningMessageId && !hasClosedReasoning) {\n hasClosedReasoning = true\n yield asChunk({\n type: 'REASONING_MESSAGE_END',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n yield asChunk({\n type: 'REASONING_END',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n }\n\n // Emit TEXT_MESSAGE_START on first text content\n if (!hasEmittedTextMessageStart) {\n hasEmittedTextMessageStart = true\n yield asChunk({\n type: 'TEXT_MESSAGE_START',\n messageId,\n model,\n timestamp,\n role: 'assistant',\n })\n }\n\n const delta = event.delta.text\n accumulatedContent += delta\n yield asChunk({\n type: 'TEXT_MESSAGE_CONTENT',\n messageId,\n model,\n timestamp,\n delta,\n content: accumulatedContent,\n })\n } else if (event.delta.type === 'thinking_delta') {\n const delta = event.delta.thinking\n accumulatedThinking += delta\n\n // Spec REASONING content event\n yield asChunk({\n type: 'REASONING_MESSAGE_CONTENT',\n messageId: reasoningMessageId!,\n delta,\n model,\n timestamp,\n })\n\n // Legacy STEP event\n yield asChunk({\n type: 'STEP_FINISHED',\n stepName: stepId || genId(),\n stepId: stepId || genId(),\n model,\n timestamp,\n delta,\n content: accumulatedThinking,\n })\n } else if (event.delta.type === 'input_json_delta') {\n const existing = toolCallsMap.get(currentToolIndex)\n if (existing) {\n // Emit TOOL_CALL_START on first args delta\n if (!existing.started) {\n existing.started = true\n yield asChunk({\n type: 'TOOL_CALL_START',\n toolCallId: existing.id,\n toolCallName: existing.name,\n toolName: existing.name,\n model,\n timestamp,\n index: currentToolIndex,\n })\n }\n\n existing.input += event.delta.partial_json\n\n yield asChunk({\n type: 'TOOL_CALL_ARGS',\n toolCallId: existing.id,\n model,\n timestamp,\n delta: event.delta.partial_json,\n args: existing.input,\n })\n }\n }\n } else if (event.type === 'content_block_stop') {\n if (currentBlockType === 'tool_use') {\n const existing = toolCallsMap.get(currentToolIndex)\n if (existing) {\n // If tool call wasn't started yet (no args), start it now\n if (!existing.started) {\n existing.started = true\n yield asChunk({\n type: 'TOOL_CALL_START',\n toolCallId: existing.id,\n toolCallName: existing.name,\n toolName: existing.name,\n model,\n timestamp,\n index: currentToolIndex,\n })\n }\n\n // Emit TOOL_CALL_END\n let parsedInput: unknown = {}\n try {\n const parsed = existing.input ? JSON.parse(existing.input) : {}\n parsedInput = parsed && typeof parsed === 'object' ? parsed : {}\n } catch {\n parsedInput = {}\n }\n\n yield asChunk({\n type: 'TOOL_CALL_END',\n toolCallId: existing.id,\n toolCallName: existing.name,\n toolName: existing.name,\n model,\n timestamp,\n input: parsedInput,\n })\n\n // Reset so a new TEXT_MESSAGE_START is emitted if text follows tool calls\n hasEmittedTextMessageStart = false\n }\n } else {\n // Emit TEXT_MESSAGE_END only for text blocks (not tool_use blocks)\n if (hasEmittedTextMessageStart && accumulatedContent) {\n yield asChunk({\n type: 'TEXT_MESSAGE_END',\n messageId,\n model,\n timestamp,\n })\n }\n }\n currentBlockType = null\n } else if (event.type === 'message_stop') {\n // Close reasoning events if still open\n if (reasoningMessageId && !hasClosedReasoning) {\n hasClosedReasoning = true\n yield asChunk({\n type: 'REASONING_MESSAGE_END',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n yield asChunk({\n type: 'REASONING_END',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n }\n\n // Only emit RUN_FINISHED from message_stop if message_delta didn't already emit one.\n // message_delta carries the real stop_reason (tool_use, end_turn, etc.),\n // while message_stop is just a completion signal.\n if (!hasEmittedRunFinished) {\n yield asChunk({\n type: 'RUN_FINISHED',\n runId,\n threadId,\n model,\n timestamp,\n finishReason: 'stop',\n })\n }\n } else if (event.type === 'message_delta') {\n if (event.delta.stop_reason) {\n hasEmittedRunFinished = true\n\n // Close reasoning events if still open\n if (reasoningMessageId && !hasClosedReasoning) {\n hasClosedReasoning = true\n yield asChunk({\n type: 'REASONING_MESSAGE_END',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n yield asChunk({\n type: 'REASONING_END',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n }\n\n switch (event.delta.stop_reason) {\n case 'tool_use': {\n yield asChunk({\n type: 'RUN_FINISHED',\n runId,\n threadId,\n model,\n timestamp,\n finishReason: 'tool_calls',\n usage: {\n promptTokens: event.usage.input_tokens || 0,\n completionTokens: event.usage.output_tokens || 0,\n totalTokens:\n (event.usage.input_tokens || 0) +\n (event.usage.output_tokens || 0),\n },\n })\n break\n }\n case 'max_tokens': {\n yield asChunk({\n type: 'RUN_ERROR',\n runId,\n model,\n timestamp,\n message:\n 'The response was cut off because the maximum token limit was reached.',\n code: 'max_tokens',\n error: {\n message:\n 'The response was cut off because the maximum token limit was reached.',\n code: 'max_tokens',\n },\n })\n break\n }\n default: {\n yield asChunk({\n type: 'RUN_FINISHED',\n runId,\n threadId,\n model,\n timestamp,\n finishReason: 'stop',\n usage: {\n promptTokens: event.usage.input_tokens || 0,\n completionTokens: event.usage.output_tokens || 0,\n totalTokens:\n (event.usage.input_tokens || 0) +\n (event.usage.output_tokens || 0),\n },\n })\n }\n }\n }\n }\n }\n } catch (error: unknown) {\n const err = error as Error & { status?: number; code?: string }\n\n yield asChunk({\n type: 'RUN_ERROR',\n runId,\n model,\n timestamp,\n message: err.message || 'Unknown error occurred',\n code: err.code || String(err.status),\n error: {\n message: err.message || 'Unknown error occurred',\n code: err.code || String(err.status),\n },\n })\n }\n }\n}\n\n/**\n * Creates an Anthropic chat adapter with explicit API key.\n * Type resolution happens here at the call site.\n */\nexport function createAnthropicChat<\n TModel extends (typeof ANTHROPIC_MODELS)[number],\n>(\n model: TModel,\n apiKey: string,\n config?: Omit<AnthropicTextConfig, 'apiKey'>,\n): AnthropicTextAdapter<\n TModel,\n ResolveProviderOptions<TModel>,\n ResolveInputModalities<TModel>\n> {\n return new AnthropicTextAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates an Anthropic text adapter with automatic API key detection.\n * Type resolution happens here at the call site.\n */\nexport function anthropicText<TModel extends (typeof ANTHROPIC_MODELS)[number]>(\n model: TModel,\n config?: Omit<AnthropicTextConfig, 'apiKey'>,\n): AnthropicTextAdapter<\n TModel,\n ResolveProviderOptions<TModel>,\n ResolveInputModalities<TModel>\n> {\n const apiKey = getAnthropicApiKeyFromEnv()\n return createAnthropicChat(model, apiKey, config)\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"text.js","sources":["../../../src/adapters/text.ts"],"sourcesContent":["import { BaseTextAdapter } from '@tanstack/ai/adapters'\nimport { convertToolsToProviderFormat } from '../tools/tool-converter'\nimport { validateTextProviderOptions } from '../text/text-provider-options'\nimport {\n createAnthropicClient,\n generateId,\n getAnthropicApiKeyFromEnv,\n} from '../utils'\nimport type {\n ANTHROPIC_MODELS,\n AnthropicChatModelProviderOptionsByName,\n AnthropicChatModelToolCapabilitiesByName,\n AnthropicModelInputModalitiesByName,\n} from '../model-meta'\nimport type {\n StructuredOutputOptions,\n StructuredOutputResult,\n} from '@tanstack/ai/adapters'\nimport type { InternalLogger } from '@tanstack/ai/adapter-internals'\nimport type {\n Base64ImageSource,\n Base64PDFSource,\n DocumentBlockParam,\n ImageBlockParam,\n MessageParam,\n TextBlockParam,\n URLImageSource,\n URLPDFSource,\n} from '@anthropic-ai/sdk/resources/messages'\nimport type Anthropic_SDK from '@anthropic-ai/sdk'\nimport type {\n ContentPart,\n Modality,\n ModelMessage,\n StreamChunk,\n TextOptions,\n} from '@tanstack/ai'\nimport type {\n ExternalTextProviderOptions,\n InternalTextProviderOptions,\n} from '../text/text-provider-options'\nimport type {\n AnthropicDocumentMetadata,\n AnthropicImageMetadata,\n AnthropicMessageMetadataByModality,\n AnthropicTextMetadata,\n} from '../message-types'\nimport type { AnthropicClientConfig } from '../utils'\n\n/** Cast an event object to StreamChunk. Adapters construct events with string\n * literal types which are structurally compatible with the EventType enum. */\nconst asChunk = (chunk: Record<string, unknown>) =>\n chunk as unknown as StreamChunk\n\n/**\n * Configuration for Anthropic text adapter\n */\nexport interface AnthropicTextConfig extends AnthropicClientConfig {}\n\n/**\n * Anthropic-specific provider options for text/chat\n */\nexport type AnthropicTextProviderOptions = ExternalTextProviderOptions\n\ntype AnthropicContentBlocks =\n Extract<MessageParam['content'], Array<unknown>> extends Array<infer Block>\n ? Array<Block>\n : never\ntype AnthropicContentBlock =\n AnthropicContentBlocks extends Array<infer Block> ? Block : never\n\n// ===========================\n// Type Resolution Helpers\n// ===========================\n\n/**\n * Resolve provider options for a specific model.\n * If the model has explicit options in the map, use those; otherwise use base options.\n */\ntype ResolveProviderOptions<TModel extends string> =\n TModel extends keyof AnthropicChatModelProviderOptionsByName\n ? AnthropicChatModelProviderOptionsByName[TModel]\n : AnthropicTextProviderOptions\n\n/**\n * Resolve input modalities for a specific model.\n * If the model has explicit modalities in the map, use those; otherwise use default.\n */\ntype ResolveInputModalities<TModel extends string> =\n TModel extends keyof AnthropicModelInputModalitiesByName\n ? AnthropicModelInputModalitiesByName[TModel]\n : readonly ['text', 'image', 'document']\n\ntype ResolveToolCapabilities<TModel extends string> =\n TModel extends keyof AnthropicChatModelToolCapabilitiesByName\n ? NonNullable<AnthropicChatModelToolCapabilitiesByName[TModel]>\n : readonly []\n\n// ===========================\n// Adapter Implementation\n// ===========================\n\n/**\n * Anthropic Text (Chat) Adapter\n *\n * Tree-shakeable adapter for Anthropic chat/text completion functionality.\n * Import only what you need for smaller bundle sizes.\n */\nexport class AnthropicTextAdapter<\n TModel extends (typeof ANTHROPIC_MODELS)[number],\n TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>,\n TInputModalities extends ReadonlyArray<Modality> =\n ResolveInputModalities<TModel>,\n TToolCapabilities extends ReadonlyArray<string> =\n ResolveToolCapabilities<TModel>,\n> extends BaseTextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n AnthropicMessageMetadataByModality,\n TToolCapabilities\n> {\n readonly kind = 'text' as const\n readonly name = 'anthropic' as const\n\n private client: Anthropic_SDK\n\n constructor(config: AnthropicTextConfig, model: TModel) {\n super({}, model)\n this.client = createAnthropicClient(config)\n }\n\n async *chatStream(\n options: TextOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n const { logger } = options\n try {\n const requestParams = this.mapCommonOptionsToAnthropic(options)\n\n logger.request(\n `activity=chat provider=anthropic model=${this.model} messages=${options.messages.length} tools=${options.tools?.length ?? 0} stream=true`,\n { provider: 'anthropic', model: this.model },\n )\n const stream = await this.client.beta.messages.create(\n { ...requestParams, stream: true },\n {\n signal: options.request?.signal,\n headers: options.request?.headers,\n },\n )\n\n yield* this.processAnthropicStream(\n stream,\n options,\n () => generateId(this.name),\n logger,\n )\n } catch (error: unknown) {\n const err = error as Error & { status?: number; code?: string }\n logger.errors('anthropic.chatStream fatal', {\n error,\n source: 'anthropic.chatStream',\n })\n yield asChunk({\n type: 'RUN_ERROR',\n model: options.model,\n timestamp: Date.now(),\n message: err.message || 'Unknown error occurred',\n code: err.code || String(err.status),\n error: {\n message: err.message || 'Unknown error occurred',\n code: err.code || String(err.status),\n },\n })\n }\n }\n\n /**\n * Generate structured output using Anthropic's tool-based approach.\n * Anthropic doesn't have native structured output, so we use a tool with the schema\n * and force the model to call it.\n * The outputSchema is already JSON Schema (converted in the ai layer).\n */\n async structuredOutput(\n options: StructuredOutputOptions<TProviderOptions>,\n ): Promise<StructuredOutputResult<unknown>> {\n const { chatOptions, outputSchema } = options\n const { logger } = chatOptions\n\n const requestParams = this.mapCommonOptionsToAnthropic(chatOptions)\n\n // Create a tool that will capture the structured output\n // Anthropic's SDK requires input_schema with type: 'object' literal\n const structuredOutputTool = {\n name: 'structured_output',\n description:\n 'Use this tool to provide your response in the required structured format.',\n input_schema: {\n type: 'object' as const,\n properties: outputSchema.properties ?? {},\n required: outputSchema.required ?? [],\n },\n }\n\n try {\n logger.request(\n `activity=chat provider=anthropic model=${this.model} messages=${chatOptions.messages.length} tools=${chatOptions.tools?.length ?? 0} stream=false`,\n { provider: 'anthropic', model: this.model },\n )\n // Make non-streaming request with tool_choice forced to our structured output tool\n const response = await this.client.messages.create(\n {\n ...requestParams,\n stream: false,\n tools: [structuredOutputTool],\n tool_choice: { type: 'tool', name: 'structured_output' },\n },\n {\n signal: chatOptions.request?.signal,\n headers: chatOptions.request?.headers,\n },\n )\n\n // Extract the tool use content from the response\n let parsed: unknown = null\n let rawText = ''\n\n for (const block of response.content) {\n if (block.type === 'tool_use' && block.name === 'structured_output') {\n parsed = block.input\n rawText = JSON.stringify(block.input)\n break\n }\n }\n\n if (parsed === null) {\n // Fallback: try to extract text content and parse as JSON\n rawText = response.content\n .map((b) => {\n if (b.type === 'text') {\n return b.text\n }\n return ''\n })\n .join('')\n try {\n parsed = JSON.parse(rawText)\n } catch {\n throw new Error(\n `Failed to extract structured output from response. Content: ${rawText.slice(0, 200)}${rawText.length > 200 ? '...' : ''}`,\n )\n }\n }\n\n return {\n data: parsed,\n rawText,\n }\n } catch (error: unknown) {\n const err = error as Error\n logger.errors('anthropic.structuredOutput fatal', {\n error,\n source: 'anthropic.structuredOutput',\n })\n throw new Error(\n `Structured output generation failed: ${err.message || 'Unknown error occurred'}`,\n )\n }\n }\n\n private mapCommonOptionsToAnthropic(\n options: TextOptions<AnthropicTextProviderOptions>,\n ) {\n const modelOptions = options.modelOptions as\n | InternalTextProviderOptions\n | undefined\n\n const formattedMessages = this.formatMessages(options.messages)\n const tools = options.tools\n ? convertToolsToProviderFormat(options.tools)\n : undefined\n\n const validProviderOptions: Partial<InternalTextProviderOptions> = {}\n if (modelOptions) {\n const validKeys: Array<keyof InternalTextProviderOptions> = [\n 'container',\n 'context_management',\n 'effort',\n 'mcp_servers',\n 'service_tier',\n 'stop_sequences',\n 'system',\n 'thinking',\n 'tool_choice',\n 'top_k',\n ]\n for (const key of validKeys) {\n if (key in modelOptions) {\n const value = modelOptions[key]\n if (key === 'tool_choice' && typeof value === 'string') {\n ;(validProviderOptions as Record<string, unknown>)[key] = {\n type: value,\n }\n } else {\n ;(validProviderOptions as Record<string, unknown>)[key] = value\n }\n }\n }\n }\n\n const thinkingBudget =\n validProviderOptions.thinking?.type === 'enabled'\n ? validProviderOptions.thinking.budget_tokens\n : undefined\n const defaultMaxTokens = options.maxTokens || 1024\n const maxTokens =\n thinkingBudget && thinkingBudget >= defaultMaxTokens\n ? thinkingBudget + 1\n : defaultMaxTokens\n\n const requestParams: InternalTextProviderOptions = {\n model: options.model,\n max_tokens: maxTokens,\n temperature: options.temperature,\n top_p: options.topP,\n messages: formattedMessages,\n system: options.systemPrompts?.join('\\n'),\n tools: tools,\n ...validProviderOptions,\n }\n validateTextProviderOptions(requestParams)\n return requestParams\n }\n\n private convertContentPartToAnthropic(\n part: ContentPart,\n ): TextBlockParam | ImageBlockParam | DocumentBlockParam {\n switch (part.type) {\n case 'text': {\n const metadata = part.metadata as AnthropicTextMetadata | undefined\n return {\n type: 'text',\n text: part.content,\n ...metadata,\n }\n }\n\n case 'image': {\n const metadata = part.metadata as AnthropicImageMetadata | undefined\n const imageSource: Base64ImageSource | URLImageSource =\n part.source.type === 'data'\n ? {\n type: 'base64',\n data: part.source.value,\n media_type: part.source.mimeType as\n | 'image/jpeg'\n | 'image/png'\n | 'image/gif'\n | 'image/webp',\n }\n : {\n type: 'url',\n url: part.source.value,\n }\n return {\n type: 'image',\n source: imageSource,\n ...metadata,\n }\n }\n case 'document': {\n const metadata = part.metadata as AnthropicDocumentMetadata | undefined\n const docSource: Base64PDFSource | URLPDFSource =\n part.source.type === 'data'\n ? {\n type: 'base64',\n data: part.source.value,\n media_type: part.source.mimeType as 'application/pdf',\n }\n : {\n type: 'url',\n url: part.source.value,\n }\n return {\n type: 'document',\n source: docSource,\n ...metadata,\n }\n }\n case 'audio':\n case 'video':\n throw new Error(\n `Anthropic does not support ${part.type} content directly`,\n )\n default: {\n const _exhaustiveCheck: never = part\n throw new Error(\n `Unsupported content part type: ${(_exhaustiveCheck as ContentPart).type}`,\n )\n }\n }\n }\n\n private formatMessages(\n messages: Array<ModelMessage>,\n ): InternalTextProviderOptions['messages'] {\n const formattedMessages: InternalTextProviderOptions['messages'] = []\n\n for (const message of messages) {\n const role = message.role\n\n if (role === 'tool' && message.toolCallId) {\n formattedMessages.push({\n role: 'user',\n content: [\n {\n type: 'tool_result',\n tool_use_id: message.toolCallId,\n content:\n typeof message.content === 'string' ? message.content : '',\n },\n ],\n })\n continue\n }\n\n if (role === 'assistant' && message.toolCalls?.length) {\n const contentBlocks: AnthropicContentBlocks = []\n\n if (message.content) {\n const content =\n typeof message.content === 'string' ? message.content : ''\n const textBlock: AnthropicContentBlock = {\n type: 'text',\n text: content,\n }\n contentBlocks.push(textBlock)\n }\n\n for (const toolCall of message.toolCalls) {\n let parsedInput: unknown = {}\n try {\n const parsed = toolCall.function.arguments\n ? JSON.parse(toolCall.function.arguments)\n : {}\n parsedInput = parsed && typeof parsed === 'object' ? parsed : {}\n } catch {\n parsedInput = toolCall.function.arguments\n }\n\n const toolUseBlock: AnthropicContentBlock = {\n type: 'tool_use',\n id: toolCall.id,\n name: toolCall.function.name,\n input: parsedInput,\n }\n contentBlocks.push(toolUseBlock)\n }\n\n formattedMessages.push({\n role: 'assistant',\n content: contentBlocks,\n })\n\n continue\n }\n\n if (role === 'user' && Array.isArray(message.content)) {\n const contentBlocks = message.content.map((part) =>\n this.convertContentPartToAnthropic(part),\n )\n formattedMessages.push({\n role: 'user',\n content: contentBlocks,\n })\n continue\n }\n\n formattedMessages.push({\n role: role === 'assistant' ? 'assistant' : 'user',\n content:\n typeof message.content === 'string'\n ? message.content\n : message.content\n ? message.content.map((c) =>\n this.convertContentPartToAnthropic(c),\n )\n : '',\n })\n }\n\n // Post-process: Anthropic requires strictly alternating user/assistant roles.\n // Tool results are sent as role:'user' messages, which can create consecutive\n // user messages when followed by a new user message. Merge them.\n return this.mergeConsecutiveSameRoleMessages(formattedMessages)\n }\n\n /**\n * Merge consecutive messages of the same role into a single message.\n * Anthropic's API requires strictly alternating user/assistant roles.\n * Tool results are wrapped as role:'user' messages, which can collide\n * with actual user messages in multi-turn conversations.\n *\n * Also filters out empty assistant messages (e.g., from a previous failed request).\n */\n private mergeConsecutiveSameRoleMessages(\n messages: InternalTextProviderOptions['messages'],\n ): InternalTextProviderOptions['messages'] {\n const merged: InternalTextProviderOptions['messages'] = []\n\n for (const msg of messages) {\n // Skip empty assistant messages (no content or empty string)\n if (msg.role === 'assistant') {\n const hasContent = Array.isArray(msg.content)\n ? msg.content.length > 0\n : typeof msg.content === 'string' && msg.content.length > 0\n if (!hasContent) {\n continue\n }\n }\n\n const prev = merged[merged.length - 1]\n if (prev && prev.role === msg.role) {\n // Normalize both contents to arrays and concatenate\n const prevBlocks = Array.isArray(prev.content)\n ? prev.content\n : typeof prev.content === 'string' && prev.content\n ? [{ type: 'text' as const, text: prev.content }]\n : []\n const msgBlocks = Array.isArray(msg.content)\n ? msg.content\n : typeof msg.content === 'string' && msg.content\n ? [{ type: 'text' as const, text: msg.content }]\n : []\n prev.content = [...prevBlocks, ...msgBlocks]\n } else {\n merged.push({ ...msg })\n }\n }\n\n // De-duplicate tool_result blocks with the same tool_use_id.\n // This can happen when the core layer generates tool results from both\n // the tool-result part and the tool-call part's output field.\n for (const msg of merged) {\n if (Array.isArray(msg.content)) {\n const seenToolResultIds = new Set<string>()\n msg.content = msg.content.filter((block: any) => {\n if (block.type === 'tool_result' && block.tool_use_id) {\n if (seenToolResultIds.has(block.tool_use_id)) {\n return false // Remove duplicate\n }\n seenToolResultIds.add(block.tool_use_id)\n }\n return true\n })\n }\n }\n\n return merged\n }\n\n private async *processAnthropicStream(\n stream: AsyncIterable<Anthropic_SDK.Beta.BetaRawMessageStreamEvent>,\n options: TextOptions<AnthropicTextProviderOptions>,\n genId: () => string,\n logger: InternalLogger,\n ): AsyncIterable<StreamChunk> {\n const model = options.model\n let accumulatedContent = ''\n let accumulatedThinking = ''\n const timestamp = Date.now()\n const toolCallsMap = new Map<\n number,\n { id: string; name: string; input: string; started: boolean }\n >()\n let currentToolIndex = -1\n\n // AG-UI lifecycle tracking\n const runId = options.runId ?? genId()\n const threadId = options.threadId ?? genId()\n const messageId = genId()\n let stepId: string | null = null\n let reasoningMessageId: string | null = null\n let hasClosedReasoning = false\n let hasEmittedRunStarted = false\n let hasEmittedTextMessageStart = false\n let hasEmittedRunFinished = false\n // Track current content block type for proper content_block_stop handling\n let currentBlockType: string | null = null\n\n try {\n for await (const event of stream) {\n logger.provider(`provider=anthropic type=${event.type}`, {\n chunk: event,\n })\n // Emit RUN_STARTED on first event\n if (!hasEmittedRunStarted) {\n hasEmittedRunStarted = true\n yield asChunk({\n type: 'RUN_STARTED',\n runId,\n threadId,\n model,\n timestamp,\n })\n }\n\n if (event.type === 'content_block_start') {\n currentBlockType = event.content_block.type\n if (event.content_block.type === 'tool_use') {\n currentToolIndex++\n toolCallsMap.set(currentToolIndex, {\n id: event.content_block.id,\n name: event.content_block.name,\n input: '',\n started: false,\n })\n } else if (event.content_block.type === 'thinking') {\n accumulatedThinking = ''\n // Emit REASONING and STEP_STARTED for thinking\n stepId = genId()\n reasoningMessageId = genId()\n\n // Spec REASONING events\n yield asChunk({\n type: 'REASONING_START',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n yield asChunk({\n type: 'REASONING_MESSAGE_START',\n messageId: reasoningMessageId,\n role: 'reasoning' as const,\n model,\n timestamp,\n })\n\n // Legacy STEP events (kept during transition)\n yield asChunk({\n type: 'STEP_STARTED',\n stepName: stepId,\n stepId,\n model,\n timestamp,\n stepType: 'thinking',\n })\n }\n } else if (event.type === 'content_block_delta') {\n if (event.delta.type === 'text_delta') {\n // Close reasoning before text starts\n if (reasoningMessageId && !hasClosedReasoning) {\n hasClosedReasoning = true\n yield asChunk({\n type: 'REASONING_MESSAGE_END',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n yield asChunk({\n type: 'REASONING_END',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n }\n\n // Emit TEXT_MESSAGE_START on first text content\n if (!hasEmittedTextMessageStart) {\n hasEmittedTextMessageStart = true\n yield asChunk({\n type: 'TEXT_MESSAGE_START',\n messageId,\n model,\n timestamp,\n role: 'assistant',\n })\n }\n\n const delta = event.delta.text\n accumulatedContent += delta\n yield asChunk({\n type: 'TEXT_MESSAGE_CONTENT',\n messageId,\n model,\n timestamp,\n delta,\n content: accumulatedContent,\n })\n } else if (event.delta.type === 'thinking_delta') {\n const delta = event.delta.thinking\n accumulatedThinking += delta\n\n // Spec REASONING content event\n yield asChunk({\n type: 'REASONING_MESSAGE_CONTENT',\n messageId: reasoningMessageId!,\n delta,\n model,\n timestamp,\n })\n\n // Legacy STEP event\n yield asChunk({\n type: 'STEP_FINISHED',\n stepName: stepId || genId(),\n stepId: stepId || genId(),\n model,\n timestamp,\n delta,\n content: accumulatedThinking,\n })\n } else if (event.delta.type === 'input_json_delta') {\n const existing = toolCallsMap.get(currentToolIndex)\n if (existing) {\n // Emit TOOL_CALL_START on first args delta\n if (!existing.started) {\n existing.started = true\n yield asChunk({\n type: 'TOOL_CALL_START',\n toolCallId: existing.id,\n toolCallName: existing.name,\n toolName: existing.name,\n model,\n timestamp,\n index: currentToolIndex,\n })\n }\n\n existing.input += event.delta.partial_json\n\n yield asChunk({\n type: 'TOOL_CALL_ARGS',\n toolCallId: existing.id,\n model,\n timestamp,\n delta: event.delta.partial_json,\n args: existing.input,\n })\n }\n }\n } else if (event.type === 'content_block_stop') {\n if (currentBlockType === 'tool_use') {\n const existing = toolCallsMap.get(currentToolIndex)\n if (existing) {\n // If tool call wasn't started yet (no args), start it now\n if (!existing.started) {\n existing.started = true\n yield asChunk({\n type: 'TOOL_CALL_START',\n toolCallId: existing.id,\n toolCallName: existing.name,\n toolName: existing.name,\n model,\n timestamp,\n index: currentToolIndex,\n })\n }\n\n // Emit TOOL_CALL_END\n let parsedInput: unknown = {}\n try {\n const parsed = existing.input ? JSON.parse(existing.input) : {}\n parsedInput = parsed && typeof parsed === 'object' ? parsed : {}\n } catch {\n parsedInput = {}\n }\n\n yield asChunk({\n type: 'TOOL_CALL_END',\n toolCallId: existing.id,\n toolCallName: existing.name,\n toolName: existing.name,\n model,\n timestamp,\n input: parsedInput,\n })\n\n // Reset so a new TEXT_MESSAGE_START is emitted if text follows tool calls\n hasEmittedTextMessageStart = false\n }\n } else {\n // Emit TEXT_MESSAGE_END only for text blocks (not tool_use blocks)\n if (hasEmittedTextMessageStart && accumulatedContent) {\n yield asChunk({\n type: 'TEXT_MESSAGE_END',\n messageId,\n model,\n timestamp,\n })\n }\n }\n currentBlockType = null\n } else if (event.type === 'message_stop') {\n // Close reasoning events if still open\n if (reasoningMessageId && !hasClosedReasoning) {\n hasClosedReasoning = true\n yield asChunk({\n type: 'REASONING_MESSAGE_END',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n yield asChunk({\n type: 'REASONING_END',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n }\n\n // Only emit RUN_FINISHED from message_stop if message_delta didn't already emit one.\n // message_delta carries the real stop_reason (tool_use, end_turn, etc.),\n // while message_stop is just a completion signal.\n if (!hasEmittedRunFinished) {\n yield asChunk({\n type: 'RUN_FINISHED',\n runId,\n threadId,\n model,\n timestamp,\n finishReason: 'stop',\n })\n }\n } else if (event.type === 'message_delta') {\n if (event.delta.stop_reason) {\n hasEmittedRunFinished = true\n\n // Close reasoning events if still open\n if (reasoningMessageId && !hasClosedReasoning) {\n hasClosedReasoning = true\n yield asChunk({\n type: 'REASONING_MESSAGE_END',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n yield asChunk({\n type: 'REASONING_END',\n messageId: reasoningMessageId,\n model,\n timestamp,\n })\n }\n\n switch (event.delta.stop_reason) {\n case 'tool_use': {\n yield asChunk({\n type: 'RUN_FINISHED',\n runId,\n threadId,\n model,\n timestamp,\n finishReason: 'tool_calls',\n usage: {\n promptTokens: event.usage.input_tokens || 0,\n completionTokens: event.usage.output_tokens || 0,\n totalTokens:\n (event.usage.input_tokens || 0) +\n (event.usage.output_tokens || 0),\n },\n })\n break\n }\n case 'max_tokens': {\n yield asChunk({\n type: 'RUN_ERROR',\n runId,\n model,\n timestamp,\n message:\n 'The response was cut off because the maximum token limit was reached.',\n code: 'max_tokens',\n error: {\n message:\n 'The response was cut off because the maximum token limit was reached.',\n code: 'max_tokens',\n },\n })\n break\n }\n default: {\n yield asChunk({\n type: 'RUN_FINISHED',\n runId,\n threadId,\n model,\n timestamp,\n finishReason: 'stop',\n usage: {\n promptTokens: event.usage.input_tokens || 0,\n completionTokens: event.usage.output_tokens || 0,\n totalTokens:\n (event.usage.input_tokens || 0) +\n (event.usage.output_tokens || 0),\n },\n })\n }\n }\n }\n }\n }\n } catch (error: unknown) {\n const err = error as Error & { status?: number; code?: string }\n\n logger.errors('anthropic.processAnthropicStream fatal', {\n error,\n source: 'anthropic.processAnthropicStream',\n })\n yield asChunk({\n type: 'RUN_ERROR',\n runId,\n model,\n timestamp,\n message: err.message || 'Unknown error occurred',\n code: err.code || String(err.status),\n error: {\n message: err.message || 'Unknown error occurred',\n code: err.code || String(err.status),\n },\n })\n }\n }\n}\n\n/**\n * Creates an Anthropic chat adapter with explicit API key.\n * Type resolution happens here at the call site.\n */\nexport function createAnthropicChat<\n TModel extends (typeof ANTHROPIC_MODELS)[number],\n>(\n model: TModel,\n apiKey: string,\n config?: Omit<AnthropicTextConfig, 'apiKey'>,\n): AnthropicTextAdapter<\n TModel,\n ResolveProviderOptions<TModel>,\n ResolveInputModalities<TModel>\n> {\n return new AnthropicTextAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates an Anthropic text adapter with automatic API key detection.\n * Type resolution happens here at the call site.\n */\nexport function anthropicText<TModel extends (typeof ANTHROPIC_MODELS)[number]>(\n model: TModel,\n config?: Omit<AnthropicTextConfig, 'apiKey'>,\n): AnthropicTextAdapter<\n TModel,\n ResolveProviderOptions<TModel>,\n ResolveInputModalities<TModel>\n> {\n const apiKey = getAnthropicApiKeyFromEnv()\n return createAnthropicChat(model, apiKey, config)\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/ai-anthropic",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "Anthropic Claude adapter for TanStack AI",
|
|
5
5
|
"author": "",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,12 +38,12 @@
|
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"zod": "^4.0.0",
|
|
41
|
-
"@tanstack/ai": "^0.
|
|
41
|
+
"@tanstack/ai": "^0.14.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@vitest/coverage-v8": "4.0.14",
|
|
45
45
|
"zod": "^4.2.0",
|
|
46
|
-
"@tanstack/ai": "0.
|
|
46
|
+
"@tanstack/ai": "0.14.0"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "vite build",
|
|
@@ -54,36 +54,52 @@ export class AnthropicSummarizeAdapter<
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
async summarize(options: SummarizationOptions): Promise<SummarizationResult> {
|
|
57
|
+
const { logger } = options
|
|
57
58
|
const systemPrompt = this.buildSummarizationPrompt(options)
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
logger.request(`activity=summarize provider=anthropic`, {
|
|
61
|
+
provider: 'anthropic',
|
|
60
62
|
model: options.model,
|
|
61
|
-
messages: [{ role: 'user', content: options.text }],
|
|
62
|
-
system: systemPrompt,
|
|
63
|
-
max_tokens: options.maxLength || 500,
|
|
64
|
-
temperature: 0.3,
|
|
65
|
-
stream: false,
|
|
66
63
|
})
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
65
|
+
try {
|
|
66
|
+
const response = await this.client.messages.create({
|
|
67
|
+
model: options.model,
|
|
68
|
+
messages: [{ role: 'user', content: options.text }],
|
|
69
|
+
system: systemPrompt,
|
|
70
|
+
max_tokens: options.maxLength || 500,
|
|
71
|
+
temperature: 0.3,
|
|
72
|
+
stream: false,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const content = response.content
|
|
76
|
+
.map((c) => (c.type === 'text' ? c.text : ''))
|
|
77
|
+
.join('')
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
id: response.id,
|
|
81
|
+
model: response.model,
|
|
82
|
+
summary: content,
|
|
83
|
+
usage: {
|
|
84
|
+
promptTokens: response.usage.input_tokens,
|
|
85
|
+
completionTokens: response.usage.output_tokens,
|
|
86
|
+
totalTokens:
|
|
87
|
+
response.usage.input_tokens + response.usage.output_tokens,
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
logger.errors('anthropic.summarize fatal', {
|
|
92
|
+
error,
|
|
93
|
+
source: 'anthropic.summarize',
|
|
94
|
+
})
|
|
95
|
+
throw error
|
|
81
96
|
}
|
|
82
97
|
}
|
|
83
98
|
|
|
84
99
|
async *summarizeStream(
|
|
85
100
|
options: SummarizationOptions,
|
|
86
101
|
): AsyncIterable<StreamChunk> {
|
|
102
|
+
const { logger } = options
|
|
87
103
|
const systemPrompt = this.buildSummarizationPrompt(options)
|
|
88
104
|
const id = generateId(this.name)
|
|
89
105
|
const model = options.model
|
|
@@ -91,50 +107,68 @@ export class AnthropicSummarizeAdapter<
|
|
|
91
107
|
let inputTokens = 0
|
|
92
108
|
let outputTokens = 0
|
|
93
109
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
system: systemPrompt,
|
|
98
|
-
max_tokens: options.maxLength || 500,
|
|
99
|
-
temperature: 0.3,
|
|
110
|
+
logger.request(`activity=summarize provider=anthropic`, {
|
|
111
|
+
provider: 'anthropic',
|
|
112
|
+
model,
|
|
100
113
|
stream: true,
|
|
101
114
|
})
|
|
102
115
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
try {
|
|
117
|
+
const stream = await this.client.messages.create({
|
|
118
|
+
model: options.model,
|
|
119
|
+
messages: [{ role: 'user', content: options.text }],
|
|
120
|
+
system: systemPrompt,
|
|
121
|
+
max_tokens: options.maxLength || 500,
|
|
122
|
+
temperature: 0.3,
|
|
123
|
+
stream: true,
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
for await (const event of stream) {
|
|
127
|
+
logger.provider(`provider=anthropic type=${event.type}`, {
|
|
128
|
+
chunk: event,
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
if (event.type === 'message_start') {
|
|
132
|
+
inputTokens = event.message.usage.input_tokens
|
|
133
|
+
} else if (event.type === 'content_block_delta') {
|
|
134
|
+
if (event.delta.type === 'text_delta') {
|
|
135
|
+
const delta = event.delta.text
|
|
136
|
+
accumulatedContent += delta
|
|
137
|
+
yield asChunk({
|
|
138
|
+
type: 'TEXT_MESSAGE_CONTENT',
|
|
139
|
+
messageId: id,
|
|
140
|
+
model,
|
|
141
|
+
timestamp: Date.now(),
|
|
142
|
+
delta,
|
|
143
|
+
content: accumulatedContent,
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
} else if (event.type === 'message_delta') {
|
|
147
|
+
outputTokens = event.usage.output_tokens
|
|
110
148
|
yield asChunk({
|
|
111
|
-
type: '
|
|
112
|
-
|
|
149
|
+
type: 'RUN_FINISHED',
|
|
150
|
+
runId: id,
|
|
113
151
|
model,
|
|
114
152
|
timestamp: Date.now(),
|
|
115
|
-
delta
|
|
116
|
-
|
|
153
|
+
finishReason: event.delta.stop_reason as
|
|
154
|
+
| 'stop'
|
|
155
|
+
| 'length'
|
|
156
|
+
| 'content_filter'
|
|
157
|
+
| null,
|
|
158
|
+
usage: {
|
|
159
|
+
promptTokens: inputTokens,
|
|
160
|
+
completionTokens: outputTokens,
|
|
161
|
+
totalTokens: inputTokens + outputTokens,
|
|
162
|
+
},
|
|
117
163
|
})
|
|
118
164
|
}
|
|
119
|
-
} else if (event.type === 'message_delta') {
|
|
120
|
-
outputTokens = event.usage.output_tokens
|
|
121
|
-
yield asChunk({
|
|
122
|
-
type: 'RUN_FINISHED',
|
|
123
|
-
runId: id,
|
|
124
|
-
model,
|
|
125
|
-
timestamp: Date.now(),
|
|
126
|
-
finishReason: event.delta.stop_reason as
|
|
127
|
-
| 'stop'
|
|
128
|
-
| 'length'
|
|
129
|
-
| 'content_filter'
|
|
130
|
-
| null,
|
|
131
|
-
usage: {
|
|
132
|
-
promptTokens: inputTokens,
|
|
133
|
-
completionTokens: outputTokens,
|
|
134
|
-
totalTokens: inputTokens + outputTokens,
|
|
135
|
-
},
|
|
136
|
-
})
|
|
137
165
|
}
|
|
166
|
+
} catch (error) {
|
|
167
|
+
logger.errors('anthropic.summarize fatal', {
|
|
168
|
+
error,
|
|
169
|
+
source: 'anthropic.summarize',
|
|
170
|
+
})
|
|
171
|
+
throw error
|
|
138
172
|
}
|
|
139
173
|
}
|
|
140
174
|
|
package/src/adapters/text.ts
CHANGED
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
StructuredOutputOptions,
|
|
17
17
|
StructuredOutputResult,
|
|
18
18
|
} from '@tanstack/ai/adapters'
|
|
19
|
+
import type { InternalLogger } from '@tanstack/ai/adapter-internals'
|
|
19
20
|
import type {
|
|
20
21
|
Base64ImageSource,
|
|
21
22
|
Base64PDFSource,
|
|
@@ -132,9 +133,14 @@ export class AnthropicTextAdapter<
|
|
|
132
133
|
async *chatStream(
|
|
133
134
|
options: TextOptions<TProviderOptions>,
|
|
134
135
|
): AsyncIterable<StreamChunk> {
|
|
136
|
+
const { logger } = options
|
|
135
137
|
try {
|
|
136
138
|
const requestParams = this.mapCommonOptionsToAnthropic(options)
|
|
137
139
|
|
|
140
|
+
logger.request(
|
|
141
|
+
`activity=chat provider=anthropic model=${this.model} messages=${options.messages.length} tools=${options.tools?.length ?? 0} stream=true`,
|
|
142
|
+
{ provider: 'anthropic', model: this.model },
|
|
143
|
+
)
|
|
138
144
|
const stream = await this.client.beta.messages.create(
|
|
139
145
|
{ ...requestParams, stream: true },
|
|
140
146
|
{
|
|
@@ -143,11 +149,18 @@ export class AnthropicTextAdapter<
|
|
|
143
149
|
},
|
|
144
150
|
)
|
|
145
151
|
|
|
146
|
-
yield* this.processAnthropicStream(
|
|
147
|
-
|
|
152
|
+
yield* this.processAnthropicStream(
|
|
153
|
+
stream,
|
|
154
|
+
options,
|
|
155
|
+
() => generateId(this.name),
|
|
156
|
+
logger,
|
|
148
157
|
)
|
|
149
158
|
} catch (error: unknown) {
|
|
150
159
|
const err = error as Error & { status?: number; code?: string }
|
|
160
|
+
logger.errors('anthropic.chatStream fatal', {
|
|
161
|
+
error,
|
|
162
|
+
source: 'anthropic.chatStream',
|
|
163
|
+
})
|
|
151
164
|
yield asChunk({
|
|
152
165
|
type: 'RUN_ERROR',
|
|
153
166
|
model: options.model,
|
|
@@ -172,6 +185,7 @@ export class AnthropicTextAdapter<
|
|
|
172
185
|
options: StructuredOutputOptions<TProviderOptions>,
|
|
173
186
|
): Promise<StructuredOutputResult<unknown>> {
|
|
174
187
|
const { chatOptions, outputSchema } = options
|
|
188
|
+
const { logger } = chatOptions
|
|
175
189
|
|
|
176
190
|
const requestParams = this.mapCommonOptionsToAnthropic(chatOptions)
|
|
177
191
|
|
|
@@ -189,6 +203,10 @@ export class AnthropicTextAdapter<
|
|
|
189
203
|
}
|
|
190
204
|
|
|
191
205
|
try {
|
|
206
|
+
logger.request(
|
|
207
|
+
`activity=chat provider=anthropic model=${this.model} messages=${chatOptions.messages.length} tools=${chatOptions.tools?.length ?? 0} stream=false`,
|
|
208
|
+
{ provider: 'anthropic', model: this.model },
|
|
209
|
+
)
|
|
192
210
|
// Make non-streaming request with tool_choice forced to our structured output tool
|
|
193
211
|
const response = await this.client.messages.create(
|
|
194
212
|
{
|
|
@@ -240,6 +258,10 @@ export class AnthropicTextAdapter<
|
|
|
240
258
|
}
|
|
241
259
|
} catch (error: unknown) {
|
|
242
260
|
const err = error as Error
|
|
261
|
+
logger.errors('anthropic.structuredOutput fatal', {
|
|
262
|
+
error,
|
|
263
|
+
source: 'anthropic.structuredOutput',
|
|
264
|
+
})
|
|
243
265
|
throw new Error(
|
|
244
266
|
`Structured output generation failed: ${err.message || 'Unknown error occurred'}`,
|
|
245
267
|
)
|
|
@@ -541,6 +563,7 @@ export class AnthropicTextAdapter<
|
|
|
541
563
|
stream: AsyncIterable<Anthropic_SDK.Beta.BetaRawMessageStreamEvent>,
|
|
542
564
|
options: TextOptions<AnthropicTextProviderOptions>,
|
|
543
565
|
genId: () => string,
|
|
566
|
+
logger: InternalLogger,
|
|
544
567
|
): AsyncIterable<StreamChunk> {
|
|
545
568
|
const model = options.model
|
|
546
569
|
let accumulatedContent = ''
|
|
@@ -567,6 +590,9 @@ export class AnthropicTextAdapter<
|
|
|
567
590
|
|
|
568
591
|
try {
|
|
569
592
|
for await (const event of stream) {
|
|
593
|
+
logger.provider(`provider=anthropic type=${event.type}`, {
|
|
594
|
+
chunk: event,
|
|
595
|
+
})
|
|
570
596
|
// Emit RUN_STARTED on first event
|
|
571
597
|
if (!hasEmittedRunStarted) {
|
|
572
598
|
hasEmittedRunStarted = true
|
|
@@ -877,6 +903,10 @@ export class AnthropicTextAdapter<
|
|
|
877
903
|
} catch (error: unknown) {
|
|
878
904
|
const err = error as Error & { status?: number; code?: string }
|
|
879
905
|
|
|
906
|
+
logger.errors('anthropic.processAnthropicStream fatal', {
|
|
907
|
+
error,
|
|
908
|
+
source: 'anthropic.processAnthropicStream',
|
|
909
|
+
})
|
|
880
910
|
yield asChunk({
|
|
881
911
|
type: 'RUN_ERROR',
|
|
882
912
|
runId,
|