ai-sdk-provider-claude-code 2.0.2 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -79,7 +79,7 @@ import { streamText } from 'ai';
79
79
  import { claudeCode } from 'ai-sdk-provider-claude-code';
80
80
 
81
81
  const result = streamText({
82
- model: claudeCode('sonnet'),
82
+ model: claudeCode('haiku'),
83
83
  prompt: 'Hello, Claude!',
84
84
  });
85
85
 
@@ -94,7 +94,7 @@ import { generateText } from 'ai';
94
94
  import { claudeCode } from 'ai-sdk-provider-claude-code';
95
95
 
96
96
  const { text } = await generateText({
97
- model: claudeCode('sonnet'),
97
+ model: claudeCode('haiku'),
98
98
  prompt: 'Hello, Claude!',
99
99
  });
100
100
 
@@ -124,8 +124,9 @@ Key changes:
124
124
 
125
125
  ## Models
126
126
 
127
- - **`opus`** - Claude 4 Opus (most capable)
128
- - **`sonnet`** - Claude 4 Sonnet (balanced performance)
127
+ - **`opus`** - Claude 4.1 Opus (most capable)
128
+ - **`sonnet`** - Claude 4.5 Sonnet (balanced performance)
129
+ - **`haiku`** - Claude 4.5 Haiku (fastest, most cost-effective)
129
130
 
130
131
  ## Documentation
131
132
 
package/dist/index.cjs CHANGED
@@ -613,7 +613,7 @@ var claudeCodeSettingsSchema = import_zod.z.object({
613
613
  extraArgs: import_zod.z.record(import_zod.z.string(), import_zod.z.union([import_zod.z.string(), import_zod.z.null()])).optional()
614
614
  }).strict();
615
615
  function validateModelId(modelId) {
616
- const knownModels = ["opus", "sonnet"];
616
+ const knownModels = ["opus", "sonnet", "haiku"];
617
617
  if (!modelId || modelId.trim() === "") {
618
618
  throw new Error("Model ID cannot be empty");
619
619
  }
@@ -708,6 +708,81 @@ function getLogger(logger) {
708
708
 
709
709
  // src/claude-code-language-model.ts
710
710
  var import_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
711
+ var CLAUDE_CODE_TRUNCATION_WARNING = "Claude Code CLI output ended unexpectedly; returning truncated response from buffered text. Await upstream fix to avoid data loss.";
712
+ var MIN_TRUNCATION_LENGTH = 1024;
713
+ var POSITION_PATTERN = /position\s+(\d+)/i;
714
+ function hasUnclosedJsonStructure(text) {
715
+ let depth = 0;
716
+ let inString = false;
717
+ let escapeNext = false;
718
+ for (let i = 0; i < text.length; i++) {
719
+ const char = text[i];
720
+ if (escapeNext) {
721
+ escapeNext = false;
722
+ continue;
723
+ }
724
+ if (inString) {
725
+ if (char === "\\") {
726
+ escapeNext = true;
727
+ continue;
728
+ }
729
+ if (char === '"') {
730
+ inString = false;
731
+ }
732
+ continue;
733
+ }
734
+ if (char === '"') {
735
+ inString = true;
736
+ continue;
737
+ }
738
+ if (char === "{" || char === "[") {
739
+ depth++;
740
+ continue;
741
+ }
742
+ if (char === "}" || char === "]") {
743
+ if (depth > 0) {
744
+ depth--;
745
+ }
746
+ }
747
+ }
748
+ return depth > 0 || inString;
749
+ }
750
+ function isClaudeCodeTruncationError(error, bufferedText) {
751
+ if (!(error instanceof SyntaxError)) {
752
+ return false;
753
+ }
754
+ if (!bufferedText) {
755
+ return false;
756
+ }
757
+ const rawMessage = typeof error.message === "string" ? error.message : "";
758
+ const message = rawMessage.toLowerCase();
759
+ const truncationIndicators = [
760
+ "unexpected end of json input",
761
+ "unexpected end of input",
762
+ "unexpected end of string",
763
+ "unterminated string"
764
+ ];
765
+ if (!truncationIndicators.some((indicator) => message.includes(indicator))) {
766
+ return false;
767
+ }
768
+ const positionMatch = rawMessage.match(POSITION_PATTERN);
769
+ if (positionMatch) {
770
+ const position = Number.parseInt(positionMatch[1], 10);
771
+ if (Number.isFinite(position)) {
772
+ const isNearBufferEnd = Math.abs(position - bufferedText.length) <= 16;
773
+ if (isNearBufferEnd && position >= MIN_TRUNCATION_LENGTH) {
774
+ return true;
775
+ }
776
+ if (!isNearBufferEnd) {
777
+ return false;
778
+ }
779
+ }
780
+ }
781
+ if (bufferedText.length < MIN_TRUNCATION_LENGTH) {
782
+ return false;
783
+ }
784
+ return hasUnclosedJsonStructure(bufferedText);
785
+ }
711
786
  function isAbortError(err) {
712
787
  if (err && typeof err === "object") {
713
788
  const e = err;
@@ -737,7 +812,8 @@ function toAsyncIterablePrompt(messagesPrompt, outputStreamEnded, sessionId, con
737
812
  }
738
813
  var modelMap = {
739
814
  opus: "opus",
740
- sonnet: "sonnet"
815
+ sonnet: "sonnet",
816
+ haiku: "haiku"
741
817
  };
742
818
  var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
743
819
  specificationVersion = "v2";
@@ -1087,6 +1163,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1087
1163
  let text = "";
1088
1164
  let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
1089
1165
  let finishReason = "stop";
1166
+ let wasTruncated = false;
1090
1167
  let costUsd;
1091
1168
  let durationMs;
1092
1169
  let rawUsage;
@@ -1157,7 +1234,16 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1157
1234
  if (isAbortError(error)) {
1158
1235
  throw options.abortSignal?.aborted ? options.abortSignal.reason : error;
1159
1236
  }
1160
- throw this.handleClaudeCodeError(error, messagesPrompt);
1237
+ if (isClaudeCodeTruncationError(error, text)) {
1238
+ wasTruncated = true;
1239
+ finishReason = "length";
1240
+ warnings.push({
1241
+ type: "other",
1242
+ message: CLAUDE_CODE_TRUNCATION_WARNING
1243
+ });
1244
+ } else {
1245
+ throw this.handleClaudeCodeError(error, messagesPrompt);
1246
+ }
1161
1247
  } finally {
1162
1248
  if (options.abortSignal && abortListener) {
1163
1249
  options.abortSignal.removeEventListener("abort", abortListener);
@@ -1184,7 +1270,8 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1184
1270
  ...this.sessionId !== void 0 && { sessionId: this.sessionId },
1185
1271
  ...costUsd !== void 0 && { costUsd },
1186
1272
  ...durationMs !== void 0 && { durationMs },
1187
- ...rawUsage !== void 0 && { rawUsage }
1273
+ ...rawUsage !== void 0 && { rawUsage },
1274
+ ...wasTruncated && { truncated: true }
1188
1275
  }
1189
1276
  }
1190
1277
  };
@@ -1276,6 +1363,9 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1276
1363
  }
1277
1364
  toolStates.clear();
1278
1365
  };
