fix: memory blocks config on createAgent (#21)
This commit is contained in:
67
README.md
67
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' }
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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
|
||||
|
||||
14
src/types.ts
14
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[];
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user