feat: add LETTA_DEBUG env var for debug logging (#190)
Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
@@ -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(", ")}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
43
src/utils/debug.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user