Skip to main content
Last updated on

Demo Architecture Reference

Quick reference for the demo agent architecture. For setup, see the Temporal Integration Guide. For customization, see Extending the Demo Agent.

System Layers

LayerTechnologyRole
ClientReact, Vite, TailwindSends messages, displays responses, shows tool confirmations
APIFastAPITranslates HTTP requests into Temporal signals and queries
OrchestrationTemporalRuns the agent loop, executes tools via activities
IntegrationLiteLLM, MCPMulti-provider LLM calls, external tool servers
GovernanceOpenBox SDKIntercepts workflow and activity events for policy evaluation
ExternalOpenAI, Anthropic, Stripe, etc.LLM providers and third-party APIs

Message Flow

  1. User sends message → frontend POSTs to /send-prompt
  2. FastAPI signals the Temporal workflow with user_prompt
  3. Workflow calls agent_validatePrompt activity → LLM checks relevance to current goal
  4. generate_genai_prompt() builds the system prompt (runs in workflow, no I/O)
  5. Workflow calls agent_toolPlanner activity → LLM returns structured JSON
  6. next field determines the path: question, confirm, done, or pick-new-goal
  7. If confirm → frontend shows confirmation dialog → user clicks → POSTs to /confirm
  8. Workflow calls dynamic_tool_activity → native handler or MCP server
  9. Tool result added to conversation history → loop back to step 4

Workflow

AgentGoalWorkflow in workflows/agent_goal_workflow.py — the main state machine that drives the agent.

Signals

SignalPurpose
user_promptDelivers the user's message to the workflow
confirmTells the workflow the user approved a tool call
end_chatTerminates the conversation

Queries

QueryReturns
get_conversation_historyFull conversation as ConversationHistory
get_agent_goalCurrent goal configuration as AgentGoal
get_latest_tool_dataPending tool call data (if any) as ToolData

Continue-as-New

After 250 turns (MAX_TURNS_BEFORE_CONTINUE), the workflow starts a fresh execution, passing along the conversation summary and current state.

Activities

Temporal requires workflow code to be deterministic — no network calls, randomness, or clock reads. All I/O runs as activities.

ActivityFilePurpose
agent_toolPlanneractivities/tool_activities.pyCalls LLM via LiteLLM, returns structured JSON with the agent's next action
agent_validatePromptactivities/tool_activities.pyCalls LLM to check if the user's message is relevant to the current goal
dynamic_tool_activityactivities/tool_activities.pyDispatches tool calls to native handlers or MCP servers

LLM Response Format

agent_toolPlanner returns a structured JSON response from the LLM:

{
"response": "I'll look up your PTO balance. Can you confirm?",
"next": "confirm",
"tool": "CurrentPTO",
"args": { "email": "bob@example.com" }
}
FieldTypeDescription
responsestringAgent's message to the user
nextstringNext step — see values below
toolstring | nullTool to execute (if applicable)
argsobject | nullTool arguments (if applicable)

next Values

ValueMeaning
questionAgent needs more information — waits for next user message
confirmAgent wants to run a tool — waits for user confirmation
doneTask complete — agent gives a final response
pick-new-goalUser wants to switch to a different agent/scenario

Prompt Generation

generate_genai_prompt() in prompts/agent_prompt_generators.py builds the system prompt. Runs directly in the workflow (deterministic, no I/O).

ComponentSource
Agent role and personaHardcoded in prompt template
Goal descriptionagent_goal.description
Tool definitionsagent_goal.tools — name, description, arguments per tool
Conversation historyconversation_history — full message list
Response format schemaJSON schema enforcing {response, next, tool, args}
Example interactionsagent_goal.example_conversation_history

Tool Dispatch

dynamic_tool_activity routes tool calls based on handler lookup:

StepLogic
1. Native checkget_handler(tool_name) in tools/__init__.py — if found, call handler directly
2. MCP fallbackIf get_handler() raises ValueError, start MCP server as stdio subprocess → ClientSessionsession.call_tool()

Both paths execute as Temporal activities — OpenBox automatically intercepts and governs them.

API Endpoints

FastAPI layer in api/main.py:

MethodEndpointPurpose
POST/send-promptSend a user message — starts the workflow if needed, then signals it
POST/confirmSignal tool confirmation
POST/end-chatSignal chat end
POST/start-workflowStart the workflow with the goal's starter prompt
GET/get-conversation-historyQuery conversation history from the running workflow
GET/tool-dataQuery current pending tool call data
GET/agent-goalQuery current goal configuration

The frontend polls /get-conversation-history to pick up new messages.

OpenBox Governance

create_openbox_worker in scripts/run_worker.py wraps the Temporal worker with governance interceptors.

CapabilityDetail
Workflow eventsIntercepts start, complete, fail, and signal events
Activity executionCaptures inputs and outputs of every activity
HTTP captureOpenTelemetry instrumentation records outbound requests with full bodies
Policy evaluationEach event evaluated against configured policies on the platform
DecisionsEvery event gets a governance decision — approved, blocked, or flagged
Zero agent-side code

All governance evaluation happens on the platform side, not in the agent code. The agent is unaware of what policies are configured — it just runs, and OpenBox observes and enforces.

Key Files

PathPurpose
scripts/run_worker.pyWorker bootstrap — create_openbox_worker integration point
api/main.pyFastAPI endpoints — HTTP bridge to Temporal
workflows/agent_goal_workflow.pyAgentGoalWorkflow — main state machine
workflows/workflow_helpers.pyis_mcp_tool(), continue-as-new logic, tool dispatch helpers
activities/tool_activities.pyLLM activities, tool execution, MCP dispatch
prompts/agent_prompt_generators.pygenerate_genai_prompt() — system prompt builder
tools/__init__.pyget_handler() — native tool registry
tools/tool_registry.pyToolDefinition instances for each native tool
goals/Goal definitions — one file per category
goals/__init__.pyAggregates all goals into a single registry
models/tool_definitions.pyDataclasses: AgentGoal, ToolDefinition, ToolArgument, MCPServerDefinition
shared/mcp_config.pyPredefined MCP server configurations