1366
+ let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
1367
+ let accumulatedText = "";
1368
+ let textPartId;
1279
1369
  try {
1280
1370
  controller.enqueue({ type: "stream-start", warnings });
1281
1371
  if (this.settings.canUseTool && this.settings.permissionPromptToolName) {
@@ -1293,9 +1383,6 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1293
1383
  prompt: sdkPrompt,
1294
1384
  options: queryOptions
1295
1385
  });
1296
- let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
1297
- let accumulatedText = "";
1298
- let textPartId;
1299
1386
  for await (const message of response) {
1300
1387
  if (message.type === "assistant") {
1301
1388
  if (!message.message?.content) {
@@ -1545,6 +1632,71 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
1545
1632
  controller.close();
1546
1633
  } catch (error) {
1547
1634
  done();
1635
+ if (isClaudeCodeTruncationError(error, accumulatedText)) {
1636
+ const truncationWarning = {
1637
+ type: "other",
1638
+ message: CLAUDE_CODE_TRUNCATION_WARNING
1639
+ };
1640
+ streamWarnings.push(truncationWarning);
1641
+ const emitJsonText = () => {
1642
+ const extractedJson = this.handleJsonExtraction(accumulatedText, streamWarnings);
1643
+ const jsonTextId = (0, import_provider_utils.generateId)();
1644
+ controller.enqueue({
1645
+ type: "text-start",
1646
+ id: jsonTextId
1647
+ });
1648
+ controller.enqueue({
1649
+ type: "text-delta",
1650
+ id: jsonTextId,
1651
+ delta: extractedJson
1652
+ });
1653
+ controller.enqueue({
1654
+ type: "text-end",
1655
+ id: jsonTextId
1656
+ });
1657
+ };
1658
+ if (options.responseFormat?.type === "json") {
1659
+ emitJsonText();
1660
+ } else if (textPartId) {
1661
+ controller.enqueue({
1662
+ type: "text-end",
1663
+ id: textPartId
1664
+ });
1665
+ } else if (accumulatedText) {
1666
+ const fallbackTextId = (0, import_provider_utils.generateId)();
1667
+ controller.enqueue({
1668
+ type: "text-start",
1669
+ id: fallbackTextId
1670
+ });
1671
+ controller.enqueue({
1672
+ type: "text-delta",
1673
+ id: fallbackTextId,
1674
+ delta: accumulatedText
1675
+ });
1676
+ controller.enqueue({
1677
+ type: "text-end",
1678
+ id: fallbackTextId
1679
+ });
1680
+ }
1681
+ finalizeToolCalls();
1682
+ const warningsJson = this.serializeWarningsForMetadata(streamWarnings);
1683
+ controller.enqueue({
1684
+ type: "finish",
1685
+ finishReason: "length",
1686
+ usage,
1687
+ providerMetadata: {
1688
+ "claude-code": {
1689
+ ...this.sessionId !== void 0 && { sessionId: this.sessionId },
1690
+ truncated: true,
1691
+ ...streamWarnings.length > 0 && {
1692
+ warnings: warningsJson
1693
+ }
1694
+ }
1695
+ }
1696
+ });
1697
+ controller.close();
1698
+ return;
1699
+ }
1548
1700
  finalizeToolCalls();
1549
1701
  let errorToEmit;
1550
1702
  if (isAbortError(error)) {