A workflow that delegates a turn to an agent

A triage workflow validates the incoming lead in a deterministic step, then hands the judgment to a lead-qualifier agent and parses a typed verdict out of its reply. callDeepAgent always resolves with plain text, because an agent turn has no typed output of its own. Ask for JSON in the message, then validate the reply.

The whole flow is a single workflows/triage-lead.workflow.ts file. The workflow stays auditable while the agent does the open-ended scoring.

workflows/triage-lead.workflow.ts
import { z } from 'zod';
import { callDeepAgent } from '@stackbone/sdk/workflow';

export const inputSchema = z.object({
  email: z.email(),
  company: z.string(),
  note: z.string(),
});
export const outputSchema = z.object({
  email: z.string(),
  score: z.number(),
  rationale: z.string(),
});

const verdictSchema = z.object({
  score: z.number().min(0).max(100),
  rationale: z.string(),
});

export async function triageLeadWorkflow(input: z.infer<typeof inputSchema>) {
  'use workflow';

  const clean = await validate(input); // deterministic gate
  const verdict = await scoreWithAgent(clean.company, clean.note); // agent judgment

  return { email: clean.email, score: verdict.score, rationale: verdict.rationale };
}

async function validate(input: z.infer<typeof inputSchema>) {
  'use step';
  if (!input.company.trim()) throw new Error('Missing company');
  return input;
}

async function scoreWithAgent(company: string, note: string) {
  'use step';
  const { text } = await callDeepAgent(
    'lead-qualifier',
    `Company: ${company}\nNote: ${note}\n` +
      'Score this lead from 0 to 100 and explain why. ' +
      'Reply with JSON only: {"score": number, "rationale": string}.',
  );
  // A malformed reply throws here, which fails the step and applies the
  // run's retry policy: a retry re-runs the whole turn.
  return verdictSchema.parse(JSON.parse(text));
}

The prompt you publish for lead-qualifier in Studio should ask for that exact JSON shape in every reply, so the step can trust the parse.

What's next

BUILT WITH ❤️ FROM CANADA AND SPAIN