fix: improve socket error handling
This commit is contained in:
@@ -24,6 +24,7 @@
|
|||||||
- Telegram: stop typing after tool results. Thanks @AbhisekBasu1 for PR #322.
|
- Telegram: stop typing after tool results. Thanks @AbhisekBasu1 for PR #322.
|
||||||
- Messages: stop defaulting ack reactions to 👀 when identity emoji is missing.
|
- Messages: stop defaulting ack reactions to 👀 when identity emoji is missing.
|
||||||
- Auto-reply: require slash for control commands to avoid false triggers in normal text.
|
- Auto-reply: require slash for control commands to avoid false triggers in normal text.
|
||||||
|
- Auto-reply: flag error payloads and improve Bun socket error messaging. Thanks @emanuelst for PR #331.
|
||||||
- Commands: unify native + text chat commands behind `commands.*` config (Discord/Slack/Telegram). Thanks @thewilloftheshadow for PR #275.
|
- Commands: unify native + text chat commands behind `commands.*` config (Discord/Slack/Telegram). Thanks @thewilloftheshadow for PR #275.
|
||||||
- Auto-reply: treat steer during compaction as a follow-up, queued until compaction completes.
|
- Auto-reply: treat steer during compaction as a follow-up, queued until compaction completes.
|
||||||
- Auth: lock auth profile refreshes to avoid multi-instance OAuth logouts; keep credentials on refresh failure.
|
- Auth: lock auth profile refreshes to avoid multi-instance OAuth logouts; keep credentials on refresh failure.
|
||||||
|
|||||||
@@ -209,4 +209,26 @@ describe("runReplyAgent typing (heartbeat)", () => {
|
|||||||
expect(payloads[0]?.text).toContain("count 1");
|
expect(payloads[0]?.text).toContain("count 1");
|
||||||
expect(sessionStore.main.compactionCount).toBe(1);
|
expect(sessionStore.main.compactionCount).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("rewrites Bun socket errors into friendly text", async () => {
|
||||||
|
runEmbeddedPiAgentMock.mockImplementationOnce(async () => ({
|
||||||
|
payloads: [
|
||||||
|
{
|
||||||
|
text: "TypeError: The socket connection was closed unexpectedly. For more information, pass `verbose: true` in the second argument to fetch()",
|
||||||
|
isError: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
meta: {},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const { run } = createMinimalRun();
|
||||||
|
const res = await run();
|
||||||
|
const payloads = Array.isArray(res) ? res : res ? [res] : [];
|
||||||
|
expect(payloads.length).toBe(1);
|
||||||
|
expect(payloads[0]?.text).toContain("LLM connection failed");
|
||||||
|
expect(payloads[0]?.text).toContain(
|
||||||
|
"socket connection was closed unexpectedly",
|
||||||
|
);
|
||||||
|
expect(payloads[0]?.text).toContain("```");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -31,6 +31,21 @@ import { extractReplyToTag } from "./reply-tags.js";
|
|||||||
import { incrementCompactionCount } from "./session-updates.js";
|
import { incrementCompactionCount } from "./session-updates.js";
|
||||||
import type { TypingController } from "./typing.js";
|
import type { TypingController } from "./typing.js";
|
||||||
|
|
||||||
|
const BUN_FETCH_SOCKET_ERROR_RE = /socket connection was closed unexpectedly/i;
|
||||||
|
|
||||||
|
const isBunFetchSocketError = (message?: string) =>
|
||||||
|
Boolean(message && BUN_FETCH_SOCKET_ERROR_RE.test(message));
|
||||||
|
|
||||||
|
const formatBunFetchSocketError = (message: string) => {
|
||||||
|
const trimmed = message.trim();
|
||||||
|
return [
|
||||||
|
"⚠️ LLM connection failed. This could be due to server issues, network problems, or context length exceeded (e.g., with local LLMs like LM Studio). Original error:",
|
||||||
|
"```",
|
||||||
|
trimmed || "Unknown error",
|
||||||
|
"```",
|
||||||
|
].join("\n");
|
||||||
|
};
|
||||||
|
|
||||||
export async function runReplyAgent(params: {
|
export async function runReplyAgent(params: {
|
||||||
commandBody: string;
|
commandBody: string;
|
||||||
followupRun: FollowupRun;
|
followupRun: FollowupRun;
|
||||||
@@ -403,19 +418,8 @@ export async function runReplyAgent(params: {
|
|||||||
: payloadArray.flatMap((payload) => {
|
: payloadArray.flatMap((payload) => {
|
||||||
let text = payload.text;
|
let text = payload.text;
|
||||||
|
|
||||||
if (payload.isError) {
|
if (payload.isError && text && isBunFetchSocketError(text)) {
|
||||||
// Handle Bun fetch socket connection error that may indicate a context length issue
|
text = formatBunFetchSocketError(text);
|
||||||
// Error source: https://github.com/oven-sh/bun/blob/main/src/bun.js/webcore/fetch/FetchTasklet.zig
|
|
||||||
const isBunFetchSocketError =
|
|
||||||
text ===
|
|
||||||
"The socket connection was closed unexpectedly. For more information, pass `verbose: true` in the second argument to fetch()";
|
|
||||||
|
|
||||||
if (isBunFetchSocketError) {
|
|
||||||
text = `⚠️ LLM connection failed. This could be due to server issues, network problems, or context length exceeded (e.g., with local LLMs like LM Studio). Original error:
|
|
||||||
\`\`\`
|
|
||||||
${text || "Unknown error"}
|
|
||||||
\`\`\``;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text || !text.includes("HEARTBEAT_OK"))
|
if (!text || !text.includes("HEARTBEAT_OK"))
|
||||||
|
|||||||
@@ -14,4 +14,5 @@ export type ReplyPayload = {
|
|||||||
mediaUrl?: string;
|
mediaUrl?: string;
|
||||||
mediaUrls?: string[];
|
mediaUrls?: string[];
|
||||||
replyToId?: string;
|
replyToId?: string;
|
||||||
|
isError?: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user