From 13eeb07f5f4b582e2ff824db382ff8917489c5c6 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Tue, 10 Mar 2026 10:38:11 -0700 Subject: [PATCH] prevent squashing some know errors --- .../Layers/OrchestrationEngine.ts | 9 +------ .../Layers/ProviderCommandReactor.ts | 27 +++++-------------- .../src/provider/Layers/CodexAdapter.ts | 16 +++++++---- apps/server/src/wsServer.ts | 13 +++------ 4 files changed, 22 insertions(+), 43 deletions(-) diff --git a/apps/server/src/orchestration/Layers/OrchestrationEngine.ts b/apps/server/src/orchestration/Layers/OrchestrationEngine.ts index 0895cd99c9dd528a1180e27a9e3b3815509cff84..33b49f233f097d4a3da4b2aa0d182f2e7d87c6d4 100644 --- a/apps/server/src/orchestration/Layers/OrchestrationEngine.ts +++ b/apps/server/src/orchestration/Layers/OrchestrationEngine.ts @@ -49,13 +49,6 @@ function commandToAggregateRef(command: OrchestrationCommand): { } } -function formatDispatchError(error: OrchestrationDispatchError): string { - if (error instanceof Error && error.message.length > 0) { - return error.message; - } - return String(error); -} - const makeOrchestrationEngine = Effect.gen(function* () { const sql = yield* SqlClient.SqlClient; const eventStore = yield* OrchestrationEventStore; @@ -191,7 +184,7 @@ const makeOrchestrationEngine = Effect.gen(function* () { acceptedAt: new Date().toISOString(), resultSequence: readModel.snapshotSequence, status: "rejected", - error: formatDispatchError(error), + error: error.message, }) .pipe(Effect.catch(() => Effect.void)); } diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts index bd1c53b7700f81ae9f5e623f9ac160cc91d8602e..e63fda1e1cbd4e6abbf072d5ff56932df26c9f7f 100644 --- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts +++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts @@ -16,7 +16,7 @@ import { Cache, Cause, Duration, Effect, Layer, Option, Queue, Schema, Stream } import { resolveThreadWorkspaceCwd } from "../../checkpointing/Utils.ts"; import { GitCore } from "../../git/Services/GitCore.ts"; -import { ProviderAdapterRequestError } from "../../provider/Errors.ts"; +import { ProviderAdapterRequestError, ProviderServiceError } from "../../provider/Errors.ts"; import { TextGeneration } from "../../git/Services/TextGeneration.ts"; import { ProviderService } from "../../provider/Services/ProviderService.ts"; import { OrchestrationEngineService } from "../Services/OrchestrationEngine.ts"; @@ -73,18 +73,8 @@ const DEFAULT_RUNTIME_MODE: RuntimeMode = "full-access"; const WORKTREE_BRANCH_PREFIX = "t3code"; const TEMP_WORKTREE_BRANCH_PATTERN = new RegExp(`^${WORKTREE_BRANCH_PREFIX}\\/[0-9a-f]{8}$`); -function toErrorMessage(error: unknown): string { - if (error instanceof Error && error.message.trim().length > 0) { - return error.message; - } - try { - return JSON.stringify(error); - } catch { - return String(error); - } -} - -function isUnknownPendingApprovalRequestError(error: unknown): boolean { +function isUnknownPendingApprovalRequestError(cause: Cause.Cause): boolean { + const error = Cause.squash(cause); if (Schema.is(ProviderAdapterRequestError)(error)) { const detail = error.detail.toLowerCase(); return ( @@ -92,7 +82,7 @@ function isUnknownPendingApprovalRequestError(error: unknown): boolean { detail.includes("unknown pending permission request") ); } - const message = toErrorMessage(error).toLowerCase(); + const message = Cause.pretty(cause); return ( message.includes("unknown pending approval request") || message.includes("unknown pending permission request") @@ -539,19 +529,17 @@ const make = Effect.gen(function* () { .pipe( Effect.catchCause((cause) => Effect.gen(function* () { - const error = Cause.squash(cause); - const detail = toErrorMessage(error); yield* appendProviderFailureActivity({ threadId: event.payload.threadId, kind: "provider.approval.respond.failed", summary: "Provider approval response failed", - detail, + detail: Cause.pretty(cause), turnId: null, createdAt: event.payload.createdAt, requestId: event.payload.requestId, }); - if (!isUnknownPendingApprovalRequestError(error)) return; + if (!isUnknownPendingApprovalRequestError(cause)) return; }), ), ); @@ -586,12 +574,11 @@ const make = Effect.gen(function* () { .pipe( Effect.catchCause((cause) => Effect.gen(function* () { - const error = Cause.squash(cause); yield* appendProviderFailureActivity({ threadId: event.payload.threadId, kind: "provider.user-input.respond.failed", summary: "Provider user input response failed", - detail: toErrorMessage(error), + detail: Cause.pretty(cause), turnId: null, createdAt: event.payload.createdAt, requestId: event.payload.requestId, diff --git a/apps/server/src/provider/Layers/CodexAdapter.ts b/apps/server/src/provider/Layers/CodexAdapter.ts index 2381cec32bbf61327445a6148e86d45fe80af076..59eabbc6280c1acf1735f3a994f84bc2b8e2f175 100644 --- a/apps/server/src/provider/Layers/CodexAdapter.ts +++ b/apps/server/src/provider/Layers/CodexAdapter.ts @@ -1338,11 +1338,17 @@ const makeCodexAdapter = (options?: CodexAdapterLiveOptions) => new Error(`Invalid attachment id '${attachment.id}'.`), ); } - const bytes = yield* fileSystem - .readFile(attachmentPath) - .pipe( - Effect.mapError((cause) => toRequestError(input.threadId, "turn/start", cause)), - ); + const bytes = yield* fileSystem.readFile(attachmentPath).pipe( + Effect.mapError( + (cause) => + new ProviderAdapterRequestError({ + provider: PROVIDER, + method: "turn/start", + detail: toMessage(cause, "Failed to read attachment file."), + cause, + }), + ), + ); return { type: "image" as const, url: `data:${attachment.mimeType};base64,${Buffer.from(bytes).toString("base64")}`, diff --git a/apps/server/src/wsServer.ts b/apps/server/src/wsServer.ts index 1bd1c02c4faf567947e999245774c43d857efd12..2c10b7cabecc5a7bfa0dee58a5d4f80275113a92 100644 --- a/apps/server/src/wsServer.ts +++ b/apps/server/src/wsServer.ts @@ -99,8 +99,7 @@ export interface ServerShape { */ export class Server extends ServiceMap.Service()("t3/wsServer/Server") {} -const isServerNotRunningError = (error: unknown): boolean => { - if (!(error instanceof Error)) return false; +const isServerNotRunningError = (error: Error): boolean => { const maybeCode = (error as NodeJS.ErrnoException).code; return ( maybeCode === "ERR_SERVER_NOT_RUNNING" || error.message.toLowerCase().includes("not running") @@ -196,12 +195,6 @@ function stripRequestTag(body: T) { return Struct.omit(body, ["_tag"]); } -function messageFromCause(cause: Cause.Cause): string { - const squashed = Cause.squash(cause); - const message = squashed instanceof Error ? squashed.message.trim() : String(squashed).trim(); - return message.length > 0 ? message : Cause.pretty(cause); -} - export type ServerCoreRuntimeServices = | OrchestrationEngineService | ProjectionSnapshotQuery @@ -943,7 +936,7 @@ export const createServer = Effect.fn(function* (): Effect.fn.Return< if (request._tag === "Failure") { const errorResponse = yield* encodeResponse({ id: "unknown", - error: { message: `Invalid request format: ${messageFromCause(request.cause)}` }, + error: { message: `Invalid request format: ${Cause.pretty(request.cause)}` }, }); ws.send(errorResponse); return; @@ -953,7 +946,7 @@ export const createServer = Effect.fn(function* (): Effect.fn.Return< if (result._tag === "Failure") { const errorResponse = yield* encodeResponse({ id: request.value.id, - error: { message: messageFromCause(result.cause) }, + error: { message: Cause.pretty(result.cause) }, }); ws.send(errorResponse); return; -- 2.54.0