diff --git a/README.md b/README.md index 169c463..5d8751a 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,8 @@ import { createAgent, resumeSession } from '@letta-ai/letta-code-sdk'; // Create an agent with custom memory (has default conversation) const agentId = await createAgent({ - memory: ['persona', 'project'], - persona: 'You are a helpful coding assistant', - project: 'A TypeScript web application' + memory: ['persona'], + persona: 'You are a helpful coding assistant for TypeScript projects' }); // Resume the default conversation @@ -160,62 +159,7 @@ createSession(agentId, { - `codex` - Basic Codex - `gemini` - Basic Gemini -### Memory Blocks -Configure which memory blocks the session uses: - -```typescript -// Use default blocks (persona, human, project) -createSession(agentId); - -// Use specific preset blocks -createSession(agentId, { - memory: ['project', 'persona'] // Only these blocks -}); - -// Use custom blocks -createSession(agentId, { - memory: [ - { label: 'context', value: 'API documentation for Acme Corp...' }, - { label: 'rules', value: 'Always use TypeScript. Prefer functional patterns.' } - ] -}); - -// No optional blocks (only core skills blocks) -createSession(agentId, { - memory: [] -}); -``` - -### Convenience Props - -Quickly customize common memory blocks: - -```typescript -createSession(agentId, { - persona: 'You are a senior Python developer who writes clean, tested code.', - human: 'Name: Alice. Prefers concise responses.', - project: 'FastAPI backend for a todo app using PostgreSQL.' -}); -``` - -### Tool Execution - -Execute tools with automatic permission handling: - -```typescript -import { createAgent, createSession } from '@letta-ai/letta-code-sdk'; - -// Create agent and run commands -const agentId = await createAgent(); -const session = createSession(agentId, { - allowedTools: ['Glob', 'Bash'], - permissionMode: 'bypassPermissions', - cwd: '/path/to/project' -}); -await session.send('List all TypeScript files'); -for await (const msg of session.stream()) { /* ... */ } -``` ## API Reference @@ -251,9 +195,10 @@ await createAgent(); await createAgent({ model: 'claude-sonnet-4', systemPrompt: 'You are a helpful Python expert.', - memory: ['persona', 'project'], - persona: 'You are a senior Python developer', - project: 'FastAPI backend for a todo app' + memory: [ + { label: 'persona', value: 'You are a senior Python developer' }, + { label: 'project', value: 'FastAPI backend for a todo app' } + ] }); ``` diff --git a/examples/v2-examples.ts b/examples/v2-examples.ts index e499226..e102c5e 100644 --- a/examples/v2-examples.ts +++ b/examples/v2-examples.ts @@ -557,8 +557,8 @@ async function testMemoryConfig() { // Test 2: Specific preset blocks only console.log('Testing specific preset blocks...'); - const specificResult = await runWithMemory('List your memory block labels', ['project']); - console.log(` specific blocks [project]: ${specificResult.success ? 'PASS' : 'FAIL'}`); + const specificResult = await runWithMemory('List your memory block labels', ['persona']); + console.log(` specific blocks [persona]: ${specificResult.success ? 'PASS' : 'FAIL'}`); // Test 3: Custom blocks console.log('Testing custom memory blocks...'); @@ -570,13 +570,13 @@ async function testMemoryConfig() { console.log(` custom blocks: ${customResult.success ? 'PASS' : 'FAIL'}`); console.log(` Response is concise: ${isConcise ? 'yes' : 'check'}`); - // Test 4: Mixed preset and custom blocks - console.log('Testing mixed blocks (preset + custom)...'); - const mixedResult = await runWithMemory( + // Test 4: Multiple preset blocks + console.log('Testing multiple preset blocks...'); + const multipleResult = await runWithMemory( 'List your memory blocks', - ['project', { label: 'custom-context', value: 'This is a test context block.' }] + ['persona', 'human'] ); - console.log(` mixed blocks: ${mixedResult.success ? 'PASS' : 'FAIL'}`); + console.log(` multiple presets: ${multipleResult.success ? 'PASS' : 'FAIL'}`); // Test 5: Empty memory (core blocks only) console.log('Testing empty memory (core only)...'); @@ -620,16 +620,16 @@ async function testConvenienceProps() { console.log(` persona: ${personaResult.success ? 'PASS' : 'FAIL'}`); console.log(` Response mentions cooking/Italian: ${hasItalian ? 'yes' : 'check'}`); - // Test 2: project prop - console.log('Testing project prop...'); + // Test 2: project block (custom) + console.log('Testing project block (custom)...'); const projectResult = await runWithProps( 'What project are you helping with?', - { project: 'A React Native mobile app for tracking daily habits.' } + { memory: [{ label: 'project', value: 'A React Native mobile app for tracking daily habits.' }] } ); const hasProject = projectResult.result.toLowerCase().includes('react') || projectResult.result.toLowerCase().includes('habit') || projectResult.result.toLowerCase().includes('mobile'); - console.log(` project: ${projectResult.success ? 'PASS' : 'FAIL'}`); + console.log(` project (custom): ${projectResult.success ? 'PASS' : 'FAIL'}`); console.log(` Response mentions project: ${hasProject ? 'yes' : 'check'}`); // Test 3: human prop @@ -646,8 +646,12 @@ async function testConvenienceProps() { // Test 4: Multiple convenience props together console.log('Testing multiple convenience props...'); const multiResult = await runWithProps( - 'Introduce yourself and the project briefly', - { persona: 'You are a friendly code reviewer.', project: 'FastAPI backend service.', human: 'Name: Alice.' } + 'Introduce yourself briefly', + { + memory: ['persona', 'human'], + persona: 'You are a friendly code reviewer.', + human: 'Name: Alice.' + } ); console.log(` multiple props: ${multiResult.success ? 'PASS' : 'FAIL'}`); console.log(` Response: ${multiResult.result.slice(0, 100)}...`); @@ -656,7 +660,7 @@ async function testConvenienceProps() { console.log('Testing convenience props with memory config...'); const combinedResult = await runWithProps( 'What is in your persona block?', - { memory: ['persona', 'project'], persona: 'You are a database expert specializing in PostgreSQL.' } + { memory: ['persona'], persona: 'You are a database expert specializing in PostgreSQL.' } ); const hasDB = combinedResult.result.toLowerCase().includes('database') || combinedResult.result.toLowerCase().includes('postgresql'); diff --git a/src/transport.ts b/src/transport.ts index c7661ed..ae3415f 100644 --- a/src/transport.ts +++ b/src/transport.ts @@ -258,14 +258,20 @@ export class SubprocessTransport { } } - // Add preset names via --init-blocks - if (presetNames.length > 0) { - args.push("--init-blocks", presetNames.join(",")); - } - - // Add custom blocks and block references via --memory-blocks + // NOTE: When custom blocks are provided via --memory-blocks, they define the complete + // memory configuration. Preset blocks (--init-blocks) cannot be mixed with custom blocks. if (memoryBlocksJson.length > 0) { + // Use custom blocks only args.push("--memory-blocks", JSON.stringify(memoryBlocksJson)); + if (presetNames.length > 0) { + console.warn( + "[letta-code-sdk] Using custom memory blocks. " + + `Preset blocks are ignored when custom blocks are provided: ${presetNames.join(", ")}` + ); + } + } else if (presetNames.length > 0) { + // Use presets only + args.push("--init-blocks", presetNames.join(",")); } } } @@ -278,9 +284,6 @@ export class SubprocessTransport { if (this.options.human !== undefined) { args.push("--block-value", `human=${this.options.human}`); } - if (this.options.project !== undefined) { - args.push("--block-value", `project=${this.options.project}`); - } } // Permission mode diff --git a/src/types.ts b/src/types.ts index efeff2f..9c3aa81 100644 --- a/src/types.ts +++ b/src/types.ts @@ -113,7 +113,7 @@ export type MemoryItem = /** * Default memory block preset names. */ -export type MemoryPreset = "persona" | "human" | "project"; +export type MemoryPreset = "persona" | "human" | "skills" | "loaded_skills"; // ═══════════════════════════════════════════════════════════════ // SESSION OPTIONS @@ -147,9 +147,8 @@ export interface InternalSessionOptions { // Memory blocks (only for new agents) memory?: MemoryItem[]; - persona?: string; - human?: string; - project?: string; + persona?: string; // Convenience for persona block + human?: string; // Convenience for human block // Permissions allowedTools?: string[]; @@ -203,8 +202,8 @@ export interface CreateAgentOptions { /** * Memory block configuration. Each item can be: - * - string: Preset block name ("project", "persona", "human") - * - CreateBlock: Custom block definition + * - string: Preset block name ("persona", "human", "skills", "loaded_skills") + * - CreateBlock: Custom block definition (e.g., { label: "project", value: "..." }) * - { blockId: string }: Reference to existing shared block */ memory?: MemoryItem[]; @@ -215,9 +214,6 @@ export interface CreateAgentOptions { /** Convenience: Set human block value directly */ human?: string; - /** Convenience: Set project block value directly */ - project?: string; - /** List of allowed tool names */ allowedTools?: string[]; diff --git a/src/validation.ts b/src/validation.ts index cbb83f4..def50b2 100644 --- a/src/validation.ts +++ b/src/validation.ts @@ -77,13 +77,6 @@ export function validateCreateAgentOptions(options: CreateAgentOptions): void { "Either add 'human' to memory array or remove the human option." ); } - - if (options.project !== undefined && !blockLabels.includes("project")) { - throw new Error( - "Cannot set 'project' value - block not included in 'memory'. " + - "Either add 'project' to memory array or remove the project option." - ); - } } // Validate systemPrompt preset if provided as preset object