@tanstack/ai-anthropic 0.7.3 → 0.7.5

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.
@@ -1,5 +1,6 @@
1
1
  import { BaseSummarizeAdapter } from "@tanstack/ai/adapters";
2
2
  import { createAnthropicClient, generateId, getAnthropicApiKeyFromEnv } from "../utils/client.js";
3
+ const asChunk = (chunk) => chunk;
3
4
  class AnthropicSummarizeAdapter extends BaseSummarizeAdapter {
4
5
  constructor(config, model) {
5
6
  super({}, model);
@@ -51,18 +52,18 @@ class AnthropicSummarizeAdapter extends BaseSummarizeAdapter {
51
52
  if (event.delta.type === "text_delta") {
52
53
  const delta = event.delta.text;
53
54
  accumulatedContent += delta;
54
- yield {
55
+ yield asChunk({
55
56
  type: "TEXT_MESSAGE_CONTENT",
56
57
  messageId: id,
57
58
  model,
58
59
  timestamp: Date.now(),
59
60
  delta,
60
61
  content: accumulatedContent
61
- };
62
+ });
62
63
  }
63
64
  } else if (event.type === "message_delta") {
64
65
  outputTokens = event.usage.output_tokens;
65
- yield {
66
+ yield asChunk({
66
67
  type: "RUN_FINISHED",
67
68
  runId: id,
68
69
  model,
@@ -73,7 +74,7 @@ class AnthropicSummarizeAdapter extends BaseSummarizeAdapter {
73
74
  completionTokens: outputTokens,
74
75
  totalTokens: inputTokens + outputTokens
75
76
  }
76
- };
77
+ });
77
78
  }
78
79
  }
79
80
  }
@@ -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/**\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: '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 {\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":";;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,WAAW;AAAA,YACX;AAAA,YACA,WAAW,KAAK,IAAA;AAAA,YAChB;AAAA,YACA,SAAS;AAAA,UAAA;AAAA,QAEb;AAAA,MACF,WAAW,MAAM,SAAS,iBAAiB;AACzC,uBAAe,MAAM,MAAM;AAC3B,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,OAAO;AAAA,UACP;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;"}
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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"}
@@ -2,6 +2,7 @@ import { BaseTextAdapter } from "@tanstack/ai/adapters";
2
2
  import { convertToolsToProviderFormat } from "../tools/tool-converter.js";
3
3
  import { validateTextProviderOptions } from "../text/text-provider-options.js";
4
4
  import { createAnthropicClient, generateId, getAnthropicApiKeyFromEnv } from "../utils/client.js";
5
+ const asChunk = (chunk) => chunk;
5
6
  class AnthropicTextAdapter extends BaseTextAdapter {
6
7
  constructor(config, model) {
7
8
  super({}, model);
@@ -21,20 +22,22 @@ class AnthropicTextAdapter extends BaseTextAdapter {
21
22
  );
22
23
  yield* this.processAnthropicStream(
23
24
  stream,
24
- options.model,
25
+ options,
25
26
  () => generateId(this.name)
26
27
  );
27
28
  } catch (error) {
28
29
  const err = error;
29
- yield {
30
+ yield asChunk({
30
31
  type: "RUN_ERROR",
31
32
  model: options.model,
32
33
  timestamp: Date.now(),
34
+ message: err.message || "Unknown error occurred",
35
+ code: err.code || String(err.status),
33
36
  error: {
34
37
  message: err.message || "Unknown error occurred",
35
38
  code: err.code || String(err.status)
36
39
  }
37
- };
40
+ });
38
41
  }
39
42
  }
40
43
  /**
@@ -315,15 +318,19 @@ class AnthropicTextAdapter extends BaseTextAdapter {
315
318
  }
316
319
  return merged;
317
320
  }
318
- async *processAnthropicStream(stream, model, genId) {
321
+ async *processAnthropicStream(stream, options, genId) {
322
+ const model = options.model;
319
323
  let accumulatedContent = "";
320
324
  let accumulatedThinking = "";
321
325
  const timestamp = Date.now();
322
326
  const toolCallsMap = /* @__PURE__ */ new Map();
323
327
  let currentToolIndex = -1;
324
- const runId = genId();
328
+ const runId = options.runId ?? genId();
329
+ const threadId = options.threadId ?? genId();
325
330
  const messageId = genId();
