T
Telephony SOPKnowledge Base
Search
← All topics

POM Builder — Prompt Object Model for Agents SDK

runnable

PomBuilder constructs structured Markdown or XML prompts for voice AI agents. Sections, subsections, bulleted instructions, incremental additions, serialization, and the relationship between PomBuilder and AgentBase.prompt_add_section.

signalwireagents-sdkpomprompt-engineering
Agent trigger phrases: PomBuilder Python · Prompt Object Model SignalWire · structured AI prompt · prompt_add_section · POM markdown XML render

POM Builder — Prompt Object Model

PomBuilder is a structured prompt construction tool from the SignalWire Agents SDK. It renders to clean Markdown (or XML) — formats that LLMs follow much more reliably than free-form text. AgentBase exposes shortcuts (prompt_add_section, prompt_add_subsection), and PomBuilder underlies them.

When to use the builder directly: when you're constructing prompts outside an AgentBase (e.g., embedding the same prompt in multiple agents), or when you need to serialize, reconstruct, or merge prompt sections programmatically.

Install

pip install signalwire-pom

PomBuilder is a separate package — only required if you import it directly.

from signalwire.core.pom_builder import PomBuilder

Building a structured prompt

pom = PomBuilder()

pom.add_section("Role", body="You are a customer service agent for Acme Plumbing.")
pom.add_section("Guidelines", bullets=[
    "Be concise.",
    "Never promise specific timelines.",
    "Always confirm caller identity before discussing accounts.",
])
pom.add_subsection("Guidelines", "Escalation", body="Transfer to a human if unresolved after 2 attempts.")
pom.add_to_section("Guidelines", bullet="Always verify caller identity first.")

prompt_text = pom.render()

render() returns Markdown:

## Role
You are a customer service agent for Acme Plumbing.

## Guidelines
- Be concise.
- Never promise specific timelines.
- Always confirm caller identity before discussing accounts.
- Always verify caller identity first.

### Escalation
Transfer to a human if unresolved after 2 attempts.

XML rendering

For LLMs that respond better to XML (Claude, some open-source models):

prompt_xml = pom.render(format="xml")
<section name="Role">
  <body>You are a customer service agent for Acme Plumbing.</body>
</section>
<section name="Guidelines">
  <bullets>
    <item>Be concise.</item>
    ...
  </bullets>
  <subsection name="Escalation">
    <body>Transfer to a human if unresolved after 2 attempts.</body>
  </subsection>
</section>

Incremental additions

PomBuilder is mutable. Add sections at construction time and append later as conditions change.

pom = PomBuilder()
pom.add_section("Role", body="You are a sales agent.")

# Later, after a CRM lookup
if customer.is_vip:
    pom.add_section("VIP", body="Treat this caller as VIP. Skip qualification questions.")

agent.set_prompt_text(pom.render())

Serialization and reconstruction

# Serialize to dict/JSON
data = pom.to_dict()

# Save to file or send over the wire
import json
with open("base_prompt.json", "w") as f:
    json.dump(data, f)

# Reconstruct elsewhere
pom2 = PomBuilder.from_dict(data)

Useful for sharing a base prompt across multiple agents, or version-controlling prompts as JSON.

AgentBase shortcuts (no need for PomBuilder directly)

If you're inside an AgentBase subclass, the same methods exist on self:

class SupportAgent(AgentBase):
    def __init__(self):
        super().__init__(name="support")

        self.prompt_add_section("Role", "You are a customer service agent.")
        self.prompt_add_section("Guidelines", bullets=[
            "Be concise.",
            "Never promise timelines.",
        ])
        self.prompt_add_subsection("Guidelines", "Escalation",
            "Transfer to a human if unresolved after 2 attempts.")
        self.prompt_add_to_section("Guidelines",
            bullet="Always verify caller identity first.")

Internally these call the underlying PomBuilder. Use them when you have a single agent. Use PomBuilder directly when prompts are shared across agents or built outside the SDK.

Prompt structure that works

LLMs follow this Markdown shape well for voice agents:

## Role
One-sentence persona.

## Goals
Bulleted list of what success looks like.

## Guidelines
Bulleted list of behavioral rules.

### Tone
Sub-section overrides.

## Tools
Bulleted list of available SWAIG functions and when to use each.

## Examples
Optional short dialogue examples.

Keep total prompt length under ~1500 tokens for voice agents. Longer prompts add latency on every turn.

Anti-patterns

  • Dumping unstructured paragraphs into a single section — LLMs do not weight prose evenly. Use bullets.
  • Mixing render formats mid-conversation (Markdown one turn, XML the next) — pick one per agent.
  • Using PomBuilder inside an AgentBase subclass when the shortcuts exist — adds indirection for no gain.
  • Forgetting to call agent.set_prompt_text(pom.render()) after edits — the agent runs with the stale prompt.
  • Storing prompts as raw strings in code instead of pom.to_dict() → JSON — kills git diffability.

See also