diff --git a/apps/sim/lib/copilot/application/error.ts b/apps/sim/lib/copilot/application/error.ts index 1626fb942b..4f5c862616 100644 --- a/apps/sim/lib/copilot/application/error.ts +++ b/apps/sim/lib/copilot/application/error.ts @@ -20,6 +20,27 @@ export function messageForCopilotApplicationError( if (classified && classified.code !== 'internal') { return classified.message } - trace.getActiveSpan()?.recordException(toError(error)) + trace.getActiveSpan()?.recordException(flattenErrorChain(error)) return fallback } + +/** + * Wrapper errors (Drizzle's "Failed query: ") bury the actionable cause — + * the Postgres constraint/violation — in `cause`. Join the chain so the span + * exception carries the part an investigator actually needs. + */ +function flattenErrorChain(error: unknown): Error { + const primary = toError(error) + const parts = [primary.message] + let cursor: unknown = primary.cause + let depth = 0 + while (cursor && depth < 4) { + parts.push(toError(cursor).message) + cursor = toError(cursor).cause + depth += 1 + } + if (parts.length === 1) return primary + const flattened = new Error(parts.join(' ← ')) + flattened.stack = primary.stack + return flattened +} diff --git a/apps/sim/lib/copilot/vfs/workspace-vfs.ts b/apps/sim/lib/copilot/vfs/workspace-vfs.ts index 451c535e01..83a425199b 100644 --- a/apps/sim/lib/copilot/vfs/workspace-vfs.ts +++ b/apps/sim/lib/copilot/vfs/workspace-vfs.ts @@ -1806,11 +1806,24 @@ export class WorkspaceVFS { }) } + // deployment.json exists for EVERY workflow: "is it deployed?" is a + // question with an answer either way, and a not-found error here was a + // recurring red herring — agents probing an undeployed workflow read a + // failure instead of the fact. Versions stay gated: they genuinely + // don't exist before the first deploy. + this.registerLazy(`${prefix}deployment.json`, async () => { + if (!versionedWorkflowIds.has(wf.id)) { + return JSON.stringify({ + deployed: false, + note: 'This workflow has never been deployed.', + }) + } + const deploymentData = await this.loadDeployments(wf.id) + return deploymentData + ? serializeDeployments(deploymentData) + : JSON.stringify({ deployed: false, note: 'This workflow has never been deployed.' }) + }) if (versionedWorkflowIds.has(wf.id)) { - this.registerLazy(`${prefix}deployment.json`, async () => { - const deploymentData = await this.loadDeployments(wf.id) - return deploymentData ? serializeDeployments(deploymentData) : null - }) this.registerLazy(`${prefix}versions.json`, async () => { const deploymentData = await this.loadDeployments(wf.id) return deploymentData?.versions && deploymentData.versions.length > 0