fix(debug): unify LETTA_DEBUG and DEBUG gating (#1408)
Co-authored-by: Letta Code <noreply@letta.com>
This commit is contained in:
@@ -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 { debugWarn, isDebugEnabled } 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
|
||||
@@ -484,7 +484,7 @@ export async function getResumeData(
|
||||
});
|
||||
messages = sortChronological(messagesPage.getPaginatedItems());
|
||||
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.log(
|
||||
`[DEBUG] conversations.messages.list(default, agent_id=${agent.id}) returned ${messages.length} messages`,
|
||||
);
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
captureToolExecutionContext,
|
||||
waitForToolsetReady,
|
||||
} from "../tools/manager";
|
||||
import { debugLog, debugWarn } from "../utils/debug";
|
||||
import { debugLog, debugWarn, isDebugEnabled } from "../utils/debug";
|
||||
import { isTimingsEnabled } from "../utils/timing";
|
||||
import {
|
||||
type ApprovalNormalizationOptions,
|
||||
@@ -138,7 +138,7 @@ export async function sendMessageStream(
|
||||
clientSkills,
|
||||
);
|
||||
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.log(
|
||||
`[DEBUG] sendMessageStream: conversationId=${conversationId}, agentId=${opts.agentId ?? "(none)"}`,
|
||||
);
|
||||
|
||||
@@ -121,7 +121,12 @@ import {
|
||||
} from "../tools/manager";
|
||||
import type { ToolsetName, ToolsetPreference } from "../tools/toolset";
|
||||
import { formatToolsetName } from "../tools/toolset-labels";
|
||||
import { debugLog, debugLogFile, debugWarn } from "../utils/debug";
|
||||
import {
|
||||
debugLog,
|
||||
debugLogFile,
|
||||
debugWarn,
|
||||
isDebugEnabled,
|
||||
} from "../utils/debug";
|
||||
import { getVersion } from "../version";
|
||||
import {
|
||||
handleMcpAdd,
|
||||
@@ -3050,7 +3055,7 @@ export default function App({
|
||||
const agentName = agentState?.name || "Unnamed Agent";
|
||||
const isResumingConversation =
|
||||
resumedExistingConversation || messageHistory.length > 0;
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.log(
|
||||
`[DEBUG] Header: resumedExistingConversation=${resumedExistingConversation}, messageHistory.length=${messageHistory.length}`,
|
||||
);
|
||||
@@ -4721,7 +4726,7 @@ export default function App({
|
||||
})
|
||||
.catch((err) => {
|
||||
// Silently ignore - not critical
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.error(
|
||||
"[DEBUG] Failed to set conversation summary:",
|
||||
err,
|
||||
|
||||
@@ -120,7 +120,7 @@ import type {
|
||||
StreamEvent,
|
||||
SystemInitMessage,
|
||||
} from "./types/protocol";
|
||||
import { debugLog, debugWarn } from "./utils/debug";
|
||||
import { debugLog, debugWarn, isDebugEnabled } from "./utils/debug";
|
||||
import {
|
||||
markMilestone,
|
||||
measureSinceMilestone,
|
||||
@@ -1493,7 +1493,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
||||
agentId: agent.id,
|
||||
skillSources: resolvedSkillSources,
|
||||
logger: (message) => {
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.warn(`[DEBUG] ${message}`);
|
||||
}
|
||||
},
|
||||
|
||||
10
src/index.ts
10
src/index.ts
@@ -49,7 +49,7 @@ import { startStartupAutoUpdateCheck } from "./startup-auto-update";
|
||||
import { telemetry } from "./telemetry";
|
||||
import { loadTools } from "./tools/manager";
|
||||
import { clearPersistedClientToolRules } from "./tools/toolset";
|
||||
import { debugLog, debugWarn } from "./utils/debug";
|
||||
import { debugLog, debugWarn, isDebugEnabled } from "./utils/debug";
|
||||
import { markMilestone } from "./utils/timing";
|
||||
|
||||
// Stable empty array constants to prevent new references on every render
|
||||
@@ -777,7 +777,7 @@ async function main(): Promise<void> {
|
||||
const message =
|
||||
err instanceof Error ? err.message : "An unexpected error occurred";
|
||||
console.error(`\nError: ${message}`);
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.error(err);
|
||||
}
|
||||
process.exit(1);
|
||||
@@ -1824,7 +1824,7 @@ async function main(): Promise<void> {
|
||||
let conversationIdToUse!: string;
|
||||
|
||||
// Debug: log resume flag status
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.log(`[DEBUG] shouldContinue=${shouldContinue}`);
|
||||
console.log(`[DEBUG] shouldResume=${shouldResume}`);
|
||||
console.log(
|
||||
@@ -1865,7 +1865,7 @@ async function main(): Promise<void> {
|
||||
settingsManager.getLocalLastSession(process.cwd()) ??
|
||||
settingsManager.getGlobalLastSession();
|
||||
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.log(`[DEBUG] lastSession=${JSON.stringify(lastSession)}`);
|
||||
console.log(`[DEBUG] agent.id=${agent.id}`);
|
||||
}
|
||||
@@ -2029,7 +2029,7 @@ async function main(): Promise<void> {
|
||||
// Handle errors gracefully without showing raw stack traces
|
||||
const message = formatErrorDetails(err);
|
||||
console.error(`\nError during initialization: ${message}`);
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.error(err);
|
||||
}
|
||||
process.exit(1);
|
||||
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
QueueItemKind,
|
||||
QueueItemSource,
|
||||
} from "../types/protocol";
|
||||
import { isDebugEnabled } from "../utils/debug";
|
||||
|
||||
export type { QueueBlockedReason, QueueClearedReason, QueueItemKind };
|
||||
|
||||
@@ -362,7 +363,7 @@ export class QueueRuntime {
|
||||
...args,
|
||||
);
|
||||
} catch (err) {
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.error(`[QueueRuntime] callback "${name}" threw:`, err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// src/utils/debug.ts
|
||||
// Debug logging utility.
|
||||
//
|
||||
// Screen output: controlled by LETTA_DEBUG=1 (or LETTA_DEBUG_FILE for a custom path).
|
||||
// Screen output: controlled by LETTA_DEBUG=1 (or DEBUG=1 for legacy compatibility),
|
||||
// or LETTA_DEBUG_FILE for a custom path.
|
||||
// File output: always written to ~/.letta/logs/debug/{agent-id}/{session-id}.log
|
||||
// once debugLogFile.init() has been called. Before init, lines are
|
||||
// silently dropped (no file path yet).
|
||||
@@ -23,12 +24,18 @@ import { format } from "node:util";
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Check if debug mode is enabled via LETTA_DEBUG env var
|
||||
* Set LETTA_DEBUG=1 or LETTA_DEBUG=true to enable debug logging
|
||||
* Check if debug mode is enabled via LETTA_DEBUG env var.
|
||||
* Also accepts DEBUG=1|true for legacy compatibility.
|
||||
*/
|
||||
export function isDebugEnabled(): boolean {
|
||||
const debug = process.env.LETTA_DEBUG;
|
||||
return debug === "1" || debug === "true";
|
||||
const lettaDebug = process.env.LETTA_DEBUG;
|
||||
const legacyDebug = process.env.DEBUG;
|
||||
return (
|
||||
lettaDebug === "1" ||
|
||||
lettaDebug === "true" ||
|
||||
legacyDebug === "1" ||
|
||||
legacyDebug === "true"
|
||||
);
|
||||
}
|
||||
|
||||
function getDebugFile(): string | null {
|
||||
|
||||
@@ -84,6 +84,7 @@ import type {
|
||||
TranscriptBackfillMessage,
|
||||
TranscriptSupplementMessage,
|
||||
} from "../types/protocol";
|
||||
import { isDebugEnabled } from "../utils/debug";
|
||||
import { getListenerBlockedReason } from "./helpers/listenerQueueAdapter";
|
||||
import {
|
||||
handleTerminalInput,
|
||||
@@ -458,7 +459,7 @@ function handleModeChange(msg: ModeChangeMessage, socket: WebSocket): void {
|
||||
success: true,
|
||||
});
|
||||
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.log(`[Listen] Mode changed to: ${msg.mode}`);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -470,7 +471,7 @@ function handleModeChange(msg: ModeChangeMessage, socket: WebSocket): void {
|
||||
error: error instanceof Error ? error.message : "Mode change failed",
|
||||
});
|
||||
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.error("[Listen] Mode change failed:", error);
|
||||
}
|
||||
}
|
||||
@@ -1325,7 +1326,7 @@ function scheduleQueuePump(
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
runtime.queuePumpScheduled = false;
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.error("[Listen] Error in queue pump:", error);
|
||||
}
|
||||
opts.onStatusChange?.("idle", opts.connectionId);
|
||||
@@ -2115,7 +2116,7 @@ function populateInterruptQueue(
|
||||
return true;
|
||||
}
|
||||
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.warn(
|
||||
"[Listen] Cancel during approval loop but no tool_call_ids available " +
|
||||
"for interrupted queue — next turn may hit pre-stream conflict. " +
|
||||
@@ -2849,7 +2850,7 @@ async function connectWithRetry(
|
||||
raw,
|
||||
});
|
||||
}
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.log(
|
||||
`[Listen] Received message: ${JSON.stringify(parsed, null, 2)}`,
|
||||
);
|
||||
@@ -3075,7 +3076,7 @@ async function connectWithRetry(
|
||||
);
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.error("[Listen] Error handling queued get_state:", error);
|
||||
}
|
||||
});
|
||||
@@ -3114,7 +3115,7 @@ async function connectWithRetry(
|
||||
}
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.error(
|
||||
"[Listen] Error handling queued pending approval recovery:",
|
||||
error,
|
||||
@@ -3187,7 +3188,7 @@ async function connectWithRetry(
|
||||
scheduleQueuePump(runtime, socket, opts);
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.error("[Listen] Error handling queued message:", error);
|
||||
}
|
||||
opts.onStatusChange?.("idle", opts.connectionId);
|
||||
@@ -3212,7 +3213,7 @@ async function connectWithRetry(
|
||||
runtime.queuedMessagesByItemId.clear();
|
||||
runtime.queueRuntime.clear("shutdown");
|
||||
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.log(
|
||||
`[Listen] WebSocket disconnected (code: ${code}, reason: ${reason.toString()})`,
|
||||
);
|
||||
@@ -3230,7 +3231,7 @@ async function connectWithRetry(
|
||||
|
||||
// 1008: Environment not found - need to re-register
|
||||
if (code === 1008) {
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.log("[Listen] Environment not found, re-registering...");
|
||||
}
|
||||
// Stop retry loop and signal that we need to re-register
|
||||
@@ -3261,7 +3262,7 @@ async function connectWithRetry(
|
||||
type: "_ws_error",
|
||||
message: error.message,
|
||||
});
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.error("[Listen] WebSocket error:", error);
|
||||
}
|
||||
// Error triggers close(), which handles retry logic.
|
||||
@@ -3320,7 +3321,7 @@ async function handleIncomingMessage(
|
||||
return;
|
||||
}
|
||||
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.log(
|
||||
`[Listen] Handling message: agentId=${agentId}, requestedConversationId=${requestedConversationId}, conversationId=${conversationId}`,
|
||||
);
|
||||
@@ -4048,7 +4049,7 @@ async function handleIncomingMessage(
|
||||
stopReason: "error",
|
||||
});
|
||||
|
||||
if (process.env.DEBUG) {
|
||||
if (isDebugEnabled()) {
|
||||
console.error("[Listen] Error handling message:", error);
|
||||
}
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user