Files
letta-code-sdk/examples/v2-examples.ts
cpacker ee7cc92724 Initial release of Letta Code SDK
Programmatic control of Letta Code CLI with persistent agent memory.

Features:
- createSession() / resumeSession() / prompt() API
- resumeConversation() for multi-threaded conversations
- Multi-turn conversations with memory
- Tool execution (Bash, Read, Edit, etc.)
- System prompt and memory configuration
- Permission callbacks (canUseTool)
- Message streaming with typed events

👾 Generated with [Letta Code](https://letta.com)
2026-01-27 00:30:09 -08:00

823 lines
31 KiB
TypeScript

#!/usr/bin/env bun
/**
* Letta Code SDK V2 Examples
*
* Comprehensive tests for all SDK features.
* Parallel to Claude Agent SDK V2 examples.
*
* Run with: LETTA_CLI_PATH=path/to/letta.js bun v2-examples.ts [example]
*/
import { createSession, resumeSession, resumeConversation, prompt } from '../src/index.js';
const CLI_PATH = process.env.LETTA_CLI_PATH;
if (!CLI_PATH) {
console.error('Set LETTA_CLI_PATH environment variable');
process.exit(1);
}
async function main() {
const example = process.argv[2] || 'basic';
switch (example) {
case 'basic':
await basicSession();
break;
case 'multi-turn':
await multiTurn();
break;
case 'one-shot':
await oneShot();
break;
case 'resume':
await sessionResume();
break;
case 'options':
await testOptions();
break;
case 'message-types':
await testMessageTypes();
break;
case 'session-properties':
await testSessionProperties();
break;
case 'tool-execution':
await testToolExecution();
break;
case 'permission-callback':
await testPermissionCallback();
break;
case 'system-prompt':
await testSystemPrompt();
break;
case 'memory-config':
await testMemoryConfig();
break;
case 'convenience-props':
await testConvenienceProps();
break;
case 'conversations':
await testConversations();
break;
case 'all':
await basicSession();
await multiTurn();
await oneShot();
await sessionResume();
await testOptions();
await testMessageTypes();
await testSessionProperties();
await testToolExecution();
await testPermissionCallback();
await testSystemPrompt();
await testMemoryConfig();
await testConvenienceProps();
await testConversations();
console.log('\n✅ All examples passed');
break;
default:
console.log('Usage: bun v2-examples.ts [basic|multi-turn|one-shot|resume|options|message-types|session-properties|tool-execution|permission-callback|system-prompt|memory-config|convenience-props|conversations|all]');
}
}
// ═══════════════════════════════════════════════════════════════
// BASIC EXAMPLES
// ═══════════════════════════════════════════════════════════════
// Basic session with send/receive pattern
async function basicSession() {
console.log('=== Basic Session ===\n');
await using session = createSession({
model: 'haiku',
permissionMode: 'bypassPermissions',
});
await session.send('Hello! Introduce yourself in one sentence.');
let response = '';
for await (const msg of session.stream()) {
if (msg.type === 'assistant') {
response += msg.content;
}
if (msg.type === 'result') {
console.log(`Letta: ${response.trim()}`);
console.log(`[Result: ${msg.success ? 'success' : 'failed'}, ${msg.durationMs}ms]`);
}
}
console.log();
}
// Multi-turn conversation
async function multiTurn() {
console.log('=== Multi-Turn Conversation ===\n');
await using session = createSession({
model: 'haiku',
permissionMode: 'bypassPermissions',
});
// Turn 1
await session.send('What is 5 + 3? Just the number.');
let turn1Result = '';
for await (const msg of session.stream()) {
if (msg.type === 'assistant') turn1Result += msg.content;
}
console.log(`Turn 1: ${turn1Result.trim()}`);
// Turn 2 - agent remembers context
await session.send('Multiply that by 2. Just the number.');
let turn2Result = '';
for await (const msg of session.stream()) {
if (msg.type === 'assistant') turn2Result += msg.content;
}
console.log(`Turn 2: ${turn2Result.trim()}`);
console.log();
}
// One-shot convenience function
async function oneShot() {
console.log('=== One-Shot Prompt ===\n');
const result = await prompt('What is the capital of France? One word.', {
model: 'haiku',
permissionMode: 'bypassPermissions',
});
if (result.success) {
console.log(`Answer: ${result.result}`);
console.log(`Duration: ${result.durationMs}ms`);
} else {
console.log(`Error: ${result.error}`);
}
console.log();
}
// Session resume - with PERSISTENT MEMORY
async function sessionResume() {
console.log('=== Session Resume (Persistent Memory) ===\n');
let agentId: string | null = null;
// First session - establish a memory
{
const session = createSession({
model: 'haiku',
permissionMode: 'bypassPermissions',
});
console.log('[Session 1] Teaching agent a secret word...');
await session.send('Remember this secret word: "pineapple". Store it in your memory.');
let response = '';
for await (const msg of session.stream()) {
if (msg.type === 'assistant') response += msg.content;
if (msg.type === 'result') {
console.log(`[Session 1] Agent: ${response.trim()}`);
}
}
agentId = session.agentId;
console.log(`[Session 1] Agent ID: ${agentId}\n`);
session.close();
}
console.log('--- Session closed. Agent persists on server. ---\n');
// Resume and verify agent remembers
{
await using session = resumeSession(agentId!, {
permissionMode: 'bypassPermissions',
});
console.log('[Session 2] Asking agent for the secret word...');
await session.send('What is the secret word I told you to remember?');
let response = '';
for await (const msg of session.stream()) {
if (msg.type === 'assistant') response += msg.content;
if (msg.type === 'result') {
console.log(`[Session 2] Agent: ${response.trim()}`);
}
}
}
console.log();
}
// ═══════════════════════════════════════════════════════════════
// OPTIONS TESTS
// ═══════════════════════════════════════════════════════════════
async function testOptions() {
console.log('=== Testing Options ===\n');
// Test model option
console.log('Testing model option...');
const modelResult = await prompt('Say "model test ok"', {
model: 'haiku',
permissionMode: 'bypassPermissions',
});
console.log(` model: ${modelResult.success ? 'PASS' : 'FAIL'} - ${modelResult.result?.slice(0, 50)}`);
// Test systemPrompt option
console.log('Testing systemPrompt option...');
const sysPromptResult = await prompt('Tell me a fun fact about penguins in one sentence.', {
model: 'haiku',
systemPrompt: 'You love penguins and always try to work penguin facts into conversations.',
permissionMode: 'bypassPermissions',
});
const hasPenguin = sysPromptResult.result?.toLowerCase().includes('penguin');
console.log(` systemPrompt: ${hasPenguin ? 'PASS' : 'PARTIAL'} - ${sysPromptResult.result?.slice(0, 80)}`);
// Test cwd option
console.log('Testing cwd option...');
const cwdResult = await prompt('Run pwd to show current directory', {
model: 'haiku',
cwd: '/tmp',
allowedTools: ['Bash'],
permissionMode: 'bypassPermissions',
});
const hasTmp = cwdResult.result?.includes('/tmp');
console.log(` cwd: ${hasTmp ? 'PASS' : 'CHECK'} - ${cwdResult.result?.slice(0, 60)}`);
// Test allowedTools option with tool execution
console.log('Testing allowedTools option...');
const toolsResult = await prompt('Run: echo tool-test-ok', {
model: 'haiku',
allowedTools: ['Bash'],
permissionMode: 'bypassPermissions',
});
const hasToolOutput = toolsResult.result?.includes('tool-test-ok');
console.log(` allowedTools: ${hasToolOutput ? 'PASS' : 'CHECK'} - ${toolsResult.result?.slice(0, 60)}`);
// Test permissionMode: bypassPermissions
console.log('Testing permissionMode: bypassPermissions...');
const bypassResult = await prompt('Run: echo bypass-test', {
model: 'haiku',
allowedTools: ['Bash'],
permissionMode: 'bypassPermissions',
});
const hasBypassOutput = bypassResult.result?.includes('bypass-test');
console.log(` permissionMode: ${hasBypassOutput ? 'PASS' : 'CHECK'}`);
console.log();
}
// ═══════════════════════════════════════════════════════════════
// MESSAGE TYPES TESTS
// ═══════════════════════════════════════════════════════════════
async function testMessageTypes() {
console.log('=== Testing Message Types ===\n');
const session = createSession({
model: 'haiku',
permissionMode: 'bypassPermissions',
});
await session.send('Say "hello" exactly');
let sawAssistant = false;
let sawResult = false;
let assistantContent = '';
for await (const msg of session.stream()) {
if (msg.type === 'assistant') {
sawAssistant = true;
assistantContent += msg.content;
// Verify assistant message has uuid
if (!msg.uuid) {
console.log(' assistant.uuid: FAIL - missing uuid');
}
}
if (msg.type === 'result') {
sawResult = true;
// Verify result message structure
const hasSuccess = typeof msg.success === 'boolean';
const hasDuration = typeof msg.durationMs === 'number';
console.log(` result.success: ${hasSuccess ? 'PASS' : 'FAIL'}`);
console.log(` result.durationMs: ${hasDuration ? 'PASS' : 'FAIL'}`);
console.log(` result.result: ${msg.result ? 'PASS' : 'FAIL (empty)'}`);
}
}
console.log(` assistant message received: ${sawAssistant ? 'PASS' : 'FAIL'}`);
console.log(` result message received: ${sawResult ? 'PASS' : 'FAIL'}`);
session.close();
console.log();
}
// ═══════════════════════════════════════════════════════════════
// SESSION PROPERTIES TESTS
// ═══════════════════════════════════════════════════════════════
async function testSessionProperties() {
console.log('=== Testing Session Properties ===\n');
const session = createSession({
model: 'haiku',
permissionMode: 'bypassPermissions',
});
// Before send - properties should be null
console.log(` agentId before send: ${session.agentId === null ? 'PASS (null)' : 'FAIL'}`);
console.log(` sessionId before send: ${session.sessionId === null ? 'PASS (null)' : 'FAIL'}`);
await session.send('Hi');
for await (const _ of session.stream()) {
// drain
}
// After send - properties should be set
const hasAgentId = session.agentId !== null && session.agentId.startsWith('agent-');
const hasSessionId = session.sessionId !== null;
console.log(` agentId after send: ${hasAgentId ? 'PASS' : 'FAIL'} - ${session.agentId}`);
console.log(` sessionId after send: ${hasSessionId ? 'PASS' : 'FAIL'} - ${session.sessionId}`);
// Test close()
session.close();
console.log(` close(): PASS (no error)`);
console.log();
}
// ═══════════════════════════════════════════════════════════════
// TOOL EXECUTION TESTS
// ═══════════════════════════════════════════════════════════════
async function testToolExecution() {
console.log('=== Testing Tool Execution ===\n');
// Test 1: Basic command execution
console.log('Testing basic command execution...');
const echoResult = await prompt('Run: echo hello-world', {
model: 'haiku',
allowedTools: ['Bash'],
permissionMode: 'bypassPermissions',
});
const hasHello = echoResult.result?.includes('hello-world');
console.log(` echo command: ${hasHello ? 'PASS' : 'FAIL'}`);
// Test 2: Command with arguments
console.log('Testing command with arguments...');
const argsResult = await prompt('Run: echo "arg1 arg2 arg3"', {
model: 'haiku',
allowedTools: ['Bash'],
permissionMode: 'bypassPermissions',
});
const hasArgs = argsResult.result?.includes('arg1') && argsResult.result?.includes('arg3');
console.log(` echo with args: ${hasArgs ? 'PASS' : 'FAIL'}`);
// Test 3: File reading with Glob
console.log('Testing Glob tool...');
const globResult = await prompt('List all .ts files in the current directory using Glob', {
model: 'haiku',
allowedTools: ['Glob'],
permissionMode: 'bypassPermissions',
});
console.log(` Glob tool: ${globResult.success ? 'PASS' : 'FAIL'}`);
// Test 4: Multi-step tool usage (agent decides which tools to use)
console.log('Testing multi-step tool usage...');
const multiResult = await prompt('First run "echo step1", then run "echo step2". Show me both outputs.', {
model: 'haiku',
allowedTools: ['Bash'],
permissionMode: 'bypassPermissions',
});
const hasStep1 = multiResult.result?.includes('step1');
const hasStep2 = multiResult.result?.includes('step2');
console.log(` multi-step: ${hasStep1 && hasStep2 ? 'PASS' : 'PARTIAL'} (step1: ${hasStep1}, step2: ${hasStep2})`);
console.log();
}
// ═══════════════════════════════════════════════════════════════
// PERMISSION CALLBACK TESTS
// ═══════════════════════════════════════════════════════════════
async function testPermissionCallback() {
console.log('=== Testing Permission Callback ===\n');
// Note: permissionMode 'default' with NO allowedTools triggers callback
// allowedTools auto-allows tools, bypassing the callback
// Test 1: Allow specific commands via callback
console.log('Testing canUseTool callback (allow)...');
const allowResult = await prompt('Run: echo callback-allowed', {
model: 'haiku',
// NO allowedTools - this ensures callback is invoked
permissionMode: 'default',
canUseTool: async (toolName, toolInput) => {
console.error('CALLBACK:', toolName, toolInput);
const command = (toolInput as { command?: string }).command || '';
if (command.includes('callback-allowed')) {
return { allow: true, reason: 'Command whitelisted' };
}
return { allow: false, reason: 'Command not whitelisted' };
},
});
const hasAllowed = allowResult.result?.includes('callback-allowed');
console.log(` allow via callback: ${hasAllowed ? 'PASS' : 'FAIL'}`);
// Test 2: Deny specific commands via callback
console.log('Testing canUseTool callback (deny)...');
const denyResult = await prompt('Run: echo dangerous-command', {
model: 'haiku',
permissionMode: 'default',
canUseTool: async (toolName, toolInput) => {
const command = (toolInput as { command?: string }).command || '';
if (command.includes('dangerous')) {
return { allow: false, reason: 'Dangerous command blocked' };
}
return { allow: true };
},
});
// Agent should report that it couldn't execute the command
const wasDenied = !denyResult.result?.includes('dangerous-command');
console.log(` deny via callback: ${wasDenied ? 'PASS' : 'CHECK'}`);
console.log();
}
// ═══════════════════════════════════════════════════════════════
// SYSTEM PROMPT TESTS
// ═══════════════════════════════════════════════════════════════
async function testSystemPrompt() {
console.log('=== Testing System Prompt Configuration ===\n');
// Test 1: Preset system prompt
console.log('Testing preset system prompt...');
const presetResult = await prompt('What kind of agent are you? One sentence.', {
model: 'haiku',
systemPrompt: { type: 'preset', preset: 'letta-claude' },
permissionMode: 'bypassPermissions',
});
console.log(` preset (letta-claude): ${presetResult.success ? 'PASS' : 'FAIL'}`);
console.log(` Response: ${presetResult.result?.slice(0, 80)}...`);
// Test 2: Preset with append
console.log('Testing preset with append...');
const appendResult = await prompt('Say hello', {
model: 'haiku',
systemPrompt: {
type: 'preset',
preset: 'letta-claude',
append: 'Always end your responses with "🎉"'
},
permissionMode: 'bypassPermissions',
});
const hasEmoji = appendResult.result?.includes('🎉');
console.log(` preset with append: ${hasEmoji ? 'PASS' : 'CHECK'}`);
console.log(` Response: ${appendResult.result?.slice(0, 80)}...`);
// Test 3: Custom string system prompt
console.log('Testing custom string system prompt...');
const customResult = await prompt('What is your specialty?', {
model: 'haiku',
systemPrompt: 'You are a pirate captain. Always speak like a pirate.',
permissionMode: 'bypassPermissions',
});
const hasPirateSpeak = customResult.result?.toLowerCase().includes('arr') ||
customResult.result?.toLowerCase().includes('matey') ||
customResult.result?.toLowerCase().includes('ship');
console.log(` custom string: ${customResult.success ? 'PASS' : 'FAIL'}`);
console.log(` Response: ${customResult.result?.slice(0, 80)}...`);
// Test 4: Basic preset (claude - no skills/memory)
console.log('Testing basic preset (claude)...');
const basicResult = await prompt('Hello, just say hi back', {
model: 'haiku',
systemPrompt: { type: 'preset', preset: 'claude' },
permissionMode: 'bypassPermissions',
});
console.log(` basic preset (claude): ${basicResult.success ? 'PASS' : 'FAIL'}`);
console.log();
}
// ═══════════════════════════════════════════════════════════════
// MEMORY CONFIGURATION TESTS
// ═══════════════════════════════════════════════════════════════
async function testMemoryConfig() {
console.log('=== Testing Memory Configuration ===\n');
// Test 1: Default memory (persona, human, project)
console.log('Testing default memory blocks...');
const defaultResult = await prompt('What memory blocks do you have? List their labels.', {
model: 'haiku',
permissionMode: 'bypassPermissions',
});
const hasDefaultBlocks = defaultResult.result?.includes('persona') ||
defaultResult.result?.includes('project');
console.log(` default blocks: ${defaultResult.success ? 'PASS' : 'FAIL'}`);
console.log(` Response mentions blocks: ${hasDefaultBlocks ? 'yes' : 'check manually'}`);
// Test 2: Specific preset blocks only
console.log('Testing specific preset blocks...');
const specificResult = await prompt('List your memory block labels', {
model: 'haiku',
memory: ['project'],
permissionMode: 'bypassPermissions',
});
console.log(` specific blocks [project]: ${specificResult.success ? 'PASS' : 'FAIL'}`);
// Test 3: Custom blocks
console.log('Testing custom memory blocks...');
const customResult = await prompt('What does your "rules" memory block say?', {
model: 'haiku',
memory: [
{ label: 'rules', value: 'Always be concise. Never use more than 10 words.' }
],
permissionMode: 'bypassPermissions',
});
const isConcise = (customResult.result?.split(' ').length || 0) < 20;
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 prompt('List your memory blocks', {
model: 'haiku',
memory: [
'project',
{ label: 'custom-context', value: 'This is a test context block.' }
],
permissionMode: 'bypassPermissions',
});
console.log(` mixed blocks: ${mixedResult.success ? 'PASS' : 'FAIL'}`);
// Test 5: Empty memory (core blocks only)
console.log('Testing empty memory (core only)...');
const emptyResult = await prompt('Hello', {
model: 'haiku',
memory: [],
permissionMode: 'bypassPermissions',
});
console.log(` empty memory: ${emptyResult.success ? 'PASS' : 'FAIL'}`);
console.log();
}
// ═══════════════════════════════════════════════════════════════
// CONVENIENCE PROPS TESTS
// ═══════════════════════════════════════════════════════════════
async function testConvenienceProps() {
console.log('=== Testing Convenience Props ===\n');
// Test 1: persona prop
console.log('Testing persona prop...');
const personaResult = await prompt('Describe your personality in one sentence', {
model: 'haiku',
persona: 'You are an enthusiastic cooking assistant who loves Italian food.',
permissionMode: 'bypassPermissions',
});
const hasItalian = personaResult.result?.toLowerCase().includes('italian') ||
personaResult.result?.toLowerCase().includes('cook');
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...');
const projectResult = await prompt('What project are you helping with?', {
model: 'haiku',
project: 'A React Native mobile app for tracking daily habits.',
permissionMode: 'bypassPermissions',
});
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(` Response mentions project: ${hasProject ? 'yes' : 'check'}`);
// Test 3: human prop
console.log('Testing human prop...');
const humanResult = await prompt('What do you know about me?', {
model: 'haiku',
human: 'Name: Bob. Senior developer. Prefers TypeScript over JavaScript.',
permissionMode: 'bypassPermissions',
});
const hasHuman = humanResult.result?.toLowerCase().includes('bob') ||
humanResult.result?.toLowerCase().includes('typescript');
console.log(` human: ${humanResult.success ? 'PASS' : 'FAIL'}`);
console.log(` Response mentions user info: ${hasHuman ? 'yes' : 'check'}`);
// Test 4: Multiple convenience props together
console.log('Testing multiple convenience props...');
const multiResult = await prompt('Introduce yourself and the project briefly', {
model: 'haiku',
persona: 'You are a friendly code reviewer.',
project: 'FastAPI backend service.',
human: 'Name: Alice.',
permissionMode: 'bypassPermissions',
});
console.log(` multiple props: ${multiResult.success ? 'PASS' : 'FAIL'}`);
console.log(` Response: ${multiResult.result?.slice(0, 100)}...`);
// Test 5: Convenience props with specific memory blocks
console.log('Testing convenience props with memory config...');
const combinedResult = await prompt('What is in your persona block?', {
model: 'haiku',
memory: ['persona', 'project'],
persona: 'You are a database expert specializing in PostgreSQL.',
permissionMode: 'bypassPermissions',
});
const hasDB = combinedResult.result?.toLowerCase().includes('database') ||
combinedResult.result?.toLowerCase().includes('postgresql');
console.log(` props with memory: ${combinedResult.success ? 'PASS' : 'FAIL'}`);
console.log(` Response mentions DB: ${hasDB ? 'yes' : 'check'}`);
console.log();
}
// ═══════════════════════════════════════════════════════════════
// CONVERSATION TESTS
// ═══════════════════════════════════════════════════════════════
async function testConversations() {
console.log('=== Testing Conversation Support ===\n');
let agentId: string | null = null;
let conversationId1: string | null = null;
let conversationId2: string | null = null;
// Test 1: Create session and get conversationId (default)
console.log('Test 1: Create session and get conversationId...');
{
const session = createSession({
model: 'haiku',
permissionMode: 'bypassPermissions',
});
await session.send('Remember: the secret code is ALPHA. Store this in memory.');
for await (const msg of session.stream()) {
// drain
}
agentId = session.agentId;
conversationId1 = session.conversationId;
const hasAgentId = agentId !== null && agentId.startsWith('agent-');
const hasConvId = conversationId1 !== null;
console.log(` agentId: ${hasAgentId ? 'PASS' : 'FAIL'} - ${agentId}`);
console.log(` conversationId: ${hasConvId ? 'PASS' : 'FAIL'} - ${conversationId1}`);
// Note: "default" is a sentinel meaning the agent's primary message history
if (conversationId1 === 'default') {
console.log(' (conversationId "default" = agent\'s primary history, not a real conversation ID)');
}
session.close();
}
// Test 2: Create NEW conversation to get a real conversation ID
console.log('\nTest 2: Create new conversation (newConversation: true)...');
{
const session = resumeSession(agentId!, {
newConversation: true,
permissionMode: 'bypassPermissions',
});
await session.send('Remember: the secret code for THIS conversation is BETA.');
for await (const msg of session.stream()) {
// drain
}
conversationId1 = session.conversationId;
const isRealConvId = conversationId1 !== null && conversationId1 !== 'default';
console.log(` newConversation created: ${isRealConvId ? 'PASS' : 'FAIL'}`);
console.log(` conversationId: ${conversationId1}`);
session.close();
}
// Test 3: Resume conversation by conversationId (only works with real conv IDs)
console.log('\nTest 3: Resume conversation by conversationId...');
if (conversationId1 === 'default') {
console.log(' SKIP - "default" is not a real conversation ID');
console.log(' Use resumeSession(agentId) to resume default conversation');
} else {
await using session = resumeConversation(conversationId1!, {
permissionMode: 'bypassPermissions',
});
await session.send('What is the secret code for this conversation?');
let response = '';
for await (const msg of session.stream()) {
if (msg.type === 'assistant') response += msg.content;
}
const remembers = response.toLowerCase().includes('beta');
console.log(` resumeConversation: ${remembers ? 'PASS' : 'FAIL'}`);
console.log(` Response: ${response.slice(0, 80)}...`);
// Verify same conversationId
const sameConv = session.conversationId === conversationId1;
console.log(` same conversationId: ${sameConv ? 'PASS' : 'FAIL'}`);
}
// Test 4: Create another new conversation (verify different IDs)
console.log('\nTest 4: Create another new conversation...');
{
await using session = resumeSession(agentId!, {
newConversation: true,
permissionMode: 'bypassPermissions',
});
await session.send('Say "third conversation"');
let response = '';
for await (const msg of session.stream()) {
if (msg.type === 'assistant') response += msg.content;
}
conversationId2 = session.conversationId;
// New conversation should have different ID
const differentConv = conversationId2 !== conversationId1;
console.log(` different from conversationId1: ${differentConv ? 'PASS' : 'FAIL'}`);
console.log(` conversationId1: ${conversationId1}`);
console.log(` conversationId2: ${conversationId2}`);
}
// Test 5: defaultConversation option
console.log('\nTest 5: defaultConversation option...');
{
await using session = resumeSession(agentId!, {
defaultConversation: true,
permissionMode: 'bypassPermissions',
});
await session.send('Say "default conversation test ok"');
let response = '';
for await (const msg of session.stream()) {
if (msg.type === 'assistant') response += msg.content;
}
const hasDefaultConv = session.conversationId === 'default' || session.conversationId !== null;
console.log(` defaultConversation: ${hasDefaultConv ? 'PASS' : 'CHECK'}`);
console.log(` conversationId: ${session.conversationId}`);
}
// Test 6: conversationId in result message
console.log('\nTest 6: conversationId in result message...');
{
await using session = resumeConversation(conversationId1!, {
permissionMode: 'bypassPermissions',
});
await session.send('Hi');
let resultConvId: string | null = null;
for await (const msg of session.stream()) {
if (msg.type === 'result') {
resultConvId = msg.conversationId;
}
}
const hasResultConvId = resultConvId !== null;
const matchesSession = resultConvId === session.conversationId;
console.log(` result.conversationId: ${hasResultConvId ? 'PASS' : 'FAIL'}`);
console.log(` matches session.conversationId: ${matchesSession ? 'PASS' : 'FAIL'}`);
}
// Test 7: continue option (resume last session)
console.log('\nTest 7: continue option...');
{
// Note: This test may behave differently depending on local state
// The --continue flag resumes the last used agent + conversation
try {
await using session = createSession({
continue: true,
permissionMode: 'bypassPermissions',
});
await session.send('Say "continue test ok"');
for await (const msg of session.stream()) {
// drain
}
const hasIds = session.agentId !== null && session.conversationId !== null;
console.log(` continue: ${hasIds ? 'PASS' : 'CHECK'}`);
console.log(` agentId: ${session.agentId}`);
console.log(` conversationId: ${session.conversationId}`);
} catch (err) {
// --continue may fail if no previous session exists
console.log(` continue: SKIP (no previous session)`);
}
}
console.log();
}
main().catch(console.error);