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 and validate the reply to get a typed verdict.

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 '@stackbone/sdk';
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 lead-qualifier agent's own prompt, the one you publish for it in Studio, should tell it to always answer in that exact JSON shape, so the step can trust the parse.

What's next

BUILT WITH ❤️ FROM CANADA AND SPAIN