Core Building Blocks / AI Agent

Agent Workflows

Compose agents through PURISTA boundaries or wrap harness workflow definitions.

Agent workflows can be modeled at two levels:

Level Use when
PURISTA level Each agent needs its own queue, retry policy, model binding, sandbox, ownership boundary, or deployment surface.
Harness level Several reasoning steps should run inside one @purista/harness workflow definition with shared session and sandbox semantics.

Prefer PURISTA-level orchestration when the workflow crosses business boundaries. Use harness-level workflow definitions for tightly coupled inner reasoning steps.

PURISTA-level orchestration

Use canInvokeAgent(...) to allow one agent to call another attached PURISTA agent:

export const reviewCoordinatorAgentBuilder = projectV1ServiceBuilder
  .getAgentQueueBuilder('reviewCoordinator', 'Coordinates project review agents')
  .addPayloadSchema(reviewInputSchema)
  .addOutputSchema(reviewOutputSchema)
  .addModel('primary', {
    model: 'gpt-4.1-mini',
    capabilities: ['object'],
  })
  .canInvokeAgent('requirementsReview', '1', {
    payloadSchema: reviewInputSchema,
    outputSchema: reviewFindingSchema,
  })
  .canInvokeAgent('securityReview', '1', {
    payloadSchema: reviewInputSchema,
    outputSchema: reviewFindingSchema,
  })
  .setRunFunction(async context => {
    const [requirements, security] = await Promise.all([
      context.invoke.agents['requirementsReview.1'].run(context.payload),
      context.invoke.agents['securityReview.1'].run(context.payload),
    ])

    return reviewOutputSchema.parse({
      findings: [...requirements.findings, ...security.findings],
    })
  })

Each child agent keeps its own generated queue, worker, command, stream, execution policy, and runtime binding.

Harness-level workflows

Use setHarnessWorkflow(...) only when you already have a workflow definition from @purista/harness and want to expose it as one PURISTA agent. Pass harness-local agents in the second argument when the workflow calls ctx.agents:

import { incidentReviewWorkflow } from './incidentReviewWorkflow.js'
import { evidenceAgent, riskAgent } from './workflowAgents.js'

export const incidentWorkflowAgentBuilder = incidentV1ServiceBuilder
  .getAgentQueueBuilder('incidentReview', 'Reviews incident evidence')
  .addPayloadSchema(incidentReviewWorkflow.input)
  .addOutputSchema(incidentReviewWorkflow.output)
  .addModel('primary', {
    model: 'gpt-4.1-mini',
    capabilities: ['object', 'tool_use'],
  })
  .setHarnessWorkflow(incidentReviewWorkflow, {
    agents: {
      evidence: evidenceAgent,
      risk: riskAgent,
    },
  })

In this shape, PURISTA owns the outer queue, command, stream, HTTP exposure, and runtime wiring. The harness workflow owns the inner reasoning loop, and the supplied harness-local agents share the same session, sandbox, memory, telemetry, durable runtime, workspace store, and model bindings.

Streaming workflow output

The HTTP response shape is still selected with streamingMode:

.exposeAsHttpEndpoint('POST', 'agents/incident-review', {
  streamingMode: 'stream',
})

Use aggregate for a final JSON response and stream for server-sent events while the workflow runs.