@boostecom/provider 0.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 +90 -0
- package/dist/index.cjs +2522 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +848 -0
- package/dist/index.d.ts +848 -0
- package/dist/index.js +2484 -0
- package/dist/index.js.map +1 -0
- package/docs/content/README.md +337 -0
- package/docs/content/agent-teams.mdx +324 -0
- package/docs/content/api.mdx +757 -0
- package/docs/content/best-practices.mdx +624 -0
- package/docs/content/examples.mdx +675 -0
- package/docs/content/guide.mdx +516 -0
- package/docs/content/index.mdx +99 -0
- package/docs/content/installation.mdx +246 -0
- package/docs/content/skills.mdx +548 -0
- package/docs/content/troubleshooting.mdx +588 -0
- package/docs/examples/README.md +499 -0
- package/docs/examples/abort-signal.ts +125 -0
- package/docs/examples/agent-teams.ts +122 -0
- package/docs/examples/basic-usage.ts +73 -0
- package/docs/examples/check-cli.ts +51 -0
- package/docs/examples/conversation-history.ts +69 -0
- package/docs/examples/custom-config.ts +90 -0
- package/docs/examples/generate-object-constraints.ts +209 -0
- package/docs/examples/generate-object.ts +211 -0
- package/docs/examples/hooks-callbacks.ts +63 -0
- package/docs/examples/images.ts +76 -0
- package/docs/examples/integration-test.ts +241 -0
- package/docs/examples/limitations.ts +150 -0
- package/docs/examples/logging-custom-logger.ts +99 -0
- package/docs/examples/logging-default.ts +55 -0
- package/docs/examples/logging-disabled.ts +74 -0
- package/docs/examples/logging-verbose.ts +64 -0
- package/docs/examples/long-running-tasks.ts +179 -0
- package/docs/examples/message-injection.ts +210 -0
- package/docs/examples/mid-stream-injection.ts +126 -0
- package/docs/examples/run-all-examples.sh +48 -0
- package/docs/examples/sdk-tools-callbacks.ts +49 -0
- package/docs/examples/skills-discovery.ts +144 -0
- package/docs/examples/skills-management.ts +140 -0
- package/docs/examples/stream-object.ts +80 -0
- package/docs/examples/streaming.ts +52 -0
- package/docs/examples/structured-output-repro.ts +227 -0
- package/docs/examples/tool-management.ts +215 -0
- package/docs/examples/tool-streaming.ts +132 -0
- package/docs/examples/zod4-compatibility-test.ts +290 -0
- package/docs/src/claude-code-language-model.test.ts +3883 -0
- package/docs/src/claude-code-language-model.ts +2586 -0
- package/docs/src/claude-code-provider.test.ts +97 -0
- package/docs/src/claude-code-provider.ts +179 -0
- package/docs/src/convert-to-claude-code-messages.images.test.ts +104 -0
- package/docs/src/convert-to-claude-code-messages.test.ts +193 -0
- package/docs/src/convert-to-claude-code-messages.ts +419 -0
- package/docs/src/errors.test.ts +213 -0
- package/docs/src/errors.ts +216 -0
- package/docs/src/index.test.ts +49 -0
- package/docs/src/index.ts +98 -0
- package/docs/src/logger.integration.test.ts +164 -0
- package/docs/src/logger.test.ts +184 -0
- package/docs/src/logger.ts +65 -0
- package/docs/src/map-claude-code-finish-reason.test.ts +120 -0
- package/docs/src/map-claude-code-finish-reason.ts +60 -0
- package/docs/src/mcp-helpers.test.ts +71 -0
- package/docs/src/mcp-helpers.ts +123 -0
- package/docs/src/message-injection.test.ts +460 -0
- package/docs/src/types.ts +447 -0
- package/docs/src/validation.test.ts +558 -0
- package/docs/src/validation.ts +360 -0
- package/package.json +124 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { claudeCode } from '../dist/index.js';
|
|
2
|
+
import { generateText } from 'ai';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Agent Teams Example with Claude Opus 4.6
|
|
6
|
+
*
|
|
7
|
+
* Demonstrates how to use multiple specialized subagents working together
|
|
8
|
+
* as a coordinated team to accomplish complex, multi-faceted tasks.
|
|
9
|
+
*
|
|
10
|
+
* This example showcases:
|
|
11
|
+
* - Multiple specialized agents (research, coding, testing)
|
|
12
|
+
* - Tool restrictions per agent
|
|
13
|
+
* - Coordination between agents
|
|
14
|
+
* - Extended context window usage (1M tokens in beta)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
console.log('=== Agent Teams Example ===\n');
|
|
19
|
+
|
|
20
|
+
// Create a model with multiple specialized subagents
|
|
21
|
+
const model = claudeCode('opus', {
|
|
22
|
+
// Enable extended context window (1M tokens - beta feature)
|
|
23
|
+
maxThinkingTokens: 10000,
|
|
24
|
+
|
|
25
|
+
// Configure agent team with specialized roles
|
|
26
|
+
agents: {
|
|
27
|
+
// Research Agent - Specializes in information gathering
|
|
28
|
+
researcher: {
|
|
29
|
+
description: 'Expert at finding information, searching codebases, and analyzing documentation',
|
|
30
|
+
tools: ['Read', 'Grep', 'Glob', 'WebSearch', 'Skill'],
|
|
31
|
+
disallowedTools: ['Write', 'Edit', 'Bash'],
|
|
32
|
+
prompt: `You are a research specialist. Your role is to:
|
|
33
|
+
- Find and analyze relevant information
|
|
34
|
+
- Search through codebases systematically
|
|
35
|
+
- Provide comprehensive summaries
|
|
36
|
+
- Cite your sources clearly
|
|
37
|
+
|
|
38
|
+
When you find information, organize it clearly and pass it to the appropriate agent.`,
|
|
39
|
+
model: 'sonnet', // Use faster model for research
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
// Coding Agent - Specializes in implementation
|
|
43
|
+
developer: {
|
|
44
|
+
description: 'Expert at writing, editing, and refactoring code with best practices',
|
|
45
|
+
tools: ['Read', 'Write', 'Edit', 'Grep', 'Glob', 'Skill'],
|
|
46
|
+
disallowedTools: ['Bash(rm:*)', 'Bash(sudo:*)'],
|
|
47
|
+
prompt: `You are a senior software engineer. Your role is to:
|
|
48
|
+
- Write clean, maintainable code
|
|
49
|
+
- Follow best practices and design patterns
|
|
50
|
+
- Implement features based on research findings
|
|
51
|
+
- Create well-documented code
|
|
52
|
+
|
|
53
|
+
Always write tests for your implementations and coordinate with the testing agent.`,
|
|
54
|
+
model: 'opus', // Use most capable model for coding
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// Testing Agent - Specializes in quality assurance
|
|
58
|
+
tester: {
|
|
59
|
+
description: 'Expert at writing tests, running test suites, and ensuring code quality',
|
|
60
|
+
tools: ['Read', 'Write', 'Bash', 'Grep', 'Skill'],
|
|
61
|
+
disallowedTools: ['Edit'],
|
|
62
|
+
prompt: `You are a QA engineer and testing specialist. Your role is to:
|
|
63
|
+
- Write comprehensive test suites
|
|
64
|
+
- Run tests and analyze results
|
|
65
|
+
- Identify edge cases and potential bugs
|
|
66
|
+
- Ensure code quality and coverage
|
|
67
|
+
|
|
68
|
+
Review implementations from the developer agent and provide feedback.`,
|
|
69
|
+
model: 'haiku', // Use fast model for testing
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
// Enable Skills for all agents
|
|
74
|
+
settingSources: ['user', 'project'],
|
|
75
|
+
allowedTools: ['Skill', 'Read', 'Write', 'Edit', 'Grep', 'Glob', 'Bash'],
|
|
76
|
+
|
|
77
|
+
// Enable extended features
|
|
78
|
+
betas: ['code-execution-tool'],
|
|
79
|
+
|
|
80
|
+
// Session management
|
|
81
|
+
persistSession: true,
|
|
82
|
+
maxTurns: 20,
|
|
83
|
+
|
|
84
|
+
verbose: true,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const prompt = `I need to build a secure user authentication system for a Node.js API. Please:
|
|
89
|
+
|
|
90
|
+
1. Research best practices for password hashing and session management
|
|
91
|
+
2. Implement a complete auth module with:
|
|
92
|
+
- User registration with bcrypt password hashing
|
|
93
|
+
- Login with JWT tokens
|
|
94
|
+
- Session management with refresh tokens
|
|
95
|
+
- Rate limiting for security
|
|
96
|
+
3. Write comprehensive tests covering all scenarios
|
|
97
|
+
|
|
98
|
+
Coordinate between the research, development, and testing agents to deliver a production-ready solution.`;
|
|
99
|
+
|
|
100
|
+
console.log('Prompt:', prompt);
|
|
101
|
+
console.log('\nGenerating with agent team...\n');
|
|
102
|
+
|
|
103
|
+
const { text, usage, finishReason } = await generateText({
|
|
104
|
+
model,
|
|
105
|
+
prompt,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
console.log('\n=== Result ===');
|
|
109
|
+
console.log(text);
|
|
110
|
+
|
|
111
|
+
console.log('\n=== Usage ===');
|
|
112
|
+
console.log('Input tokens:', usage.inputTokens);
|
|
113
|
+
console.log('Output tokens:', usage.outputTokens);
|
|
114
|
+
console.log('Finish reason:', finishReason);
|
|
115
|
+
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error('Error:', error);
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Basic usage example for Claude Code AI SDK Provider
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates simple text generation with the provider
|
|
5
|
+
* and shows the metadata returned from each request.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { streamText } from 'ai';
|
|
9
|
+
import { claudeCode } from '../dist/index.js';
|
|
10
|
+
|
|
11
|
+
async function main() {
|
|
12
|
+
try {
|
|
13
|
+
// Basic text generation - streamText returns immediately, not a promise
|
|
14
|
+
const result = streamText({
|
|
15
|
+
model: claudeCode('opus'),
|
|
16
|
+
prompt: 'Explain the concept of recursion in programming in 2-3 sentences.',
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Stream the response
|
|
20
|
+
console.log('Response:');
|
|
21
|
+
for await (const textPart of result.textStream) {
|
|
22
|
+
process.stdout.write(textPart);
|
|
23
|
+
}
|
|
24
|
+
console.log('\n');
|
|
25
|
+
|
|
26
|
+
// Get final results
|
|
27
|
+
const usage = await result.usage;
|
|
28
|
+
const providerMetadata = await result.providerMetadata;
|
|
29
|
+
|
|
30
|
+
console.log('\nToken usage:', usage);
|
|
31
|
+
|
|
32
|
+
// Display provider-specific metadata
|
|
33
|
+
const metadata = providerMetadata?.['claude-code'];
|
|
34
|
+
if (metadata) {
|
|
35
|
+
console.log('\nProvider metadata:');
|
|
36
|
+
|
|
37
|
+
// Session ID is assigned by the SDK for internal tracking
|
|
38
|
+
if (metadata.sessionId) {
|
|
39
|
+
console.log(`- Session ID: ${metadata.sessionId}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Performance metrics
|
|
43
|
+
if (metadata.durationMs) {
|
|
44
|
+
console.log(`- Duration: ${metadata.durationMs}ms`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Cost information
|
|
48
|
+
if (typeof metadata.costUsd === 'number') {
|
|
49
|
+
console.log(`- Cost: ${metadata.costUsd.toFixed(4)}`);
|
|
50
|
+
console.log(' (Pro/Max subscribers: covered by subscription)');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Raw usage breakdown (available in usage.raw in AI SDK v6 stable)
|
|
54
|
+
if (usage?.raw) {
|
|
55
|
+
console.log('- Raw usage:', JSON.stringify(usage.raw, null, 2));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error('Error:', error);
|
|
60
|
+
console.log('\n💡 Troubleshooting:');
|
|
61
|
+
console.log('1. Install Claude Code SDK: npm install -g @anthropic-ai/claude-code');
|
|
62
|
+
console.log('2. Authenticate: claude login');
|
|
63
|
+
console.log('3. Run check-cli.ts to verify setup');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
main().catch(console.error);
|
|
68
|
+
// NOTE: Migrating to Claude Agent SDK:
|
|
69
|
+
// - System prompt is not applied by default
|
|
70
|
+
// - Filesystem settings (CLAUDE.md, settings.json) are not loaded by default
|
|
71
|
+
// To restore old behavior, set:
|
|
72
|
+
// systemPrompt: { type: 'preset', preset: 'claude_code' }
|
|
73
|
+
// settingSources: ['user', 'project', 'local']
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if the Claude Code SDK is properly installed and authenticated
|
|
3
|
+
* This example verifies the setup before running other examples
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { generateText } from 'ai';
|
|
7
|
+
import { createClaudeCode } from '../dist/index.js';
|
|
8
|
+
|
|
9
|
+
async function checkSetup() {
|
|
10
|
+
console.log('🔍 Checking Claude Code SDK setup...\n');
|
|
11
|
+
|
|
12
|
+
const claudeCode = createClaudeCode();
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
// Try a simple generation to verify everything works
|
|
16
|
+
console.log('Testing SDK connection...');
|
|
17
|
+
|
|
18
|
+
const { text, usage } = await generateText({
|
|
19
|
+
model: claudeCode('opus'),
|
|
20
|
+
prompt: 'Say "Hello from Claude" and nothing else.',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
console.log('✅ Claude Code SDK is working properly!');
|
|
24
|
+
console.log('Response:', text);
|
|
25
|
+
console.log('Tokens used:', usage.totalTokens);
|
|
26
|
+
console.log('\n🎉 You can run all the examples and integration tests!');
|
|
27
|
+
} catch (error: any) {
|
|
28
|
+
console.error('❌ Failed to connect to Claude Code');
|
|
29
|
+
console.error('Error:', error.message);
|
|
30
|
+
|
|
31
|
+
if (error.message?.includes('not found') || error.message?.includes('ENOENT')) {
|
|
32
|
+
console.log('\n💡 Make sure Claude Code SDK is installed:');
|
|
33
|
+
console.log(' npm install -g @anthropic-ai/claude-code');
|
|
34
|
+
} else if (error.message?.includes('authentication') || error.message?.includes('401')) {
|
|
35
|
+
console.log('\n🔐 Authentication required. Please run:');
|
|
36
|
+
console.log(' claude login');
|
|
37
|
+
} else {
|
|
38
|
+
console.log('\n🔧 Troubleshooting tips:');
|
|
39
|
+
console.log('1. Install Claude Code SDK: npm install -g @anthropic-ai/claude-code');
|
|
40
|
+
console.log('2. Authenticate: claude login');
|
|
41
|
+
console.log('3. Verify installation: claude --version');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
checkSetup().catch((error) => {
|
|
49
|
+
console.error('Unexpected error:', error);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test conversation management with proper message history
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { generateText } from 'ai';
|
|
6
|
+
import { claudeCode } from '../dist/index.js';
|
|
7
|
+
// NOTE: Migrating to Claude Agent SDK:
|
|
8
|
+
// - System prompt is not applied by default
|
|
9
|
+
// - Filesystem settings (CLAUDE.md, settings.json) are not loaded by default
|
|
10
|
+
// To restore old behavior, set:
|
|
11
|
+
// systemPrompt: { type: 'preset', preset: 'claude_code' }
|
|
12
|
+
// settingSources: ['user', 'project', 'local']
|
|
13
|
+
import type { ModelMessage } from 'ai';
|
|
14
|
+
|
|
15
|
+
async function testConversation() {
|
|
16
|
+
console.log('🧪 Testing conversation with message history...');
|
|
17
|
+
|
|
18
|
+
const model = claudeCode('opus');
|
|
19
|
+
const messages: ModelMessage[] = [];
|
|
20
|
+
|
|
21
|
+
// First turn
|
|
22
|
+
console.log(`\n1️⃣ First turn...`);
|
|
23
|
+
messages.push({
|
|
24
|
+
role: 'user' as const,
|
|
25
|
+
content: "My name is Helen and I'm a data scientist. Remember this.",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const response1 = await generateText({
|
|
29
|
+
model,
|
|
30
|
+
messages,
|
|
31
|
+
});
|
|
32
|
+
console.log('Assistant:', response1.text);
|
|
33
|
+
messages.push({ role: 'assistant' as const, content: response1.text });
|
|
34
|
+
|
|
35
|
+
// Second turn - add to conversation
|
|
36
|
+
console.log(`\n2️⃣ Second turn...`);
|
|
37
|
+
messages.push({ role: 'user' as const, content: "What's my profession?" });
|
|
38
|
+
|
|
39
|
+
const response2 = await generateText({
|
|
40
|
+
model,
|
|
41
|
+
messages,
|
|
42
|
+
});
|
|
43
|
+
console.log('Assistant:', response2.text);
|
|
44
|
+
|
|
45
|
+
// Third turn - test memory
|
|
46
|
+
console.log(`\n3️⃣ Third turn...`);
|
|
47
|
+
messages.push({ role: 'assistant' as const, content: response2.text });
|
|
48
|
+
messages.push({ role: 'user' as const, content: 'And what was my name again?' });
|
|
49
|
+
|
|
50
|
+
const response3 = await generateText({
|
|
51
|
+
model,
|
|
52
|
+
messages,
|
|
53
|
+
});
|
|
54
|
+
console.log('Assistant:', response3.text);
|
|
55
|
+
|
|
56
|
+
// Check if context was maintained through message history
|
|
57
|
+
const contextMaintained = response3.text.toLowerCase().includes('helen');
|
|
58
|
+
console.log(`\n✅ Context maintained via message history:`, contextMaintained);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
testConversation()
|
|
62
|
+
.then(() => {
|
|
63
|
+
console.log(`\n✅ Test completed`);
|
|
64
|
+
process.exit(0);
|
|
65
|
+
})
|
|
66
|
+
.catch((error) => {
|
|
67
|
+
console.error(`\n❌ Test failed:`, error);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom configuration example for Claude Code AI SDK Provider
|
|
3
|
+
*
|
|
4
|
+
* This example shows how to configure the provider and models
|
|
5
|
+
* with specific settings for your use case.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { generateText } from 'ai';
|
|
9
|
+
import { createClaudeCode } from '../dist/index.js';
|
|
10
|
+
// NOTE: Migrating to Claude Agent SDK:
|
|
11
|
+
// - System prompt is not applied by default
|
|
12
|
+
// - Filesystem settings (CLAUDE.md, settings.json) are not loaded by default
|
|
13
|
+
// To restore old behavior, set:
|
|
14
|
+
// systemPrompt: { type: 'preset', preset: 'claude_code' }
|
|
15
|
+
// settingSources: ['user', 'project', 'local']
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
console.log('🔧 Testing custom configurations...\n');
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
// Example 1: Provider with default settings for all models
|
|
22
|
+
const customProvider = createClaudeCode({
|
|
23
|
+
defaultSettings: {
|
|
24
|
+
// Skip permission prompts for all operations
|
|
25
|
+
permissionMode: 'bypassPermissions',
|
|
26
|
+
// Set working directory for file operations
|
|
27
|
+
cwd: process.cwd(),
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
console.log('1️⃣ Using provider with default settings:');
|
|
32
|
+
const { text: response1 } = await generateText({
|
|
33
|
+
model: customProvider('opus'), // Uses default settings
|
|
34
|
+
prompt: 'What is the capital of France? Answer in one word.',
|
|
35
|
+
});
|
|
36
|
+
console.log('Response:', response1);
|
|
37
|
+
|
|
38
|
+
// Example 2: Override settings for specific model instance
|
|
39
|
+
console.log('\n2️⃣ Model with custom settings:');
|
|
40
|
+
const { text: response2 } = await generateText({
|
|
41
|
+
model: customProvider('opus', {
|
|
42
|
+
// These settings override the provider defaults
|
|
43
|
+
permissionMode: 'default', // Ask for permissions
|
|
44
|
+
maxTurns: 5, // Limit conversation turns
|
|
45
|
+
}),
|
|
46
|
+
prompt: 'Name three popular programming languages. Just list them.',
|
|
47
|
+
});
|
|
48
|
+
console.log('Response:', response2);
|
|
49
|
+
|
|
50
|
+
// Example 3: Using tool restrictions
|
|
51
|
+
console.log('\n3️⃣ Model with tool restrictions:');
|
|
52
|
+
const safeModel = customProvider('opus', {
|
|
53
|
+
// Only allow read operations
|
|
54
|
+
allowedTools: ['Read', 'LS', 'Grep', 'Glob'],
|
|
55
|
+
// Explicitly block write operations
|
|
56
|
+
disallowedTools: ['Write', 'Edit', 'Delete', 'Bash'],
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const { text: response3 } = await generateText({
|
|
60
|
+
model: safeModel,
|
|
61
|
+
prompt: 'List the files in the current directory.',
|
|
62
|
+
});
|
|
63
|
+
console.log('Response:', response3);
|
|
64
|
+
|
|
65
|
+
// Example 4: Multiple model instances from same provider
|
|
66
|
+
console.log('\n4️⃣ Using multiple model instances:');
|
|
67
|
+
const opusModel1 = customProvider('opus');
|
|
68
|
+
const opusModel2 = customProvider('opus');
|
|
69
|
+
|
|
70
|
+
// Quick comparison
|
|
71
|
+
const prompt = 'Explain quantum computing in exactly 10 words.';
|
|
72
|
+
|
|
73
|
+
const { text: response4a } = await generateText({
|
|
74
|
+
model: opusModel1,
|
|
75
|
+
prompt,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const { text: response4b } = await generateText({
|
|
79
|
+
model: opusModel2,
|
|
80
|
+
prompt,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
console.log('Instance 1:', response4a);
|
|
84
|
+
console.log('Instance 2:', response4b);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error('Error:', error);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Constrained Object Generation Examples
|
|
5
|
+
*
|
|
6
|
+
* Demonstrates validation constraints that the Claude Code CLI can enforce
|
|
7
|
+
* via constrained decoding: number ranges, simple regex patterns, array
|
|
8
|
+
* lengths, enums, and multipleOf.
|
|
9
|
+
*
|
|
10
|
+
* NOTE: Avoid Zod methods that produce unsupported JSON Schema annotations:
|
|
11
|
+
* .email(), .url(), .uuid(), .datetime() all emit `format` constraints that
|
|
12
|
+
* cause the Claude Code CLI to silently fall back to prose. Use .describe()
|
|
13
|
+
* with format hints instead, then validate client-side if strict format
|
|
14
|
+
* compliance is needed.
|
|
15
|
+
*
|
|
16
|
+
* Regex patterns WITHOUT lookaheads/lookbehinds work fine (e.g. /^\d{4}-\d{2}-\d{2}$/).
|
|
17
|
+
* Regex patterns WITH lookaheads ((?=...), (?!...)) cause silent fallback.
|
|
18
|
+
*
|
|
19
|
+
* See JSON_FIX.md for details.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { createClaudeCode } from '../dist/index.js';
|
|
23
|
+
import { generateObject } from 'ai';
|
|
24
|
+
import { z } from 'zod';
|
|
25
|
+
|
|
26
|
+
const claudeCode = createClaudeCode();
|
|
27
|
+
|
|
28
|
+
console.log('=== Claude Code: Constrained Object Generation ===\n');
|
|
29
|
+
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Example 1: Number ranges and integer constraints
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
async function example1_numberConstraints() {
|
|
34
|
+
console.log('1. Number Ranges and Integer Constraints\n');
|
|
35
|
+
|
|
36
|
+
const { object } = await generateObject({
|
|
37
|
+
model: claudeCode('opus'),
|
|
38
|
+
schema: z.object({
|
|
39
|
+
character: z.object({
|
|
40
|
+
name: z.string().min(3).max(20).describe('Character name'),
|
|
41
|
+
level: z.number().int().min(1).max(100),
|
|
42
|
+
experience: z.number().int().min(0).max(1000000),
|
|
43
|
+
stats: z.object({
|
|
44
|
+
health: z.number().int().min(100).max(9999),
|
|
45
|
+
mana: z.number().int().min(0).max(9999),
|
|
46
|
+
strength: z.number().int().min(1).max(99),
|
|
47
|
+
defense: z.number().int().min(1).max(99),
|
|
48
|
+
speed: z.number().int().min(1).max(99),
|
|
49
|
+
luck: z.number().int().min(1).max(10).describe('Luck stat (1-10)'),
|
|
50
|
+
}),
|
|
51
|
+
inventory: z.object({
|
|
52
|
+
gold: z.number().int().min(0).max(999999),
|
|
53
|
+
items: z.number().int().min(0).max(50).describe('Number of items (max 50)'),
|
|
54
|
+
weight: z.number().min(0).max(100).describe('Inventory weight in kg'),
|
|
55
|
+
}),
|
|
56
|
+
position: z.object({
|
|
57
|
+
x: z.number().min(-1000).max(1000),
|
|
58
|
+
y: z.number().min(-1000).max(1000),
|
|
59
|
+
z: z.number().min(0).max(500).describe('Altitude'),
|
|
60
|
+
}),
|
|
61
|
+
}),
|
|
62
|
+
}),
|
|
63
|
+
prompt: 'Generate a level 45 warrior character with balanced stats and moderate inventory.',
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
console.log('Generated character:');
|
|
67
|
+
console.log(JSON.stringify(object, null, 2));
|
|
68
|
+
console.log();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Example 2: String patterns, enums, and array constraints
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
async function example2_patternsAndArrays() {
|
|
75
|
+
console.log('2. String Patterns, Enums, and Array Constraints\n');
|
|
76
|
+
|
|
77
|
+
const { object } = await generateObject({
|
|
78
|
+
model: claudeCode('opus'),
|
|
79
|
+
schema: z.object({
|
|
80
|
+
registration: z.object({
|
|
81
|
+
// Simple regex (no lookaheads) — works with CLI constrained decoding
|
|
82
|
+
username: z
|
|
83
|
+
.string()
|
|
84
|
+
.min(3)
|
|
85
|
+
.max(20)
|
|
86
|
+
.regex(/^[a-zA-Z0-9_]+$/, 'Alphanumeric and underscore only'),
|
|
87
|
+
email: z.string().describe('Email address (e.g. user@example.com)'),
|
|
88
|
+
phone: z.string().regex(/^\+?[1-9]\d{1,14}$/, 'E.164 phone format'),
|
|
89
|
+
dateOfBirth: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'YYYY-MM-DD format'),
|
|
90
|
+
socialMedia: z.object({
|
|
91
|
+
twitter: z
|
|
92
|
+
.string()
|
|
93
|
+
.regex(/^@[a-zA-Z0-9_]{1,15}$/, 'Twitter handle format')
|
|
94
|
+
.optional(),
|
|
95
|
+
github: z
|
|
96
|
+
.string()
|
|
97
|
+
.describe('GitHub username (alphanumeric or hyphens, 1-39 characters)')
|
|
98
|
+
.optional(),
|
|
99
|
+
}),
|
|
100
|
+
preferences: z.object({
|
|
101
|
+
locale: z.string().regex(/^[a-z]{2}-[A-Z]{2}$/, 'Locale format like en-US'),
|
|
102
|
+
currency: z
|
|
103
|
+
.string()
|
|
104
|
+
.length(3)
|
|
105
|
+
.regex(/^[A-Z]{3}$/, 'ISO 4217 currency code'),
|
|
106
|
+
}),
|
|
107
|
+
}),
|
|
108
|
+
}),
|
|
109
|
+
prompt:
|
|
110
|
+
'Generate a user registration for a software developer from San Francisco with a GitHub account.',
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
console.log('Generated registration:');
|
|
114
|
+
console.log(JSON.stringify(object, null, 2));
|
|
115
|
+
console.log();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Example 3: Complex combined validations (invoice)
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
async function example3_complexCombined() {
|
|
122
|
+
console.log('3. Complex Combined Validations\n');
|
|
123
|
+
|
|
124
|
+
const { object } = await generateObject({
|
|
125
|
+
model: claudeCode('opus'),
|
|
126
|
+
schema: z.object({
|
|
127
|
+
invoice: z.object({
|
|
128
|
+
invoiceNumber: z.string().regex(/^INV-\d{4}-\d{6}$/, 'Format: INV-YYYY-XXXXXX'),
|
|
129
|
+
issueDate: z
|
|
130
|
+
.string()
|
|
131
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
132
|
+
.describe('Issue date in YYYY-MM-DD format'),
|
|
133
|
+
dueDate: z
|
|
134
|
+
.string()
|
|
135
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
136
|
+
.describe('Due date in YYYY-MM-DD format (after issue date)'),
|
|
137
|
+
status: z.enum(['draft', 'sent', 'paid', 'overdue', 'cancelled']),
|
|
138
|
+
client: z.object({
|
|
139
|
+
name: z.string().min(2).max(100),
|
|
140
|
+
taxId: z.string().regex(/^\d{2}-\d{7}$|^\d{3}-\d{2}-\d{4}$/, 'Tax ID format'),
|
|
141
|
+
email: z.string().describe('Client email address (e.g. billing@company.com)'),
|
|
142
|
+
address: z.object({
|
|
143
|
+
country: z
|
|
144
|
+
.string()
|
|
145
|
+
.length(2)
|
|
146
|
+
.regex(/^[A-Z]{2}$/, 'ISO country code'),
|
|
147
|
+
postalCode: z.string().min(3).max(10),
|
|
148
|
+
}),
|
|
149
|
+
}),
|
|
150
|
+
lineItems: z
|
|
151
|
+
.array(
|
|
152
|
+
z.object({
|
|
153
|
+
description: z.string().min(5).max(200),
|
|
154
|
+
quantity: z.number().positive().int().max(1000),
|
|
155
|
+
unitPrice: z.number().positive().multipleOf(0.01).max(10000),
|
|
156
|
+
taxRate: z.number().min(0).max(0.3).multipleOf(0.01),
|
|
157
|
+
discount: z.number().min(0).max(0.5).multipleOf(0.01).optional(),
|
|
158
|
+
})
|
|
159
|
+
)
|
|
160
|
+
.min(1)
|
|
161
|
+
.max(50),
|
|
162
|
+
payment: z.object({
|
|
163
|
+
terms: z.enum(['net-15', 'net-30', 'net-45', 'net-60', 'due-on-receipt']),
|
|
164
|
+
method: z.enum(['bank-transfer', 'credit-card', 'check', 'paypal', 'crypto']).optional(),
|
|
165
|
+
currency: z
|
|
166
|
+
.string()
|
|
167
|
+
.length(3)
|
|
168
|
+
.regex(/^[A-Z]{3}$/, 'ISO currency code'),
|
|
169
|
+
}),
|
|
170
|
+
totals: z.object({
|
|
171
|
+
subtotal: z.number().positive().multipleOf(0.01),
|
|
172
|
+
taxAmount: z.number().min(0).multipleOf(0.01),
|
|
173
|
+
discountAmount: z.number().min(0).multipleOf(0.01).optional(),
|
|
174
|
+
total: z.number().positive().multipleOf(0.01),
|
|
175
|
+
}),
|
|
176
|
+
}),
|
|
177
|
+
}),
|
|
178
|
+
prompt:
|
|
179
|
+
'Generate an invoice for web development services with 3 line items, sent to a US company, due in 30 days. Use a recent issue date and set the due date 30 days later.',
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
console.log('Generated invoice:');
|
|
183
|
+
console.log(JSON.stringify(object, null, 2));
|
|
184
|
+
console.log();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
// Main
|
|
189
|
+
// ---------------------------------------------------------------------------
|
|
190
|
+
async function main() {
|
|
191
|
+
try {
|
|
192
|
+
await example1_numberConstraints();
|
|
193
|
+
await example2_patternsAndArrays();
|
|
194
|
+
await example3_complexCombined();
|
|
195
|
+
|
|
196
|
+
console.log('All constraint examples completed!');
|
|
197
|
+
console.log('\nConstraint types demonstrated:');
|
|
198
|
+
console.log('- Number ranges with min/max/int/multipleOf');
|
|
199
|
+
console.log('- Simple regex patterns (no lookaheads)');
|
|
200
|
+
console.log('- String length constraints');
|
|
201
|
+
console.log('- Array length constraints (min/max)');
|
|
202
|
+
console.log('- Enums for fixed value sets');
|
|
203
|
+
console.log('- Complex combined validations');
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error('Error:', error);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
main().catch(console.error);
|