326
331
  let stepId = null;
332
+ let reasoningMessageId = null;
333
+ let hasClosedReasoning = false;
327
334
  let hasEmittedRunStarted = false;
328
335
  let hasEmittedTextMessageStart = false;
329
336
  let hasEmittedRunFinished = false;
@@ -332,12 +339,13 @@ class AnthropicTextAdapter extends BaseTextAdapter {
332
339
  for await (const event of stream) {
333
340
  if (!hasEmittedRunStarted) {
334
341
  hasEmittedRunStarted = true;
335
- yield {
342
+ yield asChunk({
336
343
  type: "RUN_STARTED",
337
344
  runId,
345
+ threadId,
338
346
  model,
339
347
  timestamp
340
- };
348
+ });
341
349
  }
342
350
  if (event.type === "content_block_start") {
343
351
  currentBlockType = event.content_block.type;
@@ -352,70 +360,109 @@ class AnthropicTextAdapter extends BaseTextAdapter {
352
360
  } else if (event.content_block.type === "thinking") {
353
361
  accumulatedThinking = "";
354
362
  stepId = genId();
355
- yield {
363
+ reasoningMessageId = genId();
364
+ yield asChunk({
365
+ type: "REASONING_START",
366
+ messageId: reasoningMessageId,
367
+ model,
368
+ timestamp
369
+ });
370
+ yield asChunk({
371
+ type: "REASONING_MESSAGE_START",
372
+ messageId: reasoningMessageId,
373
+ role: "reasoning",
374
+ model,
375
+ timestamp
376
+ });
377
+ yield asChunk({
356
378
  type: "STEP_STARTED",
379
+ stepName: stepId,
357
380
  stepId,
358
381
  model,
359
382
  timestamp,
360
383
  stepType: "thinking"
361
- };
384
+ });
362
385
  }
363
386
  } else if (event.type === "content_block_delta") {
364
387
  if (event.delta.type === "text_delta") {
388
+ if (reasoningMessageId && !hasClosedReasoning) {
389
+ hasClosedReasoning = true;
390
+ yield asChunk({
391
+ type: "REASONING_MESSAGE_END",
392
+ messageId: reasoningMessageId,
393
+ model,
394
+ timestamp
395
+ });
396
+ yield asChunk({
397
+ type: "REASONING_END",
398
+ messageId: reasoningMessageId,
399
+ model,
400
+ timestamp
401
+ });
402
+ }
365
403
  if (!hasEmittedTextMessageStart) {
366
404
  hasEmittedTextMessageStart = true;
367
- yield {
405
+ yield asChunk({
368
406
  type: "TEXT_MESSAGE_START",
369
407
  messageId,
370
408
  model,
371
409
  timestamp,
372
410
  role: "assistant"
373
- };
411
+ });
374
412
  }
375
413
  const delta = event.delta.text;
376
414
  accumulatedContent += delta;
377
- yield {
415
+ yield asChunk({
378
416
  type: "TEXT_MESSAGE_CONTENT",
379
417
  messageId,
380
418
  model,
381
419
  timestamp,
382
420
  delta,
383
421
  content: accumulatedContent
384
- };
422
+ });
385
423
  } else if (event.delta.type === "thinking_delta") {
386
424
  const delta = event.delta.thinking;
387
425
  accumulatedThinking += delta;
388
- yield {
426
+ yield asChunk({
427
+ type: "REASONING_MESSAGE_CONTENT",
428
+ messageId: reasoningMessageId,
429
+ delta,
430
+ model,
431
+ timestamp
432
+ });
433
+ yield asChunk({
389
434
  type: "STEP_FINISHED",
435
+ stepName: stepId || genId(),
390
436
  stepId: stepId || genId(),
391
437
  model,
392
438
  timestamp,
393
439
  delta,
394
440
  content: accumulatedThinking
395
- };
441
+ });
396
442
  } else if (event.delta.type === "input_json_delta") {
397
443
  const existing = toolCallsMap.get(currentToolIndex);
398
444
  if (existing) {
399
445
  if (!existing.started) {
400
446
  existing.started = true;
401
- yield {
447
+ yield asChunk({
402
448
  type: "TOOL_CALL_START",
403
449
  toolCallId: existing.id,
450
+ toolCallName: existing.name,
404
451
  toolName: existing.name,
405
452
  model,
406
453
  timestamp,
407
454
  index: currentToolIndex
408
- };
455
+ });
409
456
  }
410
457
  existing.input += event.delta.partial_json;
411
- yield {
458
+ yield asChunk({
412
459
  type: "TOOL_CALL_ARGS",
413
460
  toolCallId: existing.id,
414
461
  model,
415
462
  timestamp,
416
463
  delta: event.delta.partial_json,
417
464
  args: existing.input
418
- };
465
+ });
419
466
  }
420
467
  }
421
468
  } else if (event.type === "content_block_stop") {
@@ -424,14 +471,15 @@ class AnthropicTextAdapter extends BaseTextAdapter {
424
471
  if (existing) {
425
472
  if (!existing.started) {
426
473
  existing.started = true;
427
- yield {
474
+ yield asChunk({
428
475
  type: "TOOL_CALL_START",
429
476
  toolCallId: existing.id,
477
+ toolCallName: existing.name,
430
478
  toolName: existing.name,
431
479
  model,
432
480
  timestamp,
433
481
  index: currentToolIndex
434
- };
482
+ });
435
483
  }
436
484
  let parsedInput = {};
437
485
  try {
@@ -440,45 +488,78 @@ class AnthropicTextAdapter extends BaseTextAdapter {
440
488
  } catch {
441
489
  parsedInput = {};
442
490
  }
443
- yield {
491
+ yield asChunk({
444
492
  type: "TOOL_CALL_END",
445
493
  toolCallId: existing.id,
494
+ toolCallName: existing.name,
446
495
  toolName: existing.name,
447
496
  model,
448
497
  timestamp,
449
498
  input: parsedInput
450
- };
499
+ });
451
500
  hasEmittedTextMessageStart = false;
452
501
  }
453
502
  } else {
454
503
  if (hasEmittedTextMessageStart && accumulatedContent) {
455
- yield {
504
+ yield asChunk({
456
505
  type: "TEXT_MESSAGE_END",
457
506
  messageId,
458
507
  model,
459
508
  timestamp
460
- };
509
+ });
461
510
  }
462
511
  }
463
512
  currentBlockType = null;
464
513
  } else if (event.type === "message_stop") {
514
+ if (reasoningMessageId && !hasClosedReasoning) {
515
+ hasClosedReasoning = true;
516
+ yield asChunk({
517
+ type: "REASONING_MESSAGE_END",
518
+ messageId: reasoningMessageId,
519
+ model,
520
+ timestamp
521
+ });
522
+ yield asChunk({
523
+ type: "REASONING_END",
524
+ messageId: reasoningMessageId,
525
+ model,
526
+ timestamp
527
+ });
528
+ }
465
529
  if (!hasEmittedRunFinished) {
466
- yield {
530
+ yield asChunk({
467
531
  type: "RUN_FINISHED",
468
532
  runId,
533
+ threadId,
469
534
  model,
470
535
  timestamp,
471
536
  finishReason: "stop"
472
- };
537
+ });
473
538
  }
474
539
  } else if (event.type === "message_delta") {
475
540
  if (event.delta.stop_reason) {
476
541
  hasEmittedRunFinished = true;
542
+ if (reasoningMessageId && !hasClosedReasoning) {
543
+ hasClosedReasoning = true;
544
+ yield asChunk({
545
+ type: "REASONING_MESSAGE_END",
546
+ messageId: reasoningMessageId,
547
+ model,
548
+ timestamp
549
+ });
550
+ yield asChunk({
551
+ type: "REASONING_END",
552
+ messageId: reasoningMessageId,
553
+ model,
554
+ timestamp
555
+ });
556
+ }
477
557
  switch (event.delta.stop_reason) {
478
558
  case "tool_use": {
479
- yield {
559
+ yield asChunk({
480
560
  type: "RUN_FINISHED",
481
561
  runId,
562
+ threadId,
482
563
  model,
483
564
  timestamp,
484
565
  finishReason: "tool_calls",
@@ -487,26 +568,29 @@ class AnthropicTextAdapter extends BaseTextAdapter {
487
568
  completionTokens: event.usage.output_tokens || 0,
488
569
  totalTokens: (event.usage.input_tokens || 0) + (event.usage.output_tokens || 0)
489
570
  }
490
- };
571
+ });
491
572
  break;
492
573
  }
493
574
  case "max_tokens": {
494
- yield {
575
+ yield asChunk({
495
576
  type: "RUN_ERROR",
496
577
  runId,
497
578
  model,
498
579
  timestamp,
580
+ message: "The response was cut off because the maximum token limit was reached.",
581
+ code: "max_tokens",
499
582
  error: {
500
583
  message: "The response was cut off because the maximum token limit was reached.",
501
584
  code: "max_tokens"
502
585
  }
503
- };
586
+ });
504
587
  break;
505
588
  }
506
589
  default: {
507
- yield {
590
+ yield asChunk({
508
591
  type: "RUN_FINISHED",
509
592
  runId,
593
+ threadId,
510
594
  model,
511
595
  timestamp,
512
596
  finishReason: "stop",
@@ -515,7 +599,7 @@ class AnthropicTextAdapter extends BaseTextAdapter {
515
599
  completionTokens: event.usage.output_tokens || 0,
516
600
  totalTokens: (event.usage.input_tokens || 0) + (event.usage.output_tokens || 0)
517
601
  }
518
- };
602
+ });
519
603
  }
520
604
  }
521
605
  }
@@ -523,16 +607,18 @@ class AnthropicTextAdapter extends BaseTextAdapter {
523
607
  }
524
608
  } catch (error) {
525
609
  const err = error;
526
- yield {
610
+ yield asChunk({
527
611
  type: "RUN_ERROR",
528
612
  runId,
529
613
  model,
530
614
  timestamp,
615
+ message: err.message || "Unknown error occurred",
616
+ code: err.code || String(err.status),
531
617
  error: {
532
618
  message: err.message || "Unknown error occurred",
533
619
  code: err.code || String(err.status)
534
620
  }
535
- };
621
+ });
536
622
  }
537
623
  }
538
624
  }
@@ -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 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/**\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\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 object = ResolveProviderOptions<TModel>,\n TInputModalities extends ReadonlyArray<Modality> =\n ResolveInputModalities<TModel>,\n> extends BaseTextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n AnthropicMessageMetadataByModality\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<AnthropicTextProviderOptions>,\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.model, () =>\n generateId(this.name),\n )\n } catch (error: unknown) {\n const err = error as Error & { status?: number; code?: string }\n yield {\n type: 'RUN_ERROR',\n model: options.model,\n timestamp: Date.now(),\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<AnthropicTextProviderOptions>,\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 model: string,\n genId: () => string,\n ): AsyncIterable<StreamChunk> {\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 = genId()\n const messageId = genId()\n let stepId: string | null = null\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 {\n type: 'RUN_STARTED',\n runId,\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 STEP_STARTED for thinking\n stepId = genId()\n yield {\n type: 'STEP_STARTED',\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 // Emit TEXT_MESSAGE_START on first text content\n if (!hasEmittedTextMessageStart) {\n hasEmittedTextMessageStart = true\n yield {\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 {\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 yield {\n type: 'STEP_FINISHED',\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 {\n type: 'TOOL_CALL_START',\n toolCallId: existing.id,\n toolName: existing.name,\n model,\n timestamp,\n index: currentToolIndex,\n }\n }\n\n existing.input += event.delta.partial_json\n\n yield {\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 {\n type: 'TOOL_CALL_START',\n toolCallId: existing.id,\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 {\n type: 'TOOL_CALL_END',\n toolCallId: existing.id,\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 {\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 // 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 {\n type: 'RUN_FINISHED',\n runId,\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 switch (event.delta.stop_reason) {\n case 'tool_use': {\n yield {\n type: 'RUN_FINISHED',\n runId,\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 {\n type: 'RUN_ERROR',\n runId,\n model,\n timestamp,\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 {\n type: 'RUN_FINISHED',\n runId,\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 {\n type: 'RUN_ERROR',\n runId,\n model,\n timestamp,\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 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\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 object = ResolveProviderOptions<TModel>,\n TInputModalities extends ReadonlyArray<Modality> =\n ResolveInputModalities<TModel>,\n> extends BaseTextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n AnthropicMessageMetadataByModality\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<AnthropicTextProviderOptions>,\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<AnthropicTextProviderOptions>,\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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"}