Skip to main content
Glama

relay_workflow_run

Execute multi-step AI workflows with reduced context usage by keeping intermediate results in the workflow engine, supporting multiple model calls and tool integrations.

Instructions

Execute a multi-step AI workflow. Intermediate results stay in the workflow engine (not your context), providing 90%+ context reduction on complex pipelines. Use for any task requiring multiple model calls or tool integrations. Cost tracks your provider bills, not RelayPlane fees - we're BYOK.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameYesWorkflow name for tracing
stepsYesWorkflow steps
inputYesInput data (accessible via {{input.field}})

Implementation Reference

  • Core handler function that executes the relay_workflow_run tool: performs topological sort on steps, interpolates prompts, executes AI steps via relayRun or MCP, handles budget/costs, stores run results, computes context reduction percentage.
    export async function relayWorkflowRun(input: RelayWorkflowRunInput): Promise<RelayWorkflowRunResponse> { const startTime = Date.now(); const runId = generateRunId(); const config = getConfig(); const stepResults: Record<string, WorkflowStepResult> = {}; let totalTokens = 0; let totalCost = 0; try { // Validate and sort steps const sortedSteps = topologicalSort(input.steps); // Estimate cost for AI steps and check budget const aiSteps = sortedSteps.filter(s => s.model && s.prompt); const estimatedCost = estimateWorkflowCost(aiSteps); const budgetCheck = checkBudget(estimatedCost); if (!budgetCheck.allowed) { throw new Error(budgetCheck.error); } // Check all providers are configured for (const step of aiSteps) { const provider = step.model!.split(':')[0]; if (!isProviderConfigured(provider)) { throw new Error( `Provider "${provider}" (step "${step.name}") is not configured. Set ${provider.toUpperCase()}_API_KEY environment variable.` ); } } // Execute steps in order const context = { input: input.input, steps: {} as Record<string, any> }; for (const step of sortedSteps) { const stepStart = Date.now(); try { if (step.model && step.prompt) { // AI step - use relay_run const interpolatedPrompt = interpolate(step.prompt, context); const interpolatedSystemPrompt = step.systemPrompt ? interpolate(step.systemPrompt, context) : undefined; const result = await relayRun({ model: step.model, prompt: interpolatedPrompt, systemPrompt: interpolatedSystemPrompt, schema: step.schema, }); if (!result.success) { throw new Error(result.error?.message || 'Step execution failed'); } context.steps[step.name] = { output: result.output }; stepResults[step.name] = { success: true, output: result.output, durationMs: result.durationMs, usage: { promptTokens: result.usage.promptTokens, completionTokens: result.usage.completionTokens, estimatedProviderCostUsd: result.usage.estimatedProviderCostUsd, }, }; totalTokens += result.usage.totalTokens; totalCost += result.usage.estimatedProviderCostUsd; } else if (step.mcp) { // MCP step - placeholder for now // In a full implementation, this would call the MCP tool const stepDuration = Date.now() - stepStart; context.steps[step.name] = { output: { message: 'MCP step executed (placeholder)' } }; stepResults[step.name] = { success: true, output: { message: 'MCP step executed (placeholder)' }, durationMs: stepDuration, }; } else { // Transform step or other type const stepDuration = Date.now() - stepStart; context.steps[step.name] = { output: null }; stepResults[step.name] = { success: true, output: null, durationMs: stepDuration, }; } } catch (error) { const stepDuration = Date.now() - stepStart; const errorMessage = error instanceof Error ? error.message : String(error); stepResults[step.name] = { success: false, output: null, durationMs: stepDuration, error: { code: 'STEP_EXECUTION_ERROR', message: errorMessage, }, }; throw new Error(`Step "${step.name}" failed: ${errorMessage}`); } } const totalDurationMs = Date.now() - startTime; const lastStep = sortedSteps[sortedSteps.length - 1]; const finalOutput = stepResults[lastStep?.name]?.output; const response: RelayWorkflowRunResponse = { success: true, steps: stepResults, finalOutput, totalUsage: { totalTokens, estimatedProviderCostUsd: totalCost, }, totalDurationMs, runId, traceUrl: `${config.traceUrlBase}/${runId}`, contextReduction: estimateContextReduction(sortedSteps, stepResults), }; // Store run addRun({ runId, type: 'workflow', workflowName: input.name, success: true, startTime: new Date(startTime), endTime: new Date(), durationMs: totalDurationMs, usage: { promptTokens: 0, // Aggregated in steps completionTokens: 0, totalTokens, estimatedProviderCostUsd: totalCost, }, input: input.input, output: finalOutput, steps: stepResults, contextReduction: response.contextReduction, }); return response; } catch (error) { const totalDurationMs = Date.now() - startTime; const errorMessage = error instanceof Error ? error.message : String(error); const response: RelayWorkflowRunResponse = { success: false, steps: stepResults, finalOutput: null, totalUsage: { totalTokens, estimatedProviderCostUsd: totalCost, }, totalDurationMs, runId, traceUrl: `${config.traceUrlBase}/${runId}`, contextReduction: 'N/A (workflow failed)', error: { code: 'WORKFLOW_ERROR', message: errorMessage, }, }; // Store failed run addRun({ runId, type: 'workflow', workflowName: input.name, success: false, startTime: new Date(startTime), endTime: new Date(), durationMs: totalDurationMs, usage: { promptTokens: 0, completionTokens: 0, totalTokens, estimatedProviderCostUsd: totalCost, }, input: input.input, steps: stepResults, error: errorMessage, }); return response; } }
  • MCP tool definition object with name, description, and detailed inputSchema for validation in MCP protocol.
    export const relayWorkflowRunDefinition = { name: 'relay_workflow_run', description: "Execute a multi-step AI workflow. Intermediate results stay in the workflow engine (not your context), providing 90%+ context reduction on complex pipelines. Use for any task requiring multiple model calls or tool integrations. Cost tracks your provider bills, not RelayPlane fees - we're BYOK.", inputSchema: { type: 'object' as const, properties: { name: { type: 'string', description: 'Workflow name for tracing', }, steps: { type: 'array', description: 'Workflow steps', items: { type: 'object', properties: { name: { type: 'string', description: 'Step name' }, model: { type: 'string', description: 'Model in provider:model format' }, prompt: { type: 'string', description: 'Prompt template (supports {{input.field}} and {{steps.stepName.output}})' }, systemPrompt: { type: 'string', description: 'Optional system prompt' }, depends: { type: 'array', items: { type: 'string' }, description: 'Steps this step depends on' }, mcp: { type: 'string', description: 'MCP tool in server:tool format' }, params: { type: 'object', description: 'MCP tool parameters' }, schema: { type: 'object', description: 'JSON schema for structured output' }, }, required: ['name'], }, }, input: { type: 'object', description: 'Input data (accessible via {{input.field}})', }, }, required: ['name', 'steps', 'input'], }, };
  • Zod schema for input validation of relay_workflow_run parameters.
    export const relayWorkflowRunSchema = z.object({ name: z.string().describe('Workflow name for tracing'), steps: z.array(workflowStepSchema).describe('Workflow steps'), input: z.object({}).passthrough().describe('Input data (accessible via {{input.field}})'), });
  • src/server.ts:59-67 (registration)
    Registration of relayWorkflowRunDefinition in the TOOLS array provided to MCP listTools handler.
    const TOOLS = [ relayModelsListDefinition, relayRunDefinition, relayWorkflowRunDefinition, relayWorkflowValidateDefinition, relaySkillsListDefinition, relayRunsListDefinition, relayRunGetDefinition, ];
  • src/server.ts:119-122 (registration)
    Dispatch case in MCP callTool handler that invokes the relay_workflow_run tool implementation.
    case 'relay_workflow_run': { const parsed = relayWorkflowRunSchema.parse(args); result = await relayWorkflowRun(parsed); break;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/RelayPlane/mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server