ai-sdk-provider-claude-code 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,8 +17,8 @@
17
17
 
18
18
  | Provider Version | AI SDK Version | NPM Tag | Status | Branch |
19
19
  |-----------------|----------------|---------|---------|--------|
20
- | 1.x | v5 | `latest` | Stable | `main` |
21
- | 0.x | v4 | `ai-sdk-v4` | Maintenance | [`ai-sdk-v4`](https://github.com/ben-vargas/ai-sdk-provider-claude-code/tree/ai-sdk-v4) |
20
+ | 1.x.x | v5 | `latest` | Stable | `main` |
21
+ | 0.x.x | v4 | `ai-sdk-v4` | Maintenance | [`ai-sdk-v4`](https://github.com/ben-vargas/ai-sdk-provider-claude-code/tree/ai-sdk-v4) |
22
22
 
23
23
  ### Installing the Right Version
24
24
 
@@ -119,12 +119,14 @@ Key changes:
119
119
  - 🎯 Object generation with JSON schemas
120
120
  - 🛑 AbortSignal support
121
121
  - 🔧 Tool management (MCP servers, permissions)
122
+ - 🧩 Callbacks (hooks, canUseTool)
122
123
 
123
124
  ## Limitations
124
125
 
125
126
  - Requires Node.js ≥ 18
126
127
  - No image support
127
128
  - Some AI SDK parameters unsupported (temperature, maxTokens, etc.)
129
+ - `canUseTool` requires streaming input at the SDK level (AsyncIterable prompt). This provider supports it via `streamingInput`: use `'auto'` (default when `canUseTool` is set) or `'always'`. See GUIDE for details.
128
130
 
129
131
  ## Contributing
130
132
 
@@ -140,4 +142,4 @@ For development status and technical details, see [Development Status](docs/ai-s
140
142
 
141
143
  ## License
142
144
 
143
- MIT
145
+ MIT
package/dist/index.cjs CHANGED
@@ -25,10 +25,13 @@ __export(index_exports, {
25
25
  createAPICallError: () => createAPICallError,
26
26
  createAuthenticationError: () => createAuthenticationError,
27
27
  createClaudeCode: () => createClaudeCode,
28
+ createCustomMcpServer: () => createCustomMcpServer,
29
+ createSdkMcpServer: () => import_claude_code3.createSdkMcpServer,
28
30
  createTimeoutError: () => createTimeoutError,
29
31
  getErrorMetadata: () => getErrorMetadata,
30
32
  isAuthenticationError: () => isAuthenticationError,
31
- isTimeoutError: () => isTimeoutError
33
+ isTimeoutError: () => isTimeoutError,
34
+ tool: () => import_claude_code3.tool
32
35
  });
33
36
  module.exports = __toCommonJS(index_exports);
34
37
 
@@ -82,9 +85,9 @@ function convertToClaudeCodeMessages(prompt, mode = { type: "regular" }, jsonSch
82
85
  break;
83
86
  }
84
87
  case "tool":
85
- for (const tool of message.content) {
86
- const resultText = tool.output.type === "text" ? tool.output.value : JSON.stringify(tool.output.value);
87
- messages.push(`Tool Result (${tool.toolName}): ${resultText}`);
88
+ for (const tool3 of message.content) {
89
+ const resultText = tool3.output.type === "text" ? tool3.output.value : JSON.stringify(tool3.output.value);
90
+ messages.push(`Tool Result (${tool3.toolName}): ${resultText}`);
88
91
  }
89
92
  break;
90
93
  }
@@ -331,6 +334,15 @@ var claudeCodeSettingsSchema = import_zod.z.object({
331
334
  resume: import_zod.z.string().optional(),
332
335
  allowedTools: import_zod.z.array(import_zod.z.string()).optional(),
333
336
  disallowedTools: import_zod.z.array(import_zod.z.string()).optional(),
337
+ streamingInput: import_zod.z.enum(["auto", "always", "off"]).optional(),
338
+ // Hooks and tool-permission callback (permissive validation of shapes)
339
+ canUseTool: import_zod.z.any().refine((v) => v === void 0 || typeof v === "function", {
340
+ message: "canUseTool must be a function"
341
+ }).optional(),
342
+ hooks: import_zod.z.record(import_zod.z.string(), import_zod.z.array(import_zod.z.object({
343
+ matcher: import_zod.z.string().optional(),
344
+ hooks: import_zod.z.array(import_zod.z.any()).nonempty()
345
+ }))).optional(),
334
346
  mcpServers: import_zod.z.record(import_zod.z.string(), import_zod.z.union([
335
347
  // McpStdioServerConfig
336
348
  import_zod.z.object({
@@ -344,6 +356,18 @@ var claudeCodeSettingsSchema = import_zod.z.object({
344
356
  type: import_zod.z.literal("sse"),
345
357
  url: import_zod.z.string(),
346
358
  headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional()
359
+ }),
360
+ // McpHttpServerConfig
361
+ import_zod.z.object({
362
+ type: import_zod.z.literal("http"),
363
+ url: import_zod.z.string(),
364
+ headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional()
365
+ }),
366
+ // McpSdkServerConfig (in-process custom tools)
367
+ import_zod.z.object({
368
+ type: import_zod.z.literal("sdk"),
369
+ name: import_zod.z.string(),
370
+ instance: import_zod.z.any()
347
371
  })
348
372
  ])).optional(),
349
373
  verbose: import_zod.z.boolean().optional(),
@@ -387,9 +411,9 @@ function validateSettings(settings) {
387
411
  warnings.push("Both allowedTools and disallowedTools are specified. Only allowedTools will be used.");
388
412
  }
389
413
  const validateToolNames = (tools, type) => {
390
- tools.forEach((tool) => {
391
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*(\([^)]*\))?$/.test(tool) && !tool.startsWith("mcp__")) {
392
- warnings.push(`Unusual ${type} tool name format: '${tool}'`);
414
+ tools.forEach((tool3) => {
415
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*(\([^)]*\))?$/.test(tool3) && !tool3.startsWith("mcp__")) {
416
+ warnings.push(`Unusual ${type} tool name format: '${tool3}'`);
393
417
  }
394
418
  });
395
419
  };
@@ -442,6 +466,30 @@ function getLogger(logger) {
442
466
 
443
467
  // src/claude-code-language-model.ts
444
468
  var import_claude_code = require("@anthropic-ai/claude-code");
469
+ function isAbortError(err) {
470
+ if (err && typeof err === "object") {
471
+ const e = err;
472
+ if (typeof e.name === "string" && e.name === "AbortError") return true;
473
+ if (typeof e.code === "string" && e.code.toUpperCase() === "ABORT_ERR") return true;
474
+ }
475
+ return false;
476
+ }
477
+ function toAsyncIterablePrompt(messagesPrompt, sessionId) {
478
+ const msg = {
479
+ type: "user",
480
+ message: {
481
+ role: "user",
482
+ content: [{ type: "text", text: messagesPrompt }]
483
+ },
484
+ parent_tool_use_id: null,
485
+ session_id: sessionId ?? ""
486
+ };
487
+ return {
488
+ async *[Symbol.asyncIterator]() {
489
+ yield msg;
490
+ }
491
+ };
492
+ }
445
493
  var modelMap = {
446
494
  "opus": "opus",
447
495
  "sonnet": "sonnet"
@@ -522,7 +570,7 @@ var ClaudeCodeLanguageModel = class {
522
570
  return warnings;
523
571
  }
524
572
  createQueryOptions(abortController) {
525
- return {
573
+ const opts = {
526
574
  model: this.getModel(),
527
575
  abortController,
528
576
  resume: this.settings.resume ?? this.sessionId,
@@ -539,11 +587,16 @@ var ClaudeCodeLanguageModel = class {
539
587
  continue: this.settings.continue,
540
588
  allowedTools: this.settings.allowedTools,
541
589
  disallowedTools: this.settings.disallowedTools,
542
- mcpServers: this.settings.mcpServers
590
+ mcpServers: this.settings.mcpServers,
591
+ canUseTool: this.settings.canUseTool
543
592
  };
593
+ if (this.settings.hooks) {
594
+ opts.hooks = this.settings.hooks;
595
+ }
596
+ return opts;
544
597
  }
545
598
  handleClaudeCodeError(error, messagesPrompt) {
546
- if (error instanceof import_claude_code.AbortError) {
599
+ if (isAbortError(error)) {
547
600
  throw error;
548
601
  }
549
602
  const isErrorWithMessage = (err) => {
@@ -626,8 +679,10 @@ var ClaudeCodeLanguageModel = class {
626
679
  );
627
680
  const abortController = new AbortController();
628
681
  let abortListener;
629
- if (options.abortSignal) {
630
- abortListener = () => abortController.abort();
682
+ if (options.abortSignal?.aborted) {
683
+ abortController.abort(options.abortSignal.reason);
684
+ } else if (options.abortSignal) {
685
+ abortListener = () => abortController.abort(options.abortSignal?.reason);
631
686
  options.abortSignal.addEventListener("abort", abortListener, { once: true });
632
687
  }
633
688
  const queryOptions = this.createQueryOptions(abortController);
@@ -647,8 +702,14 @@ var ClaudeCodeLanguageModel = class {
647
702
  });
648
703
  }
649
704
  try {
705
+ const modeSetting = this.settings.streamingInput ?? "auto";
706
+ const wantsStream = modeSetting === "always" || modeSetting === "auto" && !!this.settings.canUseTool;
707
+ if (this.settings.canUseTool && this.settings.permissionPromptToolName) {
708
+ throw new Error("canUseTool requires streamingInput mode ('auto' or 'always') and cannot be used with permissionPromptToolName (SDK constraint). Set streamingInput: 'auto' (or 'always') and remove permissionPromptToolName, or remove canUseTool.");
709
+ }
710
+ const sdkPrompt = wantsStream ? toAsyncIterablePrompt(messagesPrompt, this.settings.resume ?? this.sessionId) : messagesPrompt;
650
711
  const response = (0, import_claude_code.query)({
651
- prompt: messagesPrompt,
712
+ prompt: sdkPrompt,
652
713
  options: queryOptions
653
714
  });
654
715
  for await (const message of response) {
@@ -674,7 +735,7 @@ var ClaudeCodeLanguageModel = class {
674
735
  }
675
736
  }
676
737
  } catch (error) {
677
- if (error instanceof import_claude_code.AbortError) {
738
+ if (isAbortError(error)) {
678
739
  throw options.abortSignal?.aborted ? options.abortSignal.reason : error;
679
740
  }
680
741
  throw this.handleClaudeCodeError(error, messagesPrompt);
@@ -723,8 +784,10 @@ var ClaudeCodeLanguageModel = class {
723
784
  );
724
785
  const abortController = new AbortController();
725
786
  let abortListener;
726
- if (options.abortSignal) {
727
- abortListener = () => abortController.abort();
787
+ if (options.abortSignal?.aborted) {
788
+ abortController.abort(options.abortSignal.reason);
789
+ } else if (options.abortSignal) {
790
+ abortListener = () => abortController.abort(options.abortSignal?.reason);
728
791
  options.abortSignal.addEventListener("abort", abortListener, { once: true });
729
792
  }
730
793
  const queryOptions = this.createQueryOptions(abortController);
@@ -741,8 +804,14 @@ var ClaudeCodeLanguageModel = class {
741
804
  start: async (controller) => {
742
805
  try {
743
806
  controller.enqueue({ type: "stream-start", warnings });
807
+ const modeSetting = this.settings.streamingInput ?? "auto";
808
+ const wantsStream = modeSetting === "always" || modeSetting === "auto" && !!this.settings.canUseTool;
809
+ if (this.settings.canUseTool && this.settings.permissionPromptToolName) {
810
+ throw new Error("canUseTool requires streamingInput mode ('auto' or 'always') and cannot be used with permissionPromptToolName (SDK constraint). Set streamingInput: 'auto' (or 'always') and remove permissionPromptToolName, or remove canUseTool.");
811
+ }
812
+ const sdkPrompt = wantsStream ? toAsyncIterablePrompt(messagesPrompt, this.settings.resume ?? this.sessionId) : messagesPrompt;
744
813
  const response = (0, import_claude_code.query)({
745
- prompt: messagesPrompt,
814
+ prompt: sdkPrompt,
746
815
  options: queryOptions
747
816
  });
748
817
  let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
@@ -829,7 +898,7 @@ var ClaudeCodeLanguageModel = class {
829
898
  controller.close();
830
899
  } catch (error) {
831
900
  let errorToEmit;
832
- if (error instanceof import_claude_code.AbortError) {
901
+ if (isAbortError(error)) {
833
902
  errorToEmit = options.abortSignal?.aborted ? options.abortSignal.reason : error;
834
903
  } else {
835
904
  errorToEmit = this.handleClaudeCodeError(error, messagesPrompt);
@@ -912,6 +981,24 @@ function createClaudeCode(options = {}) {
912
981
  return provider;
913
982
  }
914
983
  var claudeCode = createClaudeCode();
984
+
985
+ // src/index.ts
986
+ var import_claude_code3 = require("@anthropic-ai/claude-code");
987
+
988
+ // src/mcp-helpers.ts
989
+ var import_claude_code2 = require("@anthropic-ai/claude-code");
990
+ var import_zod2 = require("zod");
991
+ function createCustomMcpServer(config) {
992
+ const defs = Object.entries(config.tools).map(
993
+ ([name, def]) => (0, import_claude_code2.tool)(
994
+ name,
995
+ def.description,
996
+ def.inputSchema.shape,
997
+ (args, extra) => def.handler(args, extra)
998
+ )
999
+ );
1000
+ return (0, import_claude_code2.createSdkMcpServer)({ name: config.name, version: config.version, tools: defs });
1001
+ }
915
1002
  // Annotate the CommonJS export names for ESM import in node:
916
1003
  0 && (module.exports = {
917
1004
  ClaudeCodeLanguageModel,
@@ -919,9 +1006,12 @@ var claudeCode = createClaudeCode();
919
1006
  createAPICallError,
920
1007
  createAuthenticationError,
921
1008
  createClaudeCode,
1009
+ createCustomMcpServer,
1010
+ createSdkMcpServer,
922
1011
  createTimeoutError,
923
1012
  getErrorMetadata,
924
1013
  isAuthenticationError,
925
- isTimeoutError
1014
+ isTimeoutError,
1015
+ tool
926
1016
  });
927
1017
  //# sourceMappingURL=index.cjs.map