diff --git a/src/agent/check-approval.ts b/src/agent/check-approval.ts index c0cd15c..bb88586 100644 --- a/src/agent/check-approval.ts +++ b/src/agent/check-approval.ts @@ -6,7 +6,7 @@ import { APIError } from "@letta-ai/letta-client/core/error"; import type { AgentState } from "@letta-ai/letta-client/resources/agents/agents"; import type { Message } from "@letta-ai/letta-client/resources/agents/messages"; import type { ApprovalRequest } from "../cli/helpers/stream"; -import { debugWarn } from "../utils/debug"; +import { debugLog, debugWarn } from "../utils/debug"; // Backfill should feel like "the last turn(s)", not "the last N raw messages". // Tool-heavy turns can generate many tool_call/tool_return messages that would @@ -344,16 +344,21 @@ export async function getResumeData( // Use conversations API for explicit conversations, // use agents API for "default" or no conversationId (agent's primary message history) - const useConversationsApi = conversationId && conversationId !== "default"; + const useConversationsApi = + conversationId && + conversationId !== "default" && + !conversationId.startsWith("agent-"); - if (process.env.DEBUG) { - console.log( - `[DEBUG] getResumeData: conversationId=${conversationId}, useConversationsApi=${useConversationsApi}, agentId=${agent.id}`, + if (conversationId?.startsWith("agent-")) { + debugWarn( + "check-approval", + `getResumeData called with agent ID as conversationId: ${conversationId}\n${new Error().stack}`, ); } if (useConversationsApi) { // Get conversation to access in_context_message_ids (source of truth) + debugLog("conversations", `retrieve(${conversationId}) [getResumeData]`); const conversation = await client.conversations.retrieve(conversationId); inContextMessageIds = conversation.in_context_message_ids; diff --git a/src/cli/App.tsx b/src/cli/App.tsx index 9101bff..6afe942 100644 --- a/src/cli/App.tsx +++ b/src/cli/App.tsx @@ -3280,6 +3280,10 @@ export default function App({ try { const client = await getClient(); + debugLog( + "conversations", + `retrieve(${conversationId}) [syncConversationModel]`, + ); const conversation = await client.conversations.retrieve(conversationId); if (cancelled) return; @@ -6154,7 +6158,9 @@ export default function App({ // Build success message const agentLabel = agent.name || targetAgentId; const isSpecificConv = - opts?.conversationId && opts.conversationId !== "default"; + opts?.conversationId && + opts.conversationId !== "default" && + !opts?.conversationId.startsWith("agent-"); const successOutput = isSpecificConv ? [ `Switched to **${agentLabel}**`, @@ -8695,7 +8701,7 @@ export default function App({ // Build export parameters (include conversation_id if in specific conversation) const exportParams: { conversation_id?: string } = {}; - if (conversationId !== "default") { + if (conversationId !== "default" && conversationId !== agentId) { exportParams.conversation_id = conversationId; } @@ -12914,15 +12920,16 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa : `letta --agent ${agentId}`} {/* Only show conversation hint if not on default (default is resumed automatically) */} - {conversationId !== "default" && ( - <> - - Resume this conversation with: - - {`letta --conv ${conversationId}`} - - - )} + {conversationId !== "default" && + conversationId !== agentId && ( + <> + + Resume this conversation with: + + {`letta --conv ${conversationId}`} + + + )} ); })()} diff --git a/src/cli/components/AgentInfoBar.tsx b/src/cli/components/AgentInfoBar.tsx index 7044356..e689949 100644 --- a/src/cli/components/AgentInfoBar.tsx +++ b/src/cli/components/AgentInfoBar.tsx @@ -177,7 +177,9 @@ export const AgentInfoBar = memo(function AgentInfoBar({ {/* Phantom alien row + Conversation ID */} {alienLines[3]} - {conversationId && conversationId !== "default" ? ( + {conversationId && + conversationId !== "default" && + !conversationId.startsWith("agent-") ? ( {truncateText(conversationId, rightWidth)} diff --git a/src/headless.ts b/src/headless.ts index 795b86b..d43158e 100644 --- a/src/headless.ts +++ b/src/headless.ts @@ -114,6 +114,7 @@ import type { StreamEvent, SystemInitMessage, } from "./types/protocol"; +import { debugLog } from "./utils/debug"; import { markMilestone, measureSinceMilestone, @@ -526,7 +527,10 @@ export async function handleHeadlessCommand( // Validate shared mutual-exclusion rules for startup flags. try { validateFlagConflicts({ - guard: specifiedConversationId && specifiedConversationId !== "default", + guard: + specifiedConversationId && + specifiedConversationId !== "default" && + !specifiedConversationId.startsWith("agent-"), checks: [ { when: specifiedAgentId, @@ -730,8 +734,16 @@ export async function handleHeadlessCommand( // Priority 0: --conversation derives agent from conversation ID. // "default" is a virtual agent-scoped conversation (not a retrievable conv-*). // It requires --agent and should not hit conversations.retrieve(). - if (specifiedConversationId && specifiedConversationId !== "default") { + if ( + specifiedConversationId && + specifiedConversationId !== "default" && + !specifiedConversationId.startsWith("agent-") + ) { try { + debugLog( + "conversations", + `retrieve(${specifiedConversationId}) [headless conv→agent lookup]`, + ); const conversation = await client.conversations.retrieve( specifiedConversationId, ); @@ -1007,6 +1019,10 @@ export async function handleHeadlessCommand( } else { // User specified an explicit conversation to resume - validate it exists try { + debugLog( + "conversations", + `retrieve(${specifiedConversationId}) [headless --conv validate]`, + ); await client.conversations.retrieve(specifiedConversationId); conversationId = specifiedConversationId; } catch { @@ -1030,6 +1046,10 @@ export async function handleHeadlessCommand( } else { // Verify the conversation still exists try { + debugLog( + "conversations", + `retrieve(${lastSession.conversationId}) [headless lastSession resume]`, + ); await client.conversations.retrieve(lastSession.conversationId); conversationId = lastSession.conversationId; } catch { diff --git a/src/index.ts b/src/index.ts index 62085e3..17ed4a9 100755 --- a/src/index.ts +++ b/src/index.ts @@ -47,6 +47,7 @@ import { settingsManager } from "./settings-manager"; import { startStartupAutoUpdateCheck } from "./startup-auto-update"; import { telemetry } from "./telemetry"; import { loadTools } from "./tools/manager"; +import { debugLog } from "./utils/debug"; import { markMilestone } from "./utils/timing"; // Stable empty array constants to prevent new references on every render @@ -629,7 +630,10 @@ async function main(): Promise { // Validate shared mutual-exclusion rules for startup flags. try { validateFlagConflicts({ - guard: specifiedConversationId && specifiedConversationId !== "default", + guard: + specifiedConversationId && + specifiedConversationId !== "default" && + !specifiedConversationId.startsWith("agent-"), checks: [ { when: specifiedAgentId, @@ -1193,6 +1197,10 @@ async function main(): Promise { // For explicit conversations, derive agent from conversation try { + debugLog( + "conversations", + `retrieve(${specifiedConversationId}) [TUI conv→agent lookup]`, + ); const conversation = await client.conversations.retrieve( specifiedConversationId, );