ai-sdk-provider-claude-code 0.2.0

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/docs/GUIDE.md ADDED
@@ -0,0 +1,865 @@
1
+ # Usage Guide
2
+
3
+ ## Essential Examples
4
+
5
+ ### Streaming Responses
6
+
7
+ ```typescript
8
+ import { streamText } from 'ai';
9
+ import { claudeCode } from 'ai-sdk-provider-claude-code';
10
+
11
+ const result = await streamText({
12
+ model: claudeCode('sonnet'),
13
+ prompt: 'Write a haiku about programming',
14
+ });
15
+
16
+ for await (const chunk of result.textStream) {
17
+ process.stdout.write(chunk);
18
+ }
19
+ ```
20
+
21
+ ### Multi-turn Conversations
22
+
23
+ ```typescript
24
+ import { generateText } from 'ai';
25
+ import { claudeCode } from 'ai-sdk-provider-claude-code';
26
+
27
+ const messages = [];
28
+
29
+ // First turn
30
+ messages.push({ role: 'user', content: 'My name is Alice' });
31
+ const { text: response1 } = await generateText({
32
+ model: claudeCode('sonnet'),
33
+ messages,
34
+ });
35
+ messages.push({ role: 'assistant', content: response1 });
36
+
37
+ // Second turn - remembers context
38
+ messages.push({ role: 'user', content: 'What is my name?' });
39
+ const { text: response2 } = await generateText({
40
+ model: claudeCode('sonnet'),
41
+ messages,
42
+ });
43
+ console.log(response2); // "Alice"
44
+ ```
45
+
46
+ ### Object Generation with JSON Schema
47
+
48
+ ```typescript
49
+ import { generateObject } from 'ai';
50
+ import { claudeCode } from 'ai-sdk-provider-claude-code';
51
+ import { z } from 'zod';
52
+
53
+ const { object } = await generateObject({
54
+ model: claudeCode('sonnet'),
55
+ schema: z.object({
56
+ name: z.string().describe('Full name'),
57
+ age: z.number().describe('Age in years'),
58
+ email: z.string().email().describe('Email address'),
59
+ interests: z.array(z.string()).describe('List of hobbies'),
60
+ }),
61
+ prompt: 'Generate a profile for a software developer',
62
+ });
63
+
64
+ console.log(object);
65
+ // {
66
+ // name: "Alex Chen",
67
+ // age: 28,
68
+ // email: "alex.chen@example.com",
69
+ // interests: ["coding", "open source", "machine learning"]
70
+ // }
71
+ ```
72
+
73
+ ### Handling Long-Running Tasks
74
+
75
+ For complex tasks with Claude Opus 4's extended thinking, use AbortSignal with custom timeouts:
76
+
77
+ ```typescript
78
+ import { generateText } from 'ai';
79
+ import { claudeCode } from 'ai-sdk-provider-claude-code';
80
+
81
+ // Create a custom timeout
82
+ const controller = new AbortController();
83
+ const timeoutId = setTimeout(() => {
84
+ controller.abort(new Error('Request timeout after 10 minutes'));
85
+ }, 600000); // 10 minutes
86
+
87
+ try {
88
+ const { text } = await generateText({
89
+ model: claudeCode('opus'),
90
+ prompt: 'Analyze this complex problem in detail...',
91
+ abortSignal: controller.signal,
92
+ });
93
+
94
+ clearTimeout(timeoutId);
95
+ console.log(text);
96
+ } catch (error) {
97
+ if (error.name === 'AbortError') {
98
+ console.log('Request was cancelled');
99
+ }
100
+ }
101
+ ```
102
+
103
+
104
+ ### Session Management (Experimental)
105
+
106
+ ```typescript
107
+ import { generateText } from 'ai';
108
+ import { claudeCode } from 'ai-sdk-provider-claude-code';
109
+
110
+ // First message
111
+ const { text, providerMetadata } = await generateText({
112
+ model: claudeCode('sonnet'),
113
+ messages: [{ role: 'user', content: 'My name is Bob.' }],
114
+ });
115
+
116
+ // Resume using the session ID
117
+ const sessionId = providerMetadata?.['claude-code']?.sessionId;
118
+
119
+ const { text: response } = await generateText({
120
+ model: claudeCode('sonnet', { resume: sessionId }),
121
+ messages: [{ role: 'user', content: 'What is my name?' }],
122
+ });
123
+ ```
124
+
125
+ `resume` continues a previous CLI session instead of starting a new one.
126
+
127
+ ---
128
+
129
+ ## Detailed Configuration
130
+
131
+ ### AbortSignal Support
132
+
133
+ The provider fully supports the standard AbortSignal for request cancellation, following Vercel AI SDK patterns:
134
+
135
+ ```typescript
136
+ import { generateText } from 'ai';
137
+ import { claudeCode } from 'ai-sdk-provider-claude-code';
138
+
139
+ // Using AbortController for cancellation
140
+ const controller = new AbortController();
141
+
142
+ // Cancel after user action
143
+ button.addEventListener('click', () => {
144
+ controller.abort();
145
+ });
146
+
147
+ const { text } = await generateText({
148
+ model: claudeCode('opus'),
149
+ prompt: 'Write a story...',
150
+ abortSignal: controller.signal,
151
+ });
152
+ ```
153
+
154
+ **For Long-Running Tasks**: Claude Opus 4's extended thinking may require longer timeouts than typical HTTP requests. See the "Handling Long-Running Tasks" section above for implementing custom timeouts using AbortSignal.
155
+
156
+ ### Configuration Options
157
+
158
+ | Option | Type | Default | Description |
159
+ |--------|------|---------|-------------|
160
+ | `model` | `'opus' \| 'sonnet'` | `'opus'` | Model to use |
161
+ | `pathToClaudeCodeExecutable` | `string` | `'claude'` | Path to Claude CLI executable |
162
+ | `customSystemPrompt` | `string` | `undefined` | Custom system prompt |
163
+ | `appendSystemPrompt` | `string` | `undefined` | Append to system prompt |
164
+ | `maxTurns` | `number` | `undefined` | Maximum conversation turns |
165
+ | `maxThinkingTokens` | `number` | `undefined` | Maximum thinking tokens |
166
+ | `permissionMode` | `string` | `'default'` | Permission mode for tools |
167
+ | `allowedTools` | `string[]` | `undefined` | Tools to explicitly allow |
168
+ | `disallowedTools` | `string[]` | `undefined` | Tools to restrict |
169
+ | `mcpServers` | `object` | `undefined` | MCP server configuration |
170
+ | `resume` | `string` | `undefined` | Resume an existing session |
171
+
172
+ ### Custom Configuration
173
+
174
+ ```typescript
175
+ import { createClaudeCode } from 'ai-sdk-provider-claude-code';
176
+
177
+ const claude = createClaudeCode({
178
+ defaultSettings: {
179
+ pathToClaudeCodeExecutable: '/usr/local/bin/claude',
180
+ permissionMode: 'default', // Ask for permissions
181
+ customSystemPrompt: 'You are a helpful coding assistant.',
182
+ }
183
+ });
184
+
185
+ const { text } = await generateText({
186
+ model: claude('opus'),
187
+ prompt: 'Hello, Claude!',
188
+ });
189
+ ```
190
+
191
+ ### Logging Configuration
192
+
193
+ Control how warnings and errors are logged:
194
+
195
+ ```typescript
196
+ import { createClaudeCode } from 'ai-sdk-provider-claude-code';
197
+
198
+ // Default: logs to console
199
+ const defaultClaude = createClaudeCode();
200
+
201
+ // Disable all logging
202
+ const silentClaude = createClaudeCode({
203
+ defaultSettings: {
204
+ logger: false
205
+ }
206
+ });
207
+
208
+ // Custom logger
209
+ const customClaude = createClaudeCode({
210
+ defaultSettings: {
211
+ logger: {
212
+ warn: (message) => myLogger.warn('Claude:', message),
213
+ error: (message) => myLogger.error('Claude:', message),
214
+ }
215
+ }
216
+ });
217
+
218
+ // Model-specific logger override
219
+ const model = customClaude('opus', {
220
+ logger: false // Disable logging for this model only
221
+ });
222
+ ```
223
+
224
+ Logger options:
225
+ - `undefined` (default): Uses `console.warn` and `console.error`
226
+ - `false`: Disables all logging
227
+ - Custom `Logger` object: Must implement `warn` and `error` methods
228
+
229
+ ### Tool Management
230
+
231
+ Control which tools Claude Code can use with either `allowedTools` (allowlist) or `disallowedTools` (denylist). These flags work for **both built-in Claude tools and MCP tools**, providing session-only permission overrides.
232
+
233
+ #### Tool Types
234
+ - **Built-in tools**: `Bash`, `Edit`, `Read`, `Write`, `LS`, `Grep`, etc.
235
+ - **MCP tools**: `mcp__serverName__toolName` format
236
+
237
+ #### Using allowedTools (Allowlist)
238
+ ```typescript
239
+ import { createClaudeCode } from 'ai-sdk-provider-claude-code';
240
+
241
+ // Only allow specific built-in tools
242
+ const readOnlyClaude = createClaudeCode({
243
+ allowedTools: ['Read', 'LS', 'Grep'],
244
+ });
245
+
246
+ // Allow specific Bash commands using specifiers
247
+ const gitOnlyClaude = createClaudeCode({
248
+ allowedTools: [
249
+ 'Bash(git log:*)',
250
+ 'Bash(git diff:*)',
251
+ 'Bash(git status)'
252
+ ],
253
+ });
254
+
255
+ // Mix built-in and MCP tools
256
+ const mixedClaude = createClaudeCode({
257
+ allowedTools: [
258
+ 'Read',
259
+ 'Bash(npm test:*)',
260
+ 'mcp__filesystem__read_file',
261
+ 'mcp__git__status'
262
+ ],
263
+ });
264
+ ```
265
+
266
+ #### Using disallowedTools (Denylist)
267
+ ```typescript
268
+ // Block dangerous operations
269
+ const safeClaude = createClaudeCode({
270
+ disallowedTools: [
271
+ 'Write',
272
+ 'Edit',
273
+ 'Delete',
274
+ 'Bash(rm:*)',
275
+ 'Bash(sudo:*)'
276
+ ],
277
+ });
278
+
279
+ // Block all Bash and MCP write operations
280
+ const restrictedClaude = createClaudeCode({
281
+ disallowedTools: [
282
+ 'Bash',
283
+ 'mcp__filesystem__write_file',
284
+ 'mcp__git__commit',
285
+ 'mcp__git__push'
286
+ ],
287
+ });
288
+ ```
289
+
290
+ #### Model-Specific Overrides
291
+ ```typescript
292
+ const baseClaude = createClaudeCode({
293
+ disallowedTools: ['Write', 'Edit'],
294
+ });
295
+
296
+ // Override for a specific call
297
+ const { text } = await generateText({
298
+ model: baseClaude('opus', {
299
+ disallowedTools: [], // Allow everything for this call
300
+ }),
301
+ prompt: 'Create a simple config file...',
302
+ });
303
+ ```
304
+
305
+ **Key Points**:
306
+ - These are **session-only permission overrides** (same syntax as settings.json)
307
+ - Higher priority than settings files
308
+ - Works for both built-in tools AND MCP tools
309
+ - Cannot use both `allowedTools` and `disallowedTools` together
310
+ - Empty `allowedTools: []` = Explicit empty allowlist (no tools allowed)
311
+ - Omitting the flags entirely = Falls back to normal permission system
312
+ - Use `/permissions` in Claude to see all available tool names
313
+
314
+ **Common Patterns**:
315
+ - Read-only mode: `disallowedTools: ['Write', 'Edit', 'Delete']`
316
+ - No shell access: `disallowedTools: ['Bash']`
317
+ - Safe git: `allowedTools: ['Bash(git log:*)', 'Bash(git diff:*)']`
318
+ - No MCP: `disallowedTools: ['mcp__*']`
319
+
320
+ **Permission Behavior**:
321
+ | Configuration | CLI Flag Behavior | Result |
322
+ |--------------|-------------------|---------|
323
+ | No config | No `--allowedTools` or `--disallowedTools` | Falls back to settings.json and interactive prompts |
324
+ | `allowedTools: []` | `--allowedTools` (empty) | Explicit empty allowlist - blocks all tools |
325
+ | `allowedTools: ['Read']` | `--allowedTools Read` | Only allows Read tool |
326
+ | `disallowedTools: []` | `--disallowedTools` (empty) | No effect - normal permissions apply |
327
+ | `disallowedTools: ['Write']` | `--disallowedTools Write` | Blocks Write tool, others follow normal permissions |
328
+
329
+ ## Advanced Configuration
330
+
331
+ ### MCP Server Support
332
+
333
+ The provider supports Model Context Protocol (MCP) servers for extended functionality:
334
+
335
+ ```typescript
336
+ const claude = createClaudeCode({
337
+ mcpServers: {
338
+ filesystem: {
339
+ command: 'npx',
340
+ args: ['-y', '@modelcontextprotocol/server-filesystem'],
341
+ },
342
+ github: {
343
+ type: 'sse',
344
+ url: 'https://mcp.github.com/api',
345
+ headers: { 'Authorization': 'Bearer YOUR_TOKEN' },
346
+ },
347
+ },
348
+ });
349
+ ```
350
+
351
+ ### Permission Modes
352
+
353
+ Control how Claude Code handles tool permissions:
354
+
355
+ ```typescript
356
+ const claude = createClaudeCode({
357
+ permissionMode: 'bypassPermissions', // Skip all permission prompts
358
+ // Other options: 'default', 'acceptEdits', 'plan'
359
+ });
360
+ ```
361
+
362
+ ### Custom System Prompts
363
+
364
+ ```typescript
365
+ const claude = createClaudeCode({
366
+ customSystemPrompt: 'You are an expert Python developer.',
367
+ // Or append to existing prompt:
368
+ appendSystemPrompt: 'Always use type hints in Python code.',
369
+ });
370
+ ```
371
+
372
+ ## Request Cancellation
373
+
374
+ The provider supports request cancellation through the standard AbortController API:
375
+
376
+ ```typescript
377
+ import { generateText } from 'ai';
378
+ import { claudeCode } from 'ai-sdk-provider-claude-code';
379
+
380
+ // Create abort controller
381
+ const controller = new AbortController();
382
+
383
+ // Start request
384
+ const promise = generateText({
385
+ model: claudeCode('opus'),
386
+ prompt: 'Write a long story...',
387
+ abortSignal: controller.signal,
388
+ });
389
+
390
+ // Cancel the request
391
+ controller.abort();
392
+
393
+ // The promise rejects with AbortError
394
+ try {
395
+ await promise;
396
+ } catch (error) {
397
+ if (error.name === 'AbortError') {
398
+ console.log('Request was cancelled');
399
+ }
400
+ }
401
+ ```
402
+
403
+ This is especially useful in UI scenarios where users might cancel requests or navigate away.
404
+
405
+ ## Implementation Details
406
+
407
+ ### SDK Message Types
408
+
409
+ The SDK provides structured message types for different events:
410
+
411
+ #### Assistant Message
412
+ ```typescript
413
+ {
414
+ type: 'assistant',
415
+ message: {
416
+ content: [{ type: 'text', text: 'Hello!' }],
417
+ // ... other fields
418
+ },
419
+ session_id: 'abc-123-def'
420
+ }
421
+ ```
422
+
423
+ #### Result Message
424
+ ```typescript
425
+ {
426
+ type: 'result',
427
+ subtype: 'success' | 'error_max_turns' | 'error_during_execution',
428
+ session_id: 'abc-123-def',
429
+ usage: { /* token counts */ },
430
+ total_cost_usd: 0.001,
431
+ duration_ms: 1500
432
+ }
433
+ ```
434
+
435
+ #### System Message
436
+ ```typescript
437
+ {
438
+ type: 'system',
439
+ subtype: 'init',
440
+ session_id: 'abc-123-def',
441
+ tools: ['Read', 'Write', 'Bash'],
442
+ model: 'opus'
443
+ }
444
+ ```
445
+
446
+ ### SDK Implementation
447
+
448
+ The provider uses the official `@anthropic-ai/claude-code` SDK which provides:
449
+ - **AsyncGenerator pattern**: Native streaming support with `query()` function
450
+ - **Structured messages**: Rich message types (assistant, result, system, error)
451
+ - **Built-in features**: AbortController, session management, MCP servers
452
+ - **Automatic handling**: Process management, error handling, and output parsing
453
+
454
+ ### Provider Metadata
455
+
456
+ The provider returns rich metadata including token usage, timing, and cost information:
457
+
458
+ ```typescript
459
+ const { text, usage, providerMetadata } = await generateText({
460
+ model: claudeCode('sonnet'),
461
+ prompt: 'Hello!',
462
+ });
463
+
464
+ console.log(providerMetadata);
465
+ // {
466
+ // "claude-code": {
467
+ // "sessionId": "abc-123-def",
468
+ // "costUsd": 0.0285561, // Note: Always non-zero for tracking
469
+ // "durationMs": 3056,
470
+ // "rawUsage": {
471
+ // "inputTokens": 4,
472
+ // "outputTokens": 7,
473
+ // "cacheCreationInputTokens": 5924,
474
+ // "cacheReadInputTokens": 10075
475
+ // }
476
+ // }
477
+ // }
478
+ ```
479
+
480
+ **Important Note about Costs**: The `costUsd` field shows the cost of the API usage:
481
+ - **For Pro/Max subscribers**: This is informational only - usage is covered by your monthly subscription
482
+ - **For API key users**: This represents actual charges that will be billed to your account
483
+
484
+ ## Object Generation
485
+
486
+ The provider supports object generation through prompt engineering, allowing you to generate structured data with JSON schema validation:
487
+
488
+ ```typescript
489
+ import { generateObject, streamObject } from 'ai';
490
+ import { claudeCode } from 'ai-sdk-provider-claude-code';
491
+ import { z } from 'zod';
492
+
493
+ // Generate a complete object
494
+ const { object } = await generateObject({
495
+ model: claudeCode('sonnet'),
496
+ schema: z.object({
497
+ recipe: z.object({
498
+ name: z.string(),
499
+ ingredients: z.array(z.string()),
500
+ instructions: z.array(z.string()),
501
+ prepTime: z.number(),
502
+ servings: z.number(),
503
+ }),
504
+ }),
505
+ prompt: 'Generate a recipe for chocolate chip cookies',
506
+ });
507
+
508
+ // Note: streamObject waits for complete response before parsing
509
+ // Use generateObject for clarity since streaming doesn't provide benefits
510
+ const { object: analysis } = await generateObject({
511
+ model: claudeCode('sonnet'),
512
+ schema: z.object({
513
+ analysis: z.string(),
514
+ sentiment: z.enum(['positive', 'negative', 'neutral']),
515
+ score: z.number(),
516
+ }),
517
+ prompt: 'Analyze this review: "Great product!"',
518
+ });
519
+
520
+ console.log(analysis);
521
+ ```
522
+
523
+ **How it works**: The provider appends JSON generation instructions to your prompt and uses a tolerant JSON parser to extract valid output from Claude's response. Minor issues like trailing commas or comments are automatically handled, though this is still not as strict as native JSON mode.
524
+
525
+ **Important notes**:
526
+ - **Object mode support**: Only `object-json` mode is supported (via `generateObject`/`streamObject`). The provider uses prompt engineering and JSON extraction to ensure reliable object generation.
527
+ - **Streaming behavior**: While `streamObject` is supported, it accumulates the full response before extracting JSON to ensure validity. Regular text streaming works in real-time.
528
+
529
+ ## Object Generation Cookbook
530
+
531
+ ### Quick Start Examples
532
+
533
+ #### Basic Objects
534
+ Start with simple schemas and clear prompts:
535
+ ```typescript
536
+ const { object } = await generateObject({
537
+ model: claudeCode('sonnet'),
538
+ schema: z.object({
539
+ name: z.string(),
540
+ age: z.number(),
541
+ email: z.string().email(),
542
+ }),
543
+ prompt: 'Generate a developer profile',
544
+ });
545
+ ```
546
+ [Full example](../examples/generate-object-basic.ts)
547
+
548
+ #### Nested Structures
549
+ Build complex hierarchical data:
550
+ ```typescript
551
+ const { object } = await generateObject({
552
+ model: claudeCode('sonnet'),
553
+ schema: z.object({
554
+ company: z.object({
555
+ departments: z.array(z.object({
556
+ name: z.string(),
557
+ teams: z.array(z.object({
558
+ name: z.string(),
559
+ members: z.number(),
560
+ })),
561
+ })),
562
+ }),
563
+ }),
564
+ prompt: 'Generate a company org structure',
565
+ });
566
+ ```
567
+ [Full example](../examples/generate-object-nested.ts)
568
+
569
+ #### Constrained Generation
570
+ Use Zod's validation features:
571
+ ```typescript
572
+ const { object } = await generateObject({
573
+ model: claudeCode('sonnet'),
574
+ schema: z.object({
575
+ status: z.enum(['pending', 'active', 'completed']),
576
+ priority: z.number().min(1).max(5),
577
+ tags: z.array(z.string()).min(1).max(3),
578
+ }),
579
+ prompt: 'Generate a task with medium priority',
580
+ });
581
+ ```
582
+ [Full example](../examples/generate-object-constraints.ts)
583
+
584
+
585
+ ### Best Practices
586
+
587
+ 1. **Start Simple**: Begin with basic schemas and add complexity gradually
588
+ 2. **Clear Prompts**: Be specific about what you want generated
589
+ 3. **Use Descriptions**: Add `.describe()` to schema fields for better results
590
+ 4. **Handle Errors**: Implement retry logic for production use
591
+ 5. **Test Schemas**: Validate your schemas work before deployment
592
+
593
+ ### Common Patterns
594
+
595
+ - **Data Models**: [User profiles, products, orders](../examples/generate-object-nested.ts)
596
+ - **Validation**: [Enums, constraints, regex patterns](../examples/generate-object-constraints.ts)
597
+ - **Basic Objects**: [Simple schemas and arrays](../examples/generate-object-basic.ts)
598
+ - **Note**: For object generation, use `generateObject` instead of `streamObject` as streaming provides no benefits
599
+
600
+ ## Object Generation Troubleshooting
601
+
602
+ ### Common Issues and Solutions
603
+
604
+ #### 1. Invalid JSON Response
605
+ **Problem**: Claude returns text instead of valid JSON
606
+
607
+ **Solutions**:
608
+ - Simplify your schema - start with fewer fields
609
+ - Make your prompt more explicit: "Generate only valid JSON"
610
+ - Check the schema for overly complex constraints
611
+ - Use the retry pattern:
612
+
613
+ ```typescript
614
+ async function generateWithRetry(schema, prompt, maxRetries = 3) {
615
+ for (let i = 0; i < maxRetries; i++) {
616
+ try {
617
+ return await generateObject({ model, schema, prompt });
618
+ } catch (error) {
619
+ if (i === maxRetries - 1) throw error;
620
+ await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
621
+ }
622
+ }
623
+ }
624
+ ```
625
+
626
+ #### 2. Missing Required Fields
627
+ **Problem**: Generated objects missing required properties
628
+
629
+ **Solutions**:
630
+ - Emphasize requirements in your prompt
631
+ - Use descriptive field names
632
+ - Add field descriptions with `.describe()`
633
+ - Example:
634
+ ```typescript
635
+ z.object({
636
+ // Bad: vague field name
637
+ val: z.number(),
638
+
639
+ // Good: clear field name with description
640
+ totalPrice: z.number().describe('Total price in USD'),
641
+ })
642
+ ```
643
+
644
+ #### 3. Type Mismatches
645
+ **Problem**: String when expecting number, wrong date format, etc.
646
+
647
+ **Solutions**:
648
+ - Be explicit in descriptions: "age as a number" not just "age"
649
+ - For dates, specify format: `.describe('Date in YYYY-MM-DD format')`
650
+ - Use regex patterns for strings: `z.string().regex(/^\d{4}-\d{2}-\d{2}$/)`
651
+
652
+ #### 4. Schema Too Complex
653
+ **Problem**: Very complex schemas fail or timeout
654
+
655
+ **Solutions**:
656
+ - Break into smaller parts and combine:
657
+ ```typescript
658
+ // Instead of one huge schema, compose smaller ones
659
+ const userSchema = z.object({ /* user fields */ });
660
+ const settingsSchema = z.object({ /* settings */ });
661
+ const profileSchema = z.object({
662
+ user: userSchema,
663
+ settings: settingsSchema,
664
+ });
665
+ ```
666
+ - Generate in steps and merge results
667
+ - Increase timeout for complex generations
668
+
669
+ #### 5. Inconsistent Results
670
+ **Problem**: Same prompt gives different structure each time
671
+
672
+ **Solutions**:
673
+ - Make schemas more constrained (use enums, min/max)
674
+ - Provide example in prompt
675
+ - Use consistent field naming conventions
676
+ - Consider using `opus` model for complex schemas
677
+
678
+ ### Debugging Tips
679
+
680
+ 1. **Enable Debug Logging**:
681
+ ```typescript
682
+ const { object, usage, warnings } = await generateObject({
683
+ model: claudeCode('sonnet'),
684
+ schema: yourSchema,
685
+ prompt: yourPrompt,
686
+ });
687
+ console.log('Tokens used:', usage);
688
+ console.log('Warnings:', warnings);
689
+ ```
690
+
691
+ 2. **Test Schema Separately**:
692
+ ```typescript
693
+ // Validate your schema works
694
+ const testData = { /* your test object */ };
695
+ try {
696
+ schema.parse(testData);
697
+ console.log('Schema is valid');
698
+ } catch (e) {
699
+ console.log('Schema errors:', e.errors);
700
+ }
701
+ ```
702
+
703
+ 3. **Progressive Enhancement**:
704
+ Start with minimal schema, test, then add fields one by one
705
+
706
+ 4. **Check Examples**:
707
+ Review our examples for implementation patterns
708
+
709
+ ## Limitations
710
+
711
+ - **No image support**: The Claude Code CLI doesn't support image inputs (provider sets `supportsImageUrls = false`)
712
+ - **No embedding support**: Text embeddings are not available through this provider
713
+ - **Object-tool mode not supported**: Only `object-json` mode works via `generateObject`/`streamObject`. The AI SDK's tool calling interface is not implemented
714
+ - **Text-only responses**: No support for file generation or other modalities
715
+ - **Session management**: While sessions are supported, message history is the recommended approach
716
+ - **Unsupported generation settings**: The following AI SDK settings are ignored and will generate warnings:
717
+ - `temperature` - Claude Code CLI doesn't expose temperature control
718
+ - `maxTokens` - Token limits aren't configurable via CLI
719
+ - `topP`, `topK` - Sampling parameters aren't available
720
+ - `presencePenalty`, `frequencyPenalty` - Penalty parameters aren't supported
721
+ - `stopSequences` - Custom stop sequences aren't available
722
+ - `seed` - Deterministic generation isn't supported
723
+
724
+ ## Error Handling
725
+
726
+ The provider uses standard AI SDK error classes for better ecosystem compatibility:
727
+
728
+ ```typescript
729
+ import { generateText } from 'ai';
730
+ import { APICallError, LoadAPIKeyError } from '@ai-sdk/provider';
731
+ import {
732
+ claudeCode,
733
+ isAuthenticationError,
734
+ isTimeoutError,
735
+ getErrorMetadata
736
+ } from 'ai-sdk-provider-claude-code';
737
+
738
+ try {
739
+ const { text } = await generateText({
740
+ model: claudeCode('opus'),
741
+ prompt: 'Hello!',
742
+ });
743
+ } catch (error) {
744
+ if (isAuthenticationError(error)) {
745
+ console.error('Please run "claude login" to authenticate');
746
+ } else if (isTimeoutError(error)) {
747
+ console.error('Request timed out. Consider using AbortController with a custom timeout.');
748
+ } else if (error instanceof APICallError) {
749
+ // Get CLI-specific metadata
750
+ const metadata = getErrorMetadata(error);
751
+ console.error('CLI error:', {
752
+ message: error.message,
753
+ isRetryable: error.isRetryable,
754
+ exitCode: metadata?.exitCode,
755
+ stderr: metadata?.stderr,
756
+ });
757
+ } else {
758
+ console.error('Error:', error);
759
+ }
760
+ }
761
+ ```
762
+
763
+ ### Error Types
764
+
765
+ - **`LoadAPIKeyError`**: Authentication failures (exit code 401)
766
+ - **`APICallError`**: All other CLI failures
767
+ - `isRetryable: true` for timeouts
768
+ - `isRetryable: false` for SDK errors, authentication failures, etc.
769
+ - Contains metadata with `exitCode`, `stderr`, `promptExcerpt`
770
+
771
+ ## Troubleshooting
772
+
773
+ See [TROUBLESHOOTING.md](TROUBLESHOOTING.md) for solutions to common issues including:
774
+ - Authentication problems
775
+ - SDK installation issues
776
+ - Session management
777
+ - Platform-specific issues
778
+ - Timeout handling with AbortSignal
779
+
780
+ ## Project Structure
781
+
782
+ ```
783
+ ai-sdk-provider-claude-code/
784
+ ├── src/ # Source code
785
+ │ ├── index.ts # Main exports
786
+ │ ├── claude-code-provider.ts # Provider factory
787
+ │ ├── claude-code-language-model.ts # AI SDK implementation using SDK
788
+ │ ├── convert-to-claude-code-messages.ts # Message format converter
789
+ │ ├── extract-json.ts # JSON extraction for object generation
790
+ │ ├── errors.ts # Error handling utilities
791
+ │ ├── logger.ts # Configurable logger support
792
+ │ ├── map-claude-code-finish-reason.ts # Finish reason mapping utilities
793
+ │ ├── types.ts # TypeScript types and interfaces
794
+ │ ├── validation.ts # Input validation utilities
795
+ │ ├── *.test.ts # Test files for each module
796
+ │ └── logger.integration.test.ts # Logger integration tests
797
+ ├── examples/ # Example usage scripts
798
+ │ ├── README.md # Examples documentation
799
+ │ ├── abort-signal.ts # Request cancellation examples
800
+ │ ├── basic-usage.ts # Simple text generation with metadata
801
+ │ ├── check-cli.ts # CLI installation verification
802
+ │ ├── conversation-history.ts # Multi-turn conversation with message history
803
+ │ ├── custom-config.ts # Provider configuration options
804
+ │ ├── generate-object.ts # Original object generation example
805
+ │ ├── generate-object-basic.ts # Basic object generation patterns
806
+ │ ├── generate-object-constraints.ts # Validation and constraints
807
+ │ ├── generate-object-nested.ts # Complex nested structures
808
+ │ ├── integration-test.ts # Comprehensive integration tests
809
+ │ ├── limitations.ts # Provider limitations demo
810
+ │ ├── long-running-tasks.ts # Timeout handling with AbortSignal
811
+ │ ├── streaming.ts # Streaming response demo
812
+ │ ├── test-session.ts # Session management testing
813
+ │ └── tool-management.ts # Tool access control (allow/disallow)
814
+ ├── docs/ # Documentation
815
+ │ ├── GUIDE.md # Comprehensive guide (this file)
816
+ │ ├── DEVELOPMENT-STATUS.md # Development status and roadmap
817
+ │ └── TROUBLESHOOTING.md # Common issues and solutions
818
+ ├── CHANGELOG.md # Version history
819
+ ├── CODE_REVIEW_PLAN.md # Development planning documentation
820
+ ├── LICENSE # MIT License
821
+ ├── README.md # Main project documentation
822
+ ├── eslint.config.js # ESLint configuration
823
+ ├── package.json # Project metadata and dependencies
824
+ ├── package-lock.json # Dependency lock file
825
+ ├── run-all-examples.sh # Script to run all examples
826
+ ├── tsconfig.json # TypeScript configuration
827
+ ├── tsup.config.ts # Build configuration
828
+ └── vitest.config.ts # Test runner configuration
829
+ ```
830
+
831
+ ## Known Limitations
832
+
833
+ 1. **No image support**: The CLI doesn't accept image inputs
834
+ 2. **Authentication required**: Requires separate Claude Code CLI authentication (`claude login`)
835
+ 3. **Session IDs change**: Each request gets a new session ID, even when using `--resume`
836
+ 4. **No AI SDK tool calling interface**: The AI SDK's function/tool calling interface is not implemented, but Claude can use tools via MCP servers and built-in CLI tools
837
+
838
+ ## Contributing
839
+
840
+ Contributions are welcome! Please read our contributing guidelines before submitting a PR.
841
+
842
+ **Alpha Focus Areas:**
843
+ - Code structure improvements (AI-generated code cleanup)
844
+ - Performance optimizations
845
+ - Better error handling patterns
846
+ - TypeScript type improvements
847
+ - Additional example use cases
848
+
849
+ ### Dependency Management
850
+
851
+ This project uses exact dependency versions to ensure consistent behavior across all installations. When updating dependencies:
852
+
853
+ 1. Update the exact version in `package.json`
854
+ 2. Run `npm install` to update the lock file
855
+ 3. Test thoroughly before committing
856
+
857
+ Note: Peer dependencies (like `zod`) use version ranges as per npm best practices.
858
+
859
+ ## License
860
+
861
+ MIT - see [LICENSE](../LICENSE) for details.
862
+
863
+ ## Acknowledgments
864
+
865
+ This provider is built for the [Vercel AI SDK](https://sdk.vercel.ai/) and uses the [Claude Code CLI](https://docs.anthropic.com/claude-code/cli) by Anthropic.