Core Building Blocks / AI Agent

What is an Agent?

Understand agent types, model capabilities, session policies, and runtime requirements.

An agent is an AI-powered participant in your PURISTA system. It receives input, uses a language model to reason about it, optionally calls tools (commands, other agents), and returns a structured output.

Agents are not a separate runtime. They are commands and streams that happen to use AI models for their core logic. Agent capabilities require the @purista/ai-harness package — after installing it, getAgentBuilder becomes available on ServiceBuilder.

AI as a first-class citizen

Agents use the same service, event bridge, and HTTP exposure infrastructure as commands and streams. The only difference is that the handler delegates reasoning to an AI model instead of pure code. Requires @purista/ai-harness.

Agent types

Agents can be defined in three mutually exclusive ways:

TypeMethodUse case
Agent functionsetAgentFunction(fn)Custom logic with direct model access
Harness agentsetHarnessAgent(definition)Model-driven agent with tool calling
Harness workflowsetHarnessWorkflow(definition)Multi-step orchestrated workflow

You must pick exactly one execution type per agent.

Model capabilities

Agents declare which model capabilities they need. The runtime gates method availability based on these capabilities:

CapabilityAvailable methods
objectcontext.harness.models.alias.object(prompt)
textcontext.harness.models.alias.text(prompt)
embedcontext.harness.models.alias.embed(texts)
rerankcontext.harness.models.alias.rerank(query, documents)
.addModel('gpt4', {
  model: 'openai/gpt-4',
  capabilities: ['object', 'text'],
  defaults: { temperature: 0.7 },
})

If you declare only object capability, text() is not available at compile time or runtime.

Session policies

Agents can maintain conversation state:

ModeBehavior
ephemeral (default)No state persists between calls
conversationState is tracked across calls
.setSessionPolicy({
  mode: 'conversation',
  payloadPath: ['conversationId'], // which payload field identifies the session
})

Sandbox policy

For untrusted inputs or third-party models, enable sandboxing:

.setSandboxPolicy({
  enabled: true,
  adapter: 'isolated-vm', // or custom adapter
})

Runtime requirements

To run agents, your service needs:

import { ServiceBuilder } from '@purista/core'
import '@purista/ai-harness' // registers getAgentBuilder on ServiceBuilder

const aiV1ServiceBuilder = new ServiceBuilder({
  serviceName: 'AiService',
  serviceVersion: '1',
})

// add agent definitions, then:
const aiService = await aiV1ServiceBuilder.getInstance(eventBridge, {
  queueBridge: /* your queue bridge */,
  ai: {
    models: {
      gpt4: { /* model config */ },
    },
  },
})
Queue bridge required

Agents require a queueBridge in service options. Without it, agent execution fails at runtime. This is because agents may queue internal tasks or delegate to other agents.

Agent as queue-based

Agents are internally queue-based. When you invoke an agent, the request goes through the queue system:

// Inside an agent run function
const result = await context.invoke.agents['SupportAgent.1'].run({
  query: 'How do I reset my password?',
})

This queues the agent job and waits for completion (if the response mode requires it).

Response modes

Control how the agent returns results:

ModeBehavior
acceptedReturn immediately with job ID
statusReturn status after completion
streamStream chunks as they are generated
eventEmit an event on completion
callbackCall a callback URL on completion
.setResponseMode('stream', {
  progressEventName: 'agentResponseChunk',
})

Streaming agents

Agents can stream their reasoning:

.setStreamingMode('stream') // or 'aggregate'

In stream mode, the agent emits chunks as the model generates them. In aggregate mode, the full response is collected before returning.

Tools and skills

Agents call tools (commands) and other agents:

.canInvoke('UserService', '1', 'getUser')
.canInvokeAgent('SupportAgent', '1')
.useSkills(['customer-support', 'billing'])
.useBuiltInTools(['search', 'calculator'])

Tools are exposed to the model as functions it can call. The model decides which tools to use based on the input.

Execution policy

Fine-tune agent execution:

.setExecutionPolicy({
  leaseTtlMs: 60_000,
  heartbeatIntervalMs: 15_000,
  maxAttempts: 2,
  maxParallelHandlers: 1,
  timeoutMs: 300_000,
})

Execution profile

For long-running agents:

.setExecutionProfile('longRunning', {
  maxRuntimeMs: 600_000,
  strict: false,
})

Signal for cancellation

Agents can check for cancellation:

.setRunFunction(async function (context, payload, parameter) {
  if (context.signal.aborted) {
    return { cancelled: true }
  }
  // ... model reasoning
})