ai-sdk-provider-claude-code 0.2.1 → 1.0.0-beta.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/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { LanguageModelV1, ProviderV1, APICallError, LoadAPIKeyError } from '@ai-sdk/provider';
1
+ import { LanguageModelV2, ProviderV2, APICallError, LoadAPIKeyError } from '@ai-sdk/provider';
2
2
  import { PermissionMode, McpServerConfig } from '@anthropic-ai/claude-code';
3
3
 
4
4
  /**
@@ -25,7 +25,7 @@ interface Logger {
25
25
  error: (message: string) => void;
26
26
  }
27
27
  /**
28
- * Configuration settings for Claude Code CLI behavior.
28
+ * Configuration settings for Claude Code SDK behavior.
29
29
  * These settings control how the CLI executes, what permissions it has,
30
30
  * and which tools are available during conversations.
31
31
  *
@@ -42,7 +42,7 @@ interface Logger {
42
42
  */
43
43
  interface ClaudeCodeSettings {
44
44
  /**
45
- * Custom path to Claude Code CLI executable
45
+ * Custom path to Claude Code SDK executable
46
46
  * @default 'claude' (uses system PATH)
47
47
  */
48
48
  pathToClaudeCodeExecutable?: string;
@@ -179,9 +179,9 @@ interface ClaudeCodeLanguageModelOptions {
179
179
  */
180
180
  type ClaudeCodeModelId = 'opus' | 'sonnet' | (string & {});
181
181
  /**
182
- * Language model implementation for Claude Code CLI.
182
+ * Language model implementation for Claude Code SDK.
183
183
  * This class implements the AI SDK's LanguageModelV1 interface to provide
184
- * integration with Claude models through the Claude Code CLI.
184
+ * integration with Claude models through the Claude Code SDK.
185
185
  *
186
186
  * Features:
187
187
  * - Supports streaming and non-streaming generation
@@ -207,10 +207,11 @@ type ClaudeCodeModelId = 'opus' | 'sonnet' | (string & {});
207
207
  * });
208
208
  * ```
209
209
  */
210
- declare class ClaudeCodeLanguageModel implements LanguageModelV1 {
211
- readonly specificationVersion: "v1";
210
+ declare class ClaudeCodeLanguageModel implements LanguageModelV2 {
211
+ readonly specificationVersion: "v2";
212
212
  readonly defaultObjectGenerationMode: "json";
213
213
  readonly supportsImageUrls = false;
214
+ readonly supportedUrls: {};
214
215
  readonly supportsStructuredOutputs = false;
215
216
  readonly modelId: ClaudeCodeModelId;
216
217
  readonly settings: ClaudeCodeSettings;
@@ -226,8 +227,8 @@ declare class ClaudeCodeLanguageModel implements LanguageModelV1 {
226
227
  private handleClaudeCodeError;
227
228
  private setSessionId;
228
229
  private validateJsonExtraction;
229
- doGenerate(options: Parameters<LanguageModelV1['doGenerate']>[0]): Promise<Awaited<ReturnType<LanguageModelV1['doGenerate']>>>;
230
- doStream(options: Parameters<LanguageModelV1['doStream']>[0]): Promise<Awaited<ReturnType<LanguageModelV1['doStream']>>>;
230
+ doGenerate(options: Parameters<LanguageModelV2['doGenerate']>[0]): Promise<Awaited<ReturnType<LanguageModelV2['doGenerate']>>>;
231
+ doStream(options: Parameters<LanguageModelV2['doStream']>[0]): Promise<Awaited<ReturnType<LanguageModelV2['doStream']>>>;
231
232
  }
232
233
 
233
234
  /**
@@ -246,7 +247,7 @@ declare class ClaudeCodeLanguageModel implements LanguageModelV1 {
246
247
  * const languageModel = claudeCode.languageModel('opus', { maxTurns: 10 });
247
248
  * ```
248
249
  */
249
- interface ClaudeCodeProvider extends ProviderV1 {
250
+ interface ClaudeCodeProvider extends ProviderV2 {
250
251
  /**
251
252
  * Creates a language model instance for the specified model ID.
252
253
  * This is a shorthand for calling `languageModel()`.
@@ -255,7 +256,7 @@ interface ClaudeCodeProvider extends ProviderV1 {
255
256
  * @param settings - Optional settings to configure the model
256
257
  * @returns A language model instance
257
258
  */
258
- (modelId: ClaudeCodeModelId, settings?: ClaudeCodeSettings): LanguageModelV1;
259
+ (modelId: ClaudeCodeModelId, settings?: ClaudeCodeSettings): LanguageModelV2;
259
260
  /**
260
261
  * Creates a language model instance for text generation.
261
262
  *
@@ -263,7 +264,7 @@ interface ClaudeCodeProvider extends ProviderV1 {
263
264
  * @param settings - Optional settings to configure the model
264
265
  * @returns A language model instance
265
266
  */
266
- languageModel(modelId: ClaudeCodeModelId, settings?: ClaudeCodeSettings): LanguageModelV1;
267
+ languageModel(modelId: ClaudeCodeModelId, settings?: ClaudeCodeSettings): LanguageModelV2;
267
268
  /**
268
269
  * Alias for `languageModel()` to maintain compatibility with AI SDK patterns.
269
270
  *
@@ -271,7 +272,8 @@ interface ClaudeCodeProvider extends ProviderV1 {
271
272
  * @param settings - Optional settings to configure the model
272
273
  * @returns A language model instance
273
274
  */
274
- chat(modelId: ClaudeCodeModelId, settings?: ClaudeCodeSettings): LanguageModelV1;
275
+ chat(modelId: ClaudeCodeModelId, settings?: ClaudeCodeSettings): LanguageModelV2;
276
+ imageModel(modelId: string): never;
275
277
  }
276
278
  /**
277
279
  * Configuration options for creating a Claude Code provider instance.
@@ -332,7 +334,7 @@ declare function createClaudeCode(options?: ClaudeCodeProviderSettings): ClaudeC
332
334
  declare const claudeCode: ClaudeCodeProvider;
333
335
 
334
336
  /**
335
- * Metadata associated with Claude Code CLI errors.
337
+ * Metadata associated with Claude Code SDK errors.
336
338
  * Provides additional context about command execution failures.
337
339
  */
338
340
  interface ClaudeCodeErrorMetadata {
@@ -341,7 +343,7 @@ interface ClaudeCodeErrorMetadata {
341
343
  */
342
344
  code?: string;
343
345
  /**
344
- * Exit code from the Claude Code CLI process.
346
+ * Exit code from the Claude Code SDK process.
345
347
  * Common codes:
346
348
  * - 401: Authentication error
347
349
  * - 1: General error
@@ -373,7 +375,7 @@ interface ClaudeCodeErrorMetadata {
373
375
  * @example
374
376
  * ```typescript
375
377
  * throw createAPICallError({
376
- * message: 'Claude Code CLI failed',
378
+ * message: 'Claude Code SDK failed',
377
379
  * code: 'ENOENT',
378
380
  * isRetryable: true
379
381
  * });
@@ -384,7 +386,7 @@ declare function createAPICallError({ message, code, exitCode, stderr, promptExc
384
386
  isRetryable?: boolean;
385
387
  }): APICallError;
386
388
  /**
387
- * Creates an authentication error for Claude Code CLI login failures.
389
+ * Creates an authentication error for Claude Code SDK login failures.
388
390
  *
389
391
  * @param options - Error configuration
390
392
  * @param options.message - Error message describing the authentication failure
@@ -401,7 +403,7 @@ declare function createAuthenticationError({ message, }: {
401
403
  message: string;
402
404
  }): LoadAPIKeyError;
403
405
  /**
404
- * Creates a timeout error for Claude Code CLI operations.
406
+ * Creates a timeout error for Claude Code SDK operations.
405
407
  *
406
408
  * @param options - Timeout error details
407
409
  * @param options.message - Error message describing the timeout
@@ -435,7 +437,7 @@ declare function createTimeoutError({ message, promptExcerpt, timeoutMs, }: {
435
437
  * await model.generate(...);
436
438
  * } catch (error) {
437
439
  * if (isAuthenticationError(error)) {
438
- * console.log('Please authenticate with Claude Code CLI');
440
+ * console.log('Please authenticate with Claude Code SDK');
439
441
  * }
440
442
  * }
441
443
  * ```
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { NoSuchModelError } from "@ai-sdk/provider";
6
6
  import { generateId } from "@ai-sdk/provider-utils";
7
7
 
8
8
  // src/convert-to-claude-code-messages.ts
9
- function convertToClaudeCodeMessages(prompt, mode) {
9
+ function convertToClaudeCodeMessages(prompt, mode = { type: "regular" }, jsonSchema) {
10
10
  const messages = [];
11
11
  const warnings = [];
12
12
  let systemPrompt;
@@ -25,26 +25,33 @@ function convertToClaudeCodeMessages(prompt, mode) {
25
25
  }
26
26
  const imageParts = message.content.filter((part) => part.type === "image");
27
27
  if (imageParts.length > 0) {
28
- warnings.push("Claude Code CLI does not support image inputs. Images will be ignored.");
28
+ warnings.push("Claude Code SDK does not support image inputs. Images will be ignored.");
29
29
  }
30
30
  }
31
31
  break;
32
- case "assistant":
32
+ case "assistant": {
33
+ let assistantContent = "";
33
34
  if (typeof message.content === "string") {
34
- messages.push(`Assistant: ${message.content}`);
35
+ assistantContent = message.content;
35
36
  } else {
36
37
  const textParts = message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
37
38
  if (textParts) {
38
- messages.push(`Assistant: ${textParts}`);
39
+ assistantContent = textParts;
39
40
  }
40
41
  const toolCalls = message.content.filter((part) => part.type === "tool-call");
41
42
  if (toolCalls.length > 0) {
42
- messages.push(`Assistant: [Tool calls made]`);
43
+ assistantContent += `
44
+ [Tool calls made]`;
43
45
  }
44
46
  }
47
+ messages.push(`Assistant: ${assistantContent}`);
45
48
  break;
49
+ }
46
50
  case "tool":
47
- messages.push(`Tool Result (${message.content[0].toolName}): ${JSON.stringify(message.content[0].result)}`);
51
+ for (const tool of message.content) {
52
+ const resultText = tool.output.type === "text" ? tool.output.value : JSON.stringify(tool.output.value);
53
+ messages.push(`Tool Result (${tool.toolName}): ${resultText}`);
54
+ }
48
55
  break;
49
56
  }
50
57
  }
@@ -69,19 +76,20 @@ function convertToClaudeCodeMessages(prompt, mode) {
69
76
  } else {
70
77
  finalPrompt = formattedMessages.join("\n\n");
71
78
  }
72
- if (mode?.type === "object-json") {
73
- finalPrompt = `${finalPrompt}
79
+ if (mode?.type === "object-json" && jsonSchema) {
80
+ const schemaStr = JSON.stringify(jsonSchema, null, 2);
81
+ finalPrompt = `CRITICAL: You MUST respond with ONLY a JSON object. NO other text, NO explanations, NO questions.
82
+
83
+ Your response MUST start with { and end with }
84
+
85
+ The JSON MUST match this EXACT schema:
86
+ ${schemaStr}
87
+
88
+ Now, based on the following conversation, generate ONLY the JSON object with the exact fields specified above:
74
89
 
75
- CRITICAL INSTRUCTION: You MUST respond with ONLY valid JSON. Follow these rules EXACTLY:
76
- 1. Start your response with an opening brace {
77
- 2. End your response with a closing brace }
78
- 3. Do NOT include any text before the opening brace
79
- 4. Do NOT include any text after the closing brace
80
- 5. Do NOT use markdown code blocks or backticks
81
- 6. Do NOT include explanations or commentary
82
- 7. The ENTIRE response must be valid JSON that can be parsed with JSON.parse()
90
+ ${finalPrompt}
83
91
 
84
- Begin your response with { and end with }`;
92
+ Remember: Your ENTIRE response must be ONLY the JSON object, starting with { and ending with }`;
85
93
  }
86
94
  return {
87
95
  messagesPrompt: finalPrompt,
@@ -205,7 +213,7 @@ function createAuthenticationError({
205
213
  message
206
214
  }) {
207
215
  return new LoadAPIKeyError({
208
- message: message || "Authentication failed. Please ensure Claude Code CLI is properly authenticated."
216
+ message: message || "Authentication failed. Please ensure Claude Code SDK is properly authenticated."
209
217
  });
210
218
  }
211
219
  function createTimeoutError({
@@ -398,9 +406,10 @@ var modelMap = {
398
406
  "sonnet": "sonnet"
399
407
  };
400
408
  var ClaudeCodeLanguageModel = class {
401
- specificationVersion = "v1";
409
+ specificationVersion = "v2";
402
410
  defaultObjectGenerationMode = "json";
403
411
  supportsImageUrls = false;
412
+ supportedUrls = {};
404
413
  supportsStructuredOutputs = false;
405
414
  modelId;
406
415
  settings;
@@ -435,7 +444,6 @@ var ClaudeCodeLanguageModel = class {
435
444
  const warnings = [];
436
445
  const unsupportedParams = [];
437
446
  if (options.temperature !== void 0) unsupportedParams.push("temperature");
438
- if (options.maxTokens !== void 0) unsupportedParams.push("maxTokens");
439
447
  if (options.topP !== void 0) unsupportedParams.push("topP");
440
448
  if (options.topK !== void 0) unsupportedParams.push("topK");
441
449
  if (options.presencePenalty !== void 0) unsupportedParams.push("presencePenalty");
@@ -447,7 +455,7 @@ var ClaudeCodeLanguageModel = class {
447
455
  warnings.push({
448
456
  type: "unsupported-setting",
449
457
  setting: param,
450
- details: `Claude Code CLI does not support the ${param} parameter. It will be ignored.`
458
+ details: `Claude Code SDK does not support the ${param} parameter. It will be ignored.`
451
459
  });
452
460
  }
453
461
  }
@@ -516,7 +524,7 @@ var ClaudeCodeLanguageModel = class {
516
524
  const isAuthError = authErrorPatterns.some((pattern) => errorMessage.includes(pattern)) || exitCode === 401;
517
525
  if (isAuthError) {
518
526
  return createAuthenticationError({
519
- message: isErrorWithMessage(error) && error.message ? error.message : "Authentication failed. Please ensure Claude Code CLI is properly authenticated."
527
+ message: isErrorWithMessage(error) && error.message ? error.message : "Authentication failed. Please ensure Claude Code SDK is properly authenticated."
520
528
  });
521
529
  }
522
530
  const errorCode = isErrorWithCode(error) && typeof error.code === "string" ? error.code : "";
@@ -530,7 +538,7 @@ var ClaudeCodeLanguageModel = class {
530
538
  }
531
539
  const isRetryable = errorCode === "ENOENT" || errorCode === "ECONNREFUSED" || errorCode === "ETIMEDOUT" || errorCode === "ECONNRESET";
532
540
  return createAPICallError({
533
- message: isErrorWithMessage(error) && error.message ? error.message : "Claude Code CLI error",
541
+ message: isErrorWithMessage(error) && error.message ? error.message : "Claude Code SDK error",
534
542
  code: errorCode || void 0,
535
543
  exitCode,
536
544
  stderr: isErrorWithCode(error) && typeof error.stderr === "string" ? error.stderr : void 0,
@@ -569,7 +577,12 @@ var ClaudeCodeLanguageModel = class {
569
577
  }
570
578
  }
571
579
  async doGenerate(options) {
572
- const { messagesPrompt, warnings: messageWarnings } = convertToClaudeCodeMessages(options.prompt, options.mode);
580
+ const mode = options.responseFormat?.type === "json" ? { type: "object-json" } : { type: "regular" };
581
+ const { messagesPrompt, warnings: messageWarnings } = convertToClaudeCodeMessages(
582
+ options.prompt,
583
+ mode,
584
+ options.responseFormat?.type === "json" ? options.responseFormat.schema : void 0
585
+ );
573
586
  const abortController = new AbortController();
574
587
  let abortListener;
575
588
  if (options.abortSignal) {
@@ -578,7 +591,7 @@ var ClaudeCodeLanguageModel = class {
578
591
  }
579
592
  const queryOptions = this.createQueryOptions(abortController);
580
593
  let text = "";
581
- let usage = { promptTokens: 0, completionTokens: 0 };
594
+ let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
582
595
  let finishReason = "stop";
583
596
  let costUsd;
584
597
  let durationMs;
@@ -609,8 +622,9 @@ var ClaudeCodeLanguageModel = class {
609
622
  if ("usage" in message) {
610
623
  rawUsage = message.usage;
611
624
  usage = {
612
- promptTokens: (message.usage.cache_creation_input_tokens ?? 0) + (message.usage.cache_read_input_tokens ?? 0) + (message.usage.input_tokens ?? 0),
613
- completionTokens: message.usage.output_tokens ?? 0
625
+ inputTokens: (message.usage.cache_creation_input_tokens ?? 0) + (message.usage.cache_read_input_tokens ?? 0) + (message.usage.input_tokens ?? 0),
626
+ outputTokens: message.usage.output_tokens ?? 0,
627
+ totalTokens: (message.usage.cache_creation_input_tokens ?? 0) + (message.usage.cache_read_input_tokens ?? 0) + (message.usage.input_tokens ?? 0) + (message.usage.output_tokens ?? 0)
614
628
  };
615
629
  }
616
630
  finishReason = mapClaudeCodeFinishReason(message.subtype);
@@ -628,7 +642,7 @@ var ClaudeCodeLanguageModel = class {
628
642
  options.abortSignal.removeEventListener("abort", abortListener);
629
643
  }
630
644
  }
631
- if (options.mode?.type === "object-json" && text) {
645
+ if (options.responseFormat?.type === "json" && text) {
632
646
  const extracted = extractJson(text);
633
647
  const validation = this.validateJsonExtraction(text, extracted);
634
648
  if (!validation.valid && validation.warning) {
@@ -637,14 +651,10 @@ var ClaudeCodeLanguageModel = class {
637
651
  text = extracted;
638
652
  }
639
653
  return {
640
- text: text || void 0,
654
+ content: [{ type: "text", text }],
641
655
  usage,
642
656
  finishReason,
643
- rawCall: {
644
- rawPrompt: messagesPrompt,
645
- rawSettings: queryOptions
646
- },
647
- warnings: warnings.length > 0 ? warnings : void 0,
657
+ warnings,
648
658
  response: {
649
659
  id: generateId(),
650
660
  timestamp: /* @__PURE__ */ new Date(),
@@ -664,7 +674,12 @@ var ClaudeCodeLanguageModel = class {
664
674
  };
665
675
  }
666
676
  async doStream(options) {
667
- const { messagesPrompt, warnings: messageWarnings } = convertToClaudeCodeMessages(options.prompt, options.mode);
677
+ const mode = options.responseFormat?.type === "json" ? { type: "object-json" } : { type: "regular" };
678
+ const { messagesPrompt, warnings: messageWarnings } = convertToClaudeCodeMessages(
679
+ options.prompt,
680
+ mode,
681
+ options.responseFormat?.type === "json" ? options.responseFormat.schema : void 0
682
+ );
668
683
  const abortController = new AbortController();
669
684
  let abortListener;
670
685
  if (options.abortSignal) {
@@ -684,21 +699,31 @@ var ClaudeCodeLanguageModel = class {
684
699
  const stream = new ReadableStream({
685
700
  start: async (controller) => {
686
701
  try {
702
+ controller.enqueue({ type: "stream-start", warnings });
687
703
  const response = query({
688
704
  prompt: messagesPrompt,
689
705
  options: queryOptions
690
706
  });
691
- let usage = { promptTokens: 0, completionTokens: 0 };
707
+ let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
692
708
  let accumulatedText = "";
709
+ let textPartId;
693
710
  for await (const message of response) {
694
711
  if (message.type === "assistant") {
695
712
  const text = message.message.content.map((c) => c.type === "text" ? c.text : "").join("");
696
713
  if (text) {
697
714
  accumulatedText += text;
698
- if (options.mode?.type !== "object-json") {
715
+ if (options.responseFormat?.type !== "json") {
716
+ if (!textPartId) {
717
+ textPartId = generateId();
718
+ controller.enqueue({
719
+ type: "text-start",
720
+ id: textPartId
721
+ });
722
+ }
699
723
  controller.enqueue({
700
724
  type: "text-delta",
701
- textDelta: text
725
+ id: textPartId,
726
+ delta: text
702
727
  });
703
728
  }
704
729
  }
@@ -707,18 +732,34 @@ var ClaudeCodeLanguageModel = class {
707
732
  if ("usage" in message) {
708
733
  rawUsage = message.usage;
709
734
  usage = {
710
- promptTokens: (message.usage.cache_creation_input_tokens ?? 0) + (message.usage.cache_read_input_tokens ?? 0) + (message.usage.input_tokens ?? 0),
711
- completionTokens: message.usage.output_tokens ?? 0
735
+ inputTokens: (message.usage.cache_creation_input_tokens ?? 0) + (message.usage.cache_read_input_tokens ?? 0) + (message.usage.input_tokens ?? 0),
736
+ outputTokens: message.usage.output_tokens ?? 0,
737
+ totalTokens: (message.usage.cache_creation_input_tokens ?? 0) + (message.usage.cache_read_input_tokens ?? 0) + (message.usage.input_tokens ?? 0) + (message.usage.output_tokens ?? 0)
712
738
  };
713
739
  }
714
740
  const finishReason = mapClaudeCodeFinishReason(message.subtype);
715
741
  this.setSessionId(message.session_id);
716
- if (options.mode?.type === "object-json" && accumulatedText) {
742
+ if (options.responseFormat?.type === "json" && accumulatedText) {
717
743
  const extractedJson = extractJson(accumulatedText);
718
744
  this.validateJsonExtraction(accumulatedText, extractedJson);
745
+ const jsonTextId = generateId();
746
+ controller.enqueue({
747
+ type: "text-start",
748
+ id: jsonTextId
749
+ });
719
750
  controller.enqueue({
720
751
  type: "text-delta",
721
- textDelta: extractedJson
752
+ id: jsonTextId,
753
+ delta: extractedJson
754
+ });
755
+ controller.enqueue({
756
+ type: "text-end",
757
+ id: jsonTextId
758
+ });
759
+ } else if (textPartId) {
760
+ controller.enqueue({
761
+ type: "text-end",
762
+ id: textPartId
722
763
  });
723
764
  }
724
765
  controller.enqueue({
@@ -771,11 +812,6 @@ var ClaudeCodeLanguageModel = class {
771
812
  });
772
813
  return {
773
814
  stream,
774
- rawCall: {
775
- rawPrompt: messagesPrompt,
776
- rawSettings: queryOptions
777
- },
778
- warnings: warnings.length > 0 ? warnings : void 0,
779
815
  request: {
780
816
  body: messagesPrompt
781
817
  }
@@ -826,6 +862,12 @@ function createClaudeCode(options = {}) {
826
862
  modelType: "textEmbeddingModel"
827
863
  });
828
864
  };
865
+ provider.imageModel = (modelId) => {
866
+ throw new NoSuchModelError2({
867
+ modelId,
868
+ modelType: "imageModel"
869
+ });
870
+ };
829
871
  return provider;
830
872
  }
831
873
  var claudeCode = createClaudeCode();