Send separate assistant messages as separate channel messages (#31)

* Send separate assistant messages as separate channel messages

Track assistant message UUIDs to detect when a new assistant message
starts. This allows the agent to send multiple messages in response
to a single user message, appearing as separate bubbles.

Complements the existing message-type-change detection with UUID-based
separation for consecutive assistant messages.

Written by Cameron ◯ Letta Code

"Communication works best when it's broken into digestible pieces."

* Clean up bot logging and add message bubble separation

- Remove verbose diagnostic logging (API key, base URL, node version)
- Add useful event logging: tool calls, message sends
- Add UUID-based detection for separate assistant messages
- Messages now appear as separate bubbles when UUID changes

Written by Cameron ◯ Letta Code

"Good logging tells you what happened, not what you already know."
This commit is contained in:
Cameron
2026-01-30 13:45:08 -08:00
committed by GitHub
parent c68ead7a40
commit 76ea0da8fd

View File

@@ -181,13 +181,11 @@ export class LettaBot {
try {
if (this.store.agentId) {
process.env.LETTA_AGENT_ID = this.store.agentId;
console.log(`[Bot] Resuming session for agent ${this.store.agentId}`);
console.log(`[Bot] LETTA_BASE_URL=${process.env.LETTA_BASE_URL}`);
console.log(`[Bot] LETTA_API_KEY=${process.env.LETTA_API_KEY ? '(set)' : '(not set)'}`);
// Don't pass model when resuming - agent already has its model configured
session = resumeSession(this.store.agentId, baseOptions);
} else {
console.log('[Bot] Creating new session');
// Only pass model when creating a new agent
session = createSession({ ...baseOptions, model: this.config.model, memory: loadMemoryBlocks(this.config.agentName) });
}
@@ -207,14 +205,7 @@ export class LettaBot {
}
};
// Log diagnostic info for debugging connection issues
console.log('[Bot] Initializing session...');
console.log('[Bot] API key set:', !!process.env.LETTA_API_KEY);
console.log('[Bot] Base URL:', process.env.LETTA_BASE_URL || 'https://api.letta.com (default)');
console.log('[Bot] Node version:', process.version);
const initInfo = await withTimeout(session.initialize(), 'Session initialize');
console.log('[Bot] Session initialized, agent:', initInfo.agentId);
// Send message to agent with metadata envelope
const formattedMessage = formatMessageEnvelope(msg);
@@ -230,6 +221,7 @@ export class LettaBot {
let lastUpdate = Date.now();
let messageId: string | null = null;
let lastMsgType: string | null = null;
let lastAssistantUuid: string | null = null;
let sentAnyMessage = false;
// Helper to finalize and send current accumulated response
@@ -242,6 +234,8 @@ export class LettaBot {
await adapter.sendMessage({ chatId: msg.chatId, text: response, threadId: msg.threadId });
}
sentAnyMessage = true;
const preview = response.length > 50 ? response.slice(0, 50) + '...' : response;
console.log(`[Bot] Sent: "${preview}"`);
} catch {
// Ignore send errors
}
@@ -259,14 +253,34 @@ export class LettaBot {
try {
for await (const streamMsg of session.stream()) {
const msgUuid = (streamMsg as any).uuid;
// When message type changes, finalize the current message
// This ensures different message types appear as separate bubbles
if (lastMsgType && lastMsgType !== streamMsg.type && response.trim()) {
await finalizeMessage();
}
// Log meaningful events
if (streamMsg.type !== lastMsgType) {
if (streamMsg.type === 'tool_call') {
const toolName = (streamMsg as any).toolName || 'unknown';
console.log(`[Bot] Calling tool: ${toolName}`);
} else if (streamMsg.type === 'tool_result') {
console.log(`[Bot] Tool completed`);
} else if (streamMsg.type === 'assistant' && lastMsgType !== 'assistant') {
console.log(`[Bot] Generating response...`);
}
}
lastMsgType = streamMsg.type;
if (streamMsg.type === 'assistant') {
// Check if this is a new assistant message (different UUID)
if (msgUuid && lastAssistantUuid && msgUuid !== lastAssistantUuid && response.trim()) {
await finalizeMessage();
}
lastAssistantUuid = msgUuid || lastAssistantUuid;
response += streamMsg.content;
// Stream updates only for channels that support editing (Telegram, Slack)
@@ -319,6 +333,8 @@ export class LettaBot {
await adapter.sendMessage({ chatId: msg.chatId, text: response, threadId: msg.threadId });
}
sentAnyMessage = true;
const preview = response.length > 50 ? response.slice(0, 50) + '...' : response;
console.log(`[Bot] Sent: "${preview}"`);
} catch (sendError) {
console.error('[Bot] Error sending response:', sendError);
if (!messageId) {