diff --git a/.lane/memory/apps/host/src/worker.ts/01M4YQXGS3RQSHX8N6GH99R7D4-the-directory-s-self-name-st.md b/.lane/memory/apps/host/src/worker.ts/01M4YQXGS3RQSHX8N6GH99R7D4-the-directory-s-self-name-st.md index eb3ac832..9d6271a0 100644 --- a/.lane/memory/apps/host/src/worker.ts/01M4YQXGS3RQSHX8N6GH99R7D4-the-directory-s-self-name-st.md +++ b/.lane/memory/apps/host/src/worker.ts/01M4YQXGS3RQSHX8N6GH99R7D4-the-directory-s-self-name-st.md @@ -4,9 +4,9 @@ anchor: '@file' created: 2026-10-15T02:58:00Z norm: '1' sig: 1a43097a4e1ad24c -body_hash: 5e79b1f5e63ad3c5 -raw_hash: 1f3f06a6f1a6594b -vouched: 2026-10-22T20:30:45Z +body_hash: b51789a971b9b372 +raw_hash: 34f5d37f971c48ee +vouched: 2026-10-27T18:45:09Z lines: 1-194 --- diff --git a/.lane/memory/apps/host/src/worker.ts/01M5ZAW8YH3P3CH606HT4P0H3P-the-model-sdks-and-pi-ai-kee.md b/.lane/memory/apps/host/src/worker.ts/01M5ZAW8YH3P3CH606HT4P0H3P-the-model-sdks-and-pi-ai-kee.md new file mode 100644 index 00000000..846a8910 --- /dev/null +++ b/.lane/memory/apps/host/src/worker.ts/01M5ZAW8YH3P3CH606HT4P0H3P-the-model-sdks-and-pi-ai-kee.md @@ -0,0 +1,12 @@ +--- +id: 01M5ZAW8YH3P3CH606HT4P0H3P +anchor: '@file' +created: 2026-10-27T18:45:04Z +norm: '1' +sig: 1a43097a4e1ad24c +body_hash: b51789a971b9b372 +raw_hash: 34f5d37f971c48ee +lines: 1-215 +--- + +the model SDKs and pi-ai keep only "Connection error.", so the worker's fetch must log the real error before it is wrapped diff --git a/.lane/memory/packages/channel/src/log.ts/01M5FHS8DZHENAVBR7RPWT8Q1A-the-poisoned-session-error-h.md b/.lane/memory/packages/channel/src/log.ts/01M5FHS8DZHENAVBR7RPWT8Q1A-the-poisoned-session-error-h.md index 75b85a68..e74c3518 100644 --- a/.lane/memory/packages/channel/src/log.ts/01M5FHS8DZHENAVBR7RPWT8Q1A-the-poisoned-session-error-h.md +++ b/.lane/memory/packages/channel/src/log.ts/01M5FHS8DZHENAVBR7RPWT8Q1A-the-poisoned-session-error-h.md @@ -4,8 +4,9 @@ anchor: function failure created: 2026-10-21T15:37:54Z norm: '1' sig: f1231fd34544d478 -body_hash: f0ddb33d9820c29c -raw_hash: 691df1159bc16114 +body_hash: 9c6bfc2d5c2e411f +raw_hash: 407e5184a4d911dc +vouched: 2026-10-27T18:45:09Z lines: 15-20 --- diff --git a/apps/host/src/worker.ts b/apps/host/src/worker.ts index ffb7fee3..8d822ae0 100644 --- a/apps/host/src/worker.ts +++ b/apps/host/src/worker.ts @@ -15,7 +15,7 @@ import { images } from "./images"; import { models, seal } from "./keys"; import { defaultModel } from "./manage"; import { lines } from "./lines"; -import { log, open } from "./log"; +import { failure, log, open } from "./log"; import type { WorkerInfo, WorkerRequest } from "./protocol"; import { tabs } from "./tabs"; @@ -47,6 +47,19 @@ if (record.hosted || record.moving) { process.exit(0); } log("info", "worker.start", { bun: Bun.version }); + +// Model SDKs turn a failed request into "Connection error." and pi-ai keeps only that message, so +// the network error that explains it is logged here before it is wrapped. +const send = globalThis.fetch; +globalThis.fetch = Object.assign(async (input: string | URL | Request, init?: RequestInit) => { + try { + return await send(input, init); + } catch (error) { + const url = new URL(input instanceof Request ? input.url : input); + log("warn", "fetch.failed", { url: url.origin + url.pathname, ...failure(error) }); + throw error; + } +}, send); rmSync(paths.socket, { force: true }); catalog.busy(id, false); diff --git a/packages/channel/src/log.ts b/packages/channel/src/log.ts index 7a8ff540..f5d98acf 100644 --- a/packages/channel/src/log.ts +++ b/packages/channel/src/log.ts @@ -11,10 +11,11 @@ export function scoped(log: Log, base: Fields): Log { return (level, event, fields) => log(level, event, { ...base, ...fields }); } -/** An error's message, stack, and cause, which JSON drops. */ +/** An error's message, code, stack, and cause, which JSON drops. */ export function failure(error: unknown): Fields { if (!(error instanceof Error)) return { error: String(error) }; const fields: Fields = { error: error.message, stack: error.stack }; + if ("code" in error) fields.code = error.code; if (error.cause !== undefined) fields.cause = failure(error.cause); return fields; }