ai-sdk-provider-claude-code 4.0.0 → 4.0.1

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
@@ -706,6 +706,23 @@ All requests made through this provider report timing in `finalStep.providerMeta
706
706
  - When replaying conversation history through the prompt, assistant tool calls are serialized as text lines — `[Tool call: Read({"file_path":"/x"})]` (inputs truncated at 1000 characters) — paired with `Tool Result (Read): ...` lines for tool messages
707
707
  - `canUseTool` requires streaming input at the SDK level (AsyncIterable prompt), and image prompts use the same path. This provider supports it via `streamingInput`: use `'auto'` (streams when `canUseTool` is set or image parts are present), `'always'`, or `'off'` (`'off'` disables streaming image input, emits a generic `type: 'other'` image streaming-input warning, and omits image parts). See GUIDE for details.
708
708
 
709
+ ## Error Diagnostics
710
+
711
+ Mapped errors from this provider append a trimmed stderr tail to the error message as `... | stderr (tail): <last lines>`, making CLI failures visible in logs without inspecting metadata.
712
+
713
+ ```ts
714
+ import { generateText } from 'ai';
715
+ import { claudeCode, getErrorMetadata } from 'ai-sdk-provider-claude-code';
716
+
717
+ try {
718
+ await generateText({ model: claudeCode('sonnet'), prompt: 'Hello!' });
719
+ } catch (error) {
720
+ console.error(getErrorMetadata(error)?.stderr);
721
+ }
722
+ ```
723
+
724
+ The metadata accessor returns the full captured stderr, capped at 4000 characters. Authentication and timeout failures are also classified when the only evidence is in stderr, using high-precision matching to avoid false positives from unrelated stderr output.
725
+
709
726
  ## Tool Error Parity (Streaming)
710
727
 
711
728
  - AI SDK v7 represents failed tool executions with the standard `tool-result` stream event/part and `isError: true`.
package/dist/index.d.ts CHANGED
@@ -1428,8 +1428,9 @@ declare function createAPICallError({ message, code, exitCode, stderr, promptExc
1428
1428
  * });
1429
1429
  * ```
1430
1430
  */
