fix: properly serialize error objects in transcript logging (#427)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Charles Packer
2025-12-30 14:14:04 -08:00
committed by GitHub
parent 397eb5e390
commit 096b6aec4d
3 changed files with 43 additions and 6 deletions

View File

@@ -945,18 +945,26 @@ export default function App({
// Also tracks the error in telemetry so we know an error was shown
const appendError = useCallback(
(message: string, skipTelemetry = false) => {
// Defensive: ensure message is always a string (guards against [object Object])
const text =
typeof message === "string"
? message
: message != null
? JSON.stringify(message)
: "[Unknown error]";
const id = uid("err");
buffersRef.current.byId.set(id, {
kind: "error",
id,
text: message,
text,
});
buffersRef.current.order.push(id);
refreshDerived();
// Track error in telemetry (unless explicitly skipped for user-initiated actions)
if (!skipTelemetry) {
telemetry.trackError("ui_error", message, "error_display", {
telemetry.trackError("ui_error", text, "error_display", {
modelId: currentModelId || undefined,
});
}

View File

@@ -420,12 +420,19 @@ export function onChunk(b: Buffers, chunk: LettaStreamingResponse) {
for (const toolReturn of toolReturns) {
const toolCallId = toolReturn.tool_call_id;
// Handle both func_response (streaming) and tool_return (SDK) properties
const resultText =
const rawResult =
("func_response" in toolReturn
? toolReturn.func_response
: undefined) ||
("tool_return" in toolReturn ? toolReturn.tool_return : undefined) ||
"";
("tool_return" in toolReturn ? toolReturn.tool_return : undefined);
// Ensure resultText is always a string (guard against SDK returning objects)
const resultText =
typeof rawResult === "string"
? rawResult
: rawResult != null
? JSON.stringify(rawResult)
: "";
const status = toolReturn.status;
// Look up the line by toolCallId

View File

@@ -98,7 +98,29 @@ export function formatErrorDetails(e: unknown, agentId?: string): string {
return e.message;
}
// Fallback for any other type
// Fallback for any other type (e.g., plain objects thrown by SDK or other code)
if (typeof e === "object" && e !== null) {
const obj = e as Record<string, unknown>;
// Check common error-like properties
if (typeof obj.message === "string") {
return obj.message;
}
if (typeof obj.error === "string") {
return obj.error;
}
if (typeof obj.detail === "string") {
return obj.detail;
}
// Last resort: JSON stringify
try {
return JSON.stringify(e, null, 2);
} catch {
return "[Error: Unable to serialize error object]";
}
}
return String(e);
}