feat: add LETTA_DEBUG env var for debug logging (#190)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Charles Packer
2025-12-11 22:59:34 -08:00
committed by GitHub
parent c39bda9a01
commit 97e6b7e2a7
3 changed files with 65 additions and 16 deletions

View File

@@ -5,6 +5,7 @@ import type Letta from "@letta-ai/letta-client";
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";
// Number of recent messages to backfill when resuming a session
const MESSAGE_HISTORY_LIMIT = 15;
@@ -62,8 +63,9 @@ export async function getResumeData(
inContextLastMessageId &&
cursorLastMessage.id !== inContextLastMessageId
) {
console.warn(
`[check-approval] Desync detected:\n` +
debugWarn(
"check-approval",
`Desync detected:\n` +
` cursor last: ${cursorLastMessage.id} (type: ${cursorLastMessage.message_type})\n` +
` in-context last: ${inContextLastMessageId} (type: unknown until found)`,
);
@@ -84,8 +86,9 @@ export async function getResumeData(
const inContextMessage = approvalMessage ?? lastMessage;
if (inContextMessage) {
console.warn(
`[check-approval] Found in-context message (type: ${inContextMessage.message_type})` +
debugWarn(
"check-approval",
`Found in-context message (type: ${inContextMessage.message_type})` +
(matchingMessages.length > 1
? ` - had ${matchingMessages.length} duplicates`
: ""),
@@ -93,8 +96,9 @@ export async function getResumeData(
messageToCheck = inContextMessage;
}
} else {
console.warn(
`[check-approval] In-context message ${inContextLastMessageId} not found in cursor fetch.\n` +
debugWarn(
"check-approval",
`In-context message ${inContextLastMessageId} not found in cursor fetch.\n` +
` This likely means the in-context message is older than the cursor window.\n` +
` Falling back to cursor message - approval state may be incorrect.`,
);
@@ -110,11 +114,10 @@ export async function getResumeData(
const lastStopReason = (agent as { last_stop_reason?: string })
.last_stop_reason;
if (lastStopReason === "requires_approval") {
console.warn(
`[check-approval] Agent last_stop_reason: ${lastStopReason}`,
);
console.warn(
`[check-approval] Message to check: ${messageToCheck.id} (type: ${messageToCheck.message_type})`,
debugWarn("check-approval", `Agent last_stop_reason: ${lastStopReason}`);
debugWarn(
"check-approval",
`Message to check: ${messageToCheck.id} (type: ${messageToCheck.message_type})`,
);
}
@@ -162,8 +165,9 @@ export async function getResumeData(
// Set legacy singular field for backward compatibility (first approval only)
if (pendingApprovals.length > 0) {
pendingApproval = pendingApprovals[0] || null;
console.warn(
`[check-approval] Found ${pendingApprovals.length} pending approval(s): ${pendingApprovals.map((a) => a.toolName).join(", ")}`,
debugWarn(
"check-approval",
`Found ${pendingApprovals.length} pending approval(s): ${pendingApprovals.map((a) => a.toolName).join(", ")}`,
);
}
}

View File

@@ -2,6 +2,7 @@ import type { Stream } from "@letta-ai/letta-client/core/streaming";
import type { LettaStreamingResponse } from "@letta-ai/letta-client/resources/agents/messages";
import type { StopReasonType } from "@letta-ai/letta-client/resources/runs/runs";
import { getClient } from "../../agent/client";
import { debugWarn } from "../../utils/debug";
import {
type createBuffers,
@@ -179,10 +180,11 @@ export async function drainStream(
}));
if (approvals.length === 0) {
console.error(
"[drainStream] No approvals collected despite requires_approval stop reason",
debugWarn(
"drainStream",
"No approvals collected despite requires_approval stop reason",
);
console.error("[drainStream] Pending approvals map:", allPending);
debugWarn("drainStream", "Pending approvals map:", allPending);
} else {
// Set legacy singular field for backward compatibility
approval = approvals[0] || null;

43
src/utils/debug.ts Normal file
View File

@@ -0,0 +1,43 @@
// src/utils/debug.ts
// Simple debug logging utility - only logs when LETTA_DEBUG env var is set
/**
* Check if debug mode is enabled via LETTA_DEBUG env var
* Set LETTA_DEBUG=1 or LETTA_DEBUG=true to enable debug logging
*/
export function isDebugEnabled(): boolean {
const debug = process.env.LETTA_DEBUG;
return debug === "1" || debug === "true";
}
/**
* Log a debug message (only if LETTA_DEBUG is enabled)
* @param prefix - A prefix/tag for the log message (e.g., "check-approval")
* @param message - The message to log
* @param args - Additional arguments to log
*/
export function debugLog(
prefix: string,
message: string,
...args: unknown[]
): void {
if (isDebugEnabled()) {
console.log(`[${prefix}] ${message}`, ...args);
}
}
/**
* Log a debug warning (only if LETTA_DEBUG is enabled)
* @param prefix - A prefix/tag for the log message
* @param message - The message to log
* @param args - Additional arguments to log
*/
export function debugWarn(
prefix: string,
message: string,
...args: unknown[]
): void {
if (isDebugEnabled()) {
console.warn(`[${prefix}] ${message}`, ...args);
}
}