1431
- declare function createAuthenticationError({ message }: {
1431
+ declare function createAuthenticationError({ message, stderr, }: {
1432
1432
  message: string;
1433
+ stderr?: string;
1433
1434
  }): LoadAPIKeyError;
1434
1435
  /**
1435
1436
  * Creates a timeout error for Claude Code SDK operations.
@@ -1448,8 +1449,9 @@ declare function createAuthenticationError({ message }: {
1448
1449
  * });
1449
1450
  * ```
1450
1451
  */
1451
- declare function createTimeoutError({ message, promptExcerpt, timeoutMs, }: {
1452
+ declare function createTimeoutError({ message, stderr, promptExcerpt, timeoutMs, }: {
1452
1453
  message: string;
1454
+ stderr?: string;
1453
1455
  promptExcerpt?: string;
1454
1456
  timeoutMs?: number;
1455
1457
  }): APICallError;
package/dist/index.js CHANGED
@@ -488,6 +488,21 @@ ${segmentText}`;
488
488
 
489
489
  // src/errors.ts
490
490
  import { APICallError, LoadAPIKeyError } from "@ai-sdk/provider";
491
+ var STDERR_TAIL_MARKER = " | stderr (tail):";
492
+ var ANSI_ESCAPE_SEQUENCE = (
493
+ // eslint-disable-next-line no-control-regex
494
+ /\x1b(?:\][^\x07\x1b]*(?:\x07|\x1b\\)|\[[0-?]*[ -/]*[@-~])/g
495
+ );
496
+ function stderrTail(raw) {
497
+ const withoutAnsi = raw.replace(ANSI_ESCAPE_SEQUENCE, "");
498
+ const withoutControlCharacters = Array.from(withoutAnsi).filter((character) => {
499
+ const codePoint = character.codePointAt(0) ?? 0;
500
+ return character === "\r" || character === "\n" || codePoint === 8232 || codePoint === 8233 || codePoint >= 32 && codePoint < 127 || codePoint > 159;
501
+ }).join("");
502
+ const tail = withoutControlCharacters.split(/\r\n|\r|\n|\u2028|\u2029/).map((line) => line.trim()).filter((line) => line.length > 0).slice(-5).join("; ");
503
+ const codePoints = Array.from(tail);
504
+ return codePoints.length > 600 ? `\u2026${codePoints.slice(-599).join("")}` : tail;
505
+ }
491
506
  function createAPICallError({
492
507
  message,
493
508
  code,
@@ -502,26 +517,37 @@ function createAPICallError({
502
517
  stderr,
503
518
  promptExcerpt
504
519
  };
520
+ const tail = typeof stderr === "string" && stderr.length > 0 ? stderrTail(stderr) : "";
521
+ const enrichedMessage = tail && !message.includes(STDERR_TAIL_MARKER) ? `${message}${STDERR_TAIL_MARKER} ${tail}` : message;
505
522
  return new APICallError({
506
- message,
523
+ message: enrichedMessage,
507
524
  isRetryable,
508
525
  url: "claude-code-cli://command",
509
526
  requestBodyValues: promptExcerpt ? { prompt: promptExcerpt } : void 0,
510
527
  data: metadata
511
528
  });
512
529
  }
513
- function createAuthenticationError({ message }) {
514
- return new LoadAPIKeyError({
530
+ function createAuthenticationError({
531
+ message,
532
+ stderr
533
+ }) {
534
+ const error = new LoadAPIKeyError({
515
535
  message: message || "Authentication failed. Please ensure Claude Code SDK is properly authenticated."
516
536
  });
537
+ if (stderr) {
538
+ error.data = { stderr };
539
+ }
540
+ return error;
517
541
  }
518
542
  function createTimeoutError({
519
543
  message,
544
+ stderr,
520
545
  promptExcerpt,
521
546
  timeoutMs
522
547
  }) {
523
548
  const metadata = {
524
549
  code: "TIMEOUT",
550
+ stderr,
525
551
  promptExcerpt
526
552
  };
527
553
  return new APICallError({
@@ -547,6 +573,9 @@ function getErrorMetadata(error) {
547
573
  if (error instanceof APICallError && error.data) {
548
574
  return error.data;
549
575
  }
576
+ if (error instanceof LoadAPIKeyError && error.data) {
577
+ return error.data;
578
+ }
550
579
  return void 0;
551
580
  }
552
581
 
@@ -1177,10 +1206,16 @@ function createClaudeCodeQueryController(query2) {
1177
1206
 
1178
1207
  // src/claude-code-language-model.ts
1179
1208
  import { query } from "@anthropic-ai/claude-agent-sdk";
1180
- var PROVIDER_VERSION = "4.0.0";
1209
+ var PROVIDER_VERSION = "4.0.1";
1181
1210
  var DEFAULT_CLIENT_APP = `ai-sdk-provider-claude-code/${PROVIDER_VERSION}`;
1182
1211
  var CLAUDE_CODE_TRUNCATION_WARNING = "Claude Code SDK output ended unexpectedly; returning truncated response from buffered text. Await upstream fix to avoid data loss.";
1183
1212
  var MIN_TRUNCATION_LENGTH = 512;
1213
+ function capStderr(raw) {
1214
+ if (raw.length <= 4e3) {
1215
+ return raw;
1216
+ }
1217
+ return Array.from(raw).slice(-4e3).join("");
1218
+ }
1184
1219
  function isClaudeCodeTruncationError(error, bufferedText) {
1185
1220
  const isSyntaxError = error instanceof SyntaxError || // eslint-disable-next-line @typescript-eslint/no-explicit-any
1186
1221
  typeof error?.name === "string" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -2401,12 +2436,18 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2401
2436
  return opts;
2402
2437
  }
2403
2438
  handleClaudeCodeError(error, messagesPrompt, collectedStderr) {
2404
- if (isAbortError(error)) {
2405
- throw error;
2406
- }
2407
2439
  if (error instanceof APICallError2 || error instanceof LoadAPIKeyError2) {
2408
2440
  return error;
2409
2441
  }
2442
+ const rawSdkStderr = typeof error === "object" && error !== null && "stderr" in error && typeof error.stderr === "string" ? error.stderr : void 0;
2443
+ const cappedSdkStderr = rawSdkStderr !== void 0 ? capStderr(rawSdkStderr) : void 0;
2444
+ const selectedStderr = cappedSdkStderr !== void 0 && stderrTail(cappedSdkStderr) ? cappedSdkStderr : collectedStderr ? capStderr(collectedStderr) : void 0;
2445
+ const stderr = selectedStderr || void 0;
2446
+ const tail = stderr ? stderrTail(stderr) : "";
2447
+ const appendStderrTail = (message) => tail && !message.includes(STDERR_TAIL_MARKER) ? `${message}${STDERR_TAIL_MARKER} ${tail}` : message;
2448
+ if (isAbortError(error)) {
2449
+ throw error;
2450
+ }
2410
2451
  const isErrorWithMessage = (err) => {
2411
2452
  return typeof err === "object" && err !== null && "message" in err;
2412
2453
  };
@@ -2427,26 +2468,43 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2427
2468
  "oauth_org_not_allowed"
2428
2469
  // SDK 0.3.x assistant error kind: OAuth org not permitted
2429
2470
  ];
2471
+ const stderrAuthPatterns = [
2472
+ "not logged in",
2473
+ "not authenticated",
2474
+ "auth failed",
2475
+ "please login",
2476
+ "please run /login",
2477
+ "claude login",
2478
+ "claude auth login",
2479
+ "invalid api key",
2480
+ "oauth token revoked",
2481
+ "oauth_org_not_allowed"
2482
+ ];
2430
2483
  const errorMessage = isErrorWithMessage(error) && error.message ? error.message.toLowerCase() : "";
2484
+ const stderrMessage = stderr?.toLowerCase() ?? "";
2431
2485
  const errorKind = getStructuredErrorKind(error);
2432
2486
  const exitCode = isErrorWithCode(error) && typeof error.exitCode === "number" ? error.exitCode : void 0;
2433
- const isAuthError = errorKind === "authentication_failed" || errorKind === "oauth_org_not_allowed" || authErrorPatterns.some((pattern) => errorMessage.includes(pattern)) || exitCode === 401;
2487
+ const isAuthError = errorKind === "authentication_failed" || errorKind === "oauth_org_not_allowed" || authErrorPatterns.some((pattern) => errorMessage.includes(pattern)) || stderrAuthPatterns.some((pattern) => stderrMessage.includes(pattern)) || exitCode === 401;
2434
2488
  if (isAuthError) {
2435
2489
  return createAuthenticationError({
2436
- message: isErrorWithMessage(error) && error.message ? error.message : "Authentication failed. Please ensure Claude Code SDK is properly authenticated."
2490
+ message: appendStderrTail(
2491
+ isErrorWithMessage(error) && error.message ? error.message : "Authentication failed. Please ensure Claude Code SDK is properly authenticated."
2492
+ ),
2493
+ stderr
2437
2494
  });
2438
2495
  }
2439
2496
  const errorCode = isErrorWithCode(error) && typeof error.code === "string" ? error.code : "";
2440
- if (errorCode === "ETIMEDOUT" || errorMessage.includes("timeout")) {
2497
+ if (errorCode === "ETIMEDOUT" || errorMessage.includes("timeout") || /request timed out|etimedout/i.test(stderr ?? "")) {
2441
2498
  return createTimeoutError({
2442
- message: isErrorWithMessage(error) && error.message ? error.message : "Request timed out",
2499
+ message: appendStderrTail(
2500
+ isErrorWithMessage(error) && error.message ? error.message : "Request timed out"
2501
+ ),
2502
+ stderr,
2443
2503
  promptExcerpt: messagesPrompt.substring(0, 200)
2444
2504
  // Don't specify timeoutMs since we don't know the actual timeout value
2445
2505
  // It's controlled by the consumer via AbortSignal
2446
2506
  });
2447
2507
  }
2448
- const stderrFromError = isErrorWithCode(error) && typeof error.stderr === "string" ? error.stderr : void 0;
2449
- const stderr = stderrFromError || collectedStderr || void 0;
2450
2508
  if (errorKind === "overloaded" || errorKind === "rate_limit" || errorMessage.includes("overloaded")) {
2451
2509
  return createAPICallError({
2452
2510
  message: isErrorWithMessage(error) && error.message ? error.message : "Anthropic API is overloaded. Please retry.",
@@ -2822,6 +2880,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
2822
2880
  let collectedStderr = "";
2823
2881
  const stderrCollector = (data) => {
2824
2882
  collectedStderr += data;
2883
+ collectedStderr = capStderr(collectedStderr);
2825
2884
  };
2826
2885
  const sdkOptions = this.getSanitizedSdkOptions();
2827
2886
  const effectiveResume = this.getEffectiveResume(sdkOptions);
@@ -3322,6 +3381,7 @@ var ClaudeCodeLanguageModel = class _ClaudeCodeLanguageModel {
3322
3381
  let collectedStderr = "";
3323
3382
  const stderrCollector = (data) => {
3324
3383
  collectedStderr += data;
3384
+ collectedStderr = capStderr(collectedStderr);
3325
3385
  };
3326
3386
  const sdkOptions = this.getSanitizedSdkOptions();
3327
3387
  const effectiveResume = this.getEffectiveResume(sdkOptions);