From d0f64f1d02a19c20c12414f4e7dbabbb25913800 Mon Sep 17 00:00:00 2001 From: Vincent Grobler Date: Thu, 9 Apr 2026 12:54:52 +0100 Subject: [PATCH] fix(orchestrator): pass output to webhook dispatcher The orchestratorExecutor was dispatching team_run.completed webhooks without the 'output' field, causing all webhook destinations (Trello, Slack, Discord, etc.) to receive result_full: null. - Pass runOutput (already fetched from DB) to dispatchTeamRunWebhooks - Also pass team name and output_route_ids (matching pipeline executor) - Hoist teamData above try block so it's available in catch for errors - Fixes Trello creating a single empty card instead of multi-card output --- task-runner/src/orchestratorExecutor.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/task-runner/src/orchestratorExecutor.ts b/task-runner/src/orchestratorExecutor.ts index 0c5d8cd..e0966d3 100644 --- a/task-runner/src/orchestratorExecutor.ts +++ b/task-runner/src/orchestratorExecutor.ts @@ -137,12 +137,13 @@ export async function processOrchestratorRun(run: TeamRun): Promise { let totalTokens = 0; let totalCost = 0; + let teamData: { name: string; config: OrchestratorConfig; mode: string; output_route_ids: string[] | null } | null = null; try { // 1. Fetch team to get config const teamResponse = await supabase .from('teams') - .select('config, mode') + .select('name, config, mode, output_route_ids') .eq('id', run.team_id) .single(); @@ -150,7 +151,7 @@ export async function processOrchestratorRun(run: TeamRun): Promise { throw new Error(`Failed to load team: ${teamResponse.error?.message ?? 'not found'}`); } - const teamData = teamResponse.data as { config: OrchestratorConfig; mode: string }; + teamData = teamResponse.data as { name: string; config: OrchestratorConfig; mode: string; output_route_ids: string[] | null }; const config = teamData.config; if (!config.brain_agent_id || !config.worker_agent_ids?.length) { @@ -313,9 +314,10 @@ export async function processOrchestratorRun(run: TeamRun): Promise { // Fire team_run.completed webhook (fire-and-forget) void dispatchTeamRunWebhooks( - { id: run.id, team_id: run.team_id, workspace_id: run.workspace_id, status: 'completed', input_task: run.input_task }, - `Orchestrator Team ${run.team_id}`, + { id: run.id, team_id: run.team_id, workspace_id: run.workspace_id, status: 'completed', input_task: run.input_task, output: runOutput ?? undefined }, + teamData.name, 'team_run.completed', + teamData.output_route_ids, ); } catch (error: unknown) { @@ -336,8 +338,9 @@ export async function processOrchestratorRun(run: TeamRun): Promise { // Fire team_run.failed webhook (fire-and-forget) void dispatchTeamRunWebhooks( { id: run.id, team_id: run.team_id, workspace_id: run.workspace_id, status: 'failed', input_task: run.input_task, error_message: errMsg }, - `Orchestrator Team ${run.team_id}`, + teamData?.name ?? `Orchestrator Team ${run.team_id}`, 'team_run.failed', + teamData?.output_route_ids ?? null, ); } }