Agents

Agents are the core building blocks of Vouchstone. They are intelligent AI entities that can understand context, maintain memory across interactions, and perform complex tasks autonomously.

What is an Agent?

An Vouchstone agent is more than just a chatbot. It's an AI-powered entity with:

  • Persistent Memory - Remembers past interactions and learned knowledge
  • Configurable Personality - Customizable tone, style, and behavior
  • Tool Access - Can use integrations and external services
  • Autonomous Capability - Can make decisions and take actions

Agent Types

Vouchstone provides several pre-configured agent types optimized for common use cases. You can also create custom agent types for specialized requirements.

Customer Support

Handle customer inquiries, troubleshoot issues, and provide product information.

Data Analyst

Analyze data, generate reports, and provide insights from your datasets.

Code Assistant

Help with code review, debugging, documentation, and development tasks.

Content Writer

Create blog posts, marketing copy, documentation, and other content.

Sales Assistant

Qualify leads, answer product questions, and assist with the sales process.

Custom Agent

Build a completely custom agent tailored to your specific requirements.

Creating an Agent

You can create agents using the dashboard UI or programmatically via the API/SDK.

Using the Dashboard

  1. Navigate to Agent Studio in the sidebar
  2. Click Create New Agent
  3. Select an agent type or start from scratch
  4. Configure the agent's name, description, and personality
  5. Select memory layers (working, episodic, semantic, procedural, meta-memory)
  6. Configure any integrations or tools the agent needs
  7. Review and create the agent

Using the Python SDK

from vouchstone_sdk import Agent, AgentConfig, Message, AgentResponse, MemoryContext

# Agents are built locally by subclassing Agent -- there is no server-side
# "create" call. Personality, tone, and guardrails live in your system
# prompt and run() logic, since that's what actually shapes model behavior.
class SupportHeroAgent(Agent):
    async def run(self, message: Message, context: MemoryContext) -> AgentResponse:
        # context.semantic_entities -- known entities (products, accounts, etc.)
        # context.procedural_skills -- learned support procedures
        response = await self.llm.complete(
            system=self.config.system_prompt,
            messages=[{"role": "user", "content": message.content}],
        )
        return AgentResponse(content=response)

config = AgentConfig(
    name="Support Hero",
    model="claude-sonnet-4-20250514",
    temperature=0.7,
    max_tokens=1000,
    system_prompt=(
        "You are Support Hero, a friendly, professional, and empathetic "
        "customer support agent. Keep responses concise but thorough. "
        "Never discuss competitor pricing. Escalate to a human when unsure."
    ),
    # All five memory layers are enabled by default (see AgentConfig).
    metadata={"team": "support", "language": "en"},
)

agent = SupportHeroAgent(config)
await agent.initialize(agent_id="support-hero-1")

print("Agent ready:", config.name)

Agent Configuration

Personality, Tone, and Guardrails

These aren't typed config fields — AgentConfig has nopersonality, tone, response_style, or guardrails options. They're expressed in natural language through system_prompt, since that's what actually shapes the underlying model's behavior:

config = AgentConfig(
    name="Support Hero",
    model="claude-sonnet-4-20250514",
    system_prompt=(
        "You are Support Hero: professional yet approachable, warm and "
        "helpful, semi-formal in tone. Structure responses with bullet "
        "points where useful and keep them under ~500 words. Never give "
        "medical or legal advice. If your confidence in an answer is low, "
        "say so and offer to escalate to a human rather than guessing."
    ),
)

System-Prompt Guardrails Are Not Enforced Boundaries

Instructions in system_prompt are a strong steer, not a hard constraint — the model can still be prompted around them. For anything that must hold every time (PII handling, dual sign-off, budget caps), enforce it in your run() logic or the platform's governance layer (the Constitution/Rule Book and Authority Matrix), not in prose alone.

Agent Lifecycle

States

Agents can be in one of several states:

  • Draft - Agent is being configured, not yet active
  • Active - Agent is running and can receive requests
  • Paused - Agent is temporarily disabled
  • Archived - Agent is deactivated but data is preserved

Managing Agent State

Lifecycle state lives on the control-plane Agent record, not the harness — manage it via the dashboard or the REST API directly:

# Activate (also resumes a paused agent)
curl -X POST https://your-control-plane-host/api/v1/agents/${AGENT_ID}/activate \
  -H "Authorization: Bearer ${TOKEN}"

# Pause
curl -X POST https://your-control-plane-host/api/v1/agents/${AGENT_ID}/pause \
  -H "Authorization: Bearer ${TOKEN}"

# Delete (soft-delete: sets status=archived, preserves memory/history)
curl -X DELETE https://your-control-plane-host/api/v1/agents/${AGENT_ID} \
  -H "Authorization: Bearer ${TOKEN}"

Interacting with Agents

For a harness process you're running yourself, send messages through process() — it prepares memory context, calls your run(), then persists the turn to episodic memory:

response = await agent.process(Message(content="How do I reset my password?"))
print(response.content)

# Concurrent turns across independent sessions
import asyncio

session_a = agent.start_session()
session_b = agent.start_session()
responses = await asyncio.gather(
    agent.process(Message(content="Question 1"), session_id=session_a),
    agent.process(Message(content="Question 2"), session_id=session_b),
)

Best Practices

Start with Clear Instructions

Provide detailed system instructions that clearly define the agent's role, capabilities, and limitations. The more specific, the better.

Use Appropriate Memory Types

Choose memory layers based on your use case. Not every agent needs all five memory layers - select what's relevant.

Implement Proper Escalation

Always configure escalation paths for situations the agent can't handle. Know when to hand off to a human.

Monitor and Iterate

Use analytics to track agent performance. Review conversations regularly and refine prompts and configurations based on real interactions.