#!/usr/bin/env bun /** * Letta Code SDK V2 Examples * * Comprehensive tests for all SDK features. * * Run with: bun examples/v2-examples.ts [example] */ import { createSession, resumeSession, resumeConversation, prompt } from '../src/index.js'; 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);