Skip to main content

Running Agents

Once an agent is configured in the App Panel, you run it by calling get_agent() to look it up and agent.run() to execute it. This page covers every way to call an agent — from the simplest one-liner to files, memory sessions, JSON output, and background tasks.

The Basics

from zango.ai import get_agent

agent = get_agent("your-agent-name")
response = agent.run(input="Summarise the latest orders.")

print(response.content) # str — the LLM's text response
print(response.cost_usd) # float — cost of this invocation in USD
print(response.usage.input_tokens)
print(response.usage.output_tokens)

get_agent() looks up the agent by name in the current tenant's schema. It raises AgentNotFound if the name doesn't match or the agent is disabled.

agent.run() always returns an LLMResponse. Every invocation is automatically logged — see Invocation History.


Input Modes

There are three ways to provide input to agent.run(). The first non-None value wins.

1. Plain string (input=)

The simplest call. Pass a string directly as the user message.

agent = get_agent("support-agent")
response = agent.run(input="What are the refund policies?")
print(response.content)

Use this when the agent has a system prompt defined but no user prompt template — the system prompt provides the agent's instructions, and input= supplies the per-call user message directly.

2. Prompt variables (variables= and system_variables=)

When the agent has a User Prompt template configured with {{placeholders}}, pass a dict of values to render it via variables=.

agent = get_agent("patient-summary-agent")
response = agent.run(
variables={"patient_id": 42, "question": "Summarise this patient's recent visits."},
triggered_by="user",
)
print(response.content)

If the System Prompt also has {{placeholders}}, pass those separately via system_variables=. The two dicts are independent — variables renders the user prompt, system_variables renders the system prompt.

response = agent.run(
variables={"patient_id": 42, "question": "What medications is this patient on?"},
system_variables={"department": "cardiology", "protocol_version": "2026-Q1"},
triggered_by="user",
)

If system_variables is omitted, the system prompt is used as-is (no substitution).

3. Full message list (messages=)

For multi-turn conversations or when you need to inject history manually, pass a list of LLMMessage objects directly. This bypasses the agent's prompt template.

from zango.ai import get_agent, LLMMessage

agent = get_agent("chat-agent")
response = agent.run(
messages=[
LLMMessage(role="user", content="What's the capital of France?"),
LLMMessage(role="assistant", content="Paris."),
LLMMessage(role="user", content="And what's its population?"),
],
triggered_by="user",
)
print(response.content)

Running with File Attachments

Pass one or more LLMFile objects via files= to send documents or images alongside the prompt. Files work with all three input modes above.

from zango.ai import get_agent, LLMFile

From a model file field

The most common case in app code — pass a Django file field directly.

agent = get_agent("report-analyser")
response = agent.run(
input="Summarise the key findings from this report.",
files=[LLMFile.from_django_file(report.report_file)],
triggered_by="user",
)

From a request upload

For files submitted directly in the HTTP request.

agent = get_agent("prescription-processor")
response = agent.run(
input="Extract the medication names and dosages from this prescription.",
files=[LLMFile.from_django_file(request.FILES["prescription"])],
triggered_by="user",
)

From raw bytes

When you have the file content in memory (e.g., generated programmatically or fetched from an API).

agent = get_agent("invoice-agent")
response = agent.run(
input="Extract the total amount and line items from this invoice.",
files=[LLMFile.from_bytes(pdf_bytes, media_type="application/pdf")],
triggered_by="system",
)

From a public URL

When the file is publicly accessible — no download needed, the provider fetches it directly.

agent = get_agent("image-tagger")
response = agent.run(
input="Describe what's in this image and suggest tags.",
files=[LLMFile.from_url("https://cdn.example.com/product-photo.jpg")],
triggered_by="user",
)

Multiple files

Pass a list to send multiple attachments in one call.

agent = get_agent("lab-results-agent")
response = agent.run(
input="Compare these two lab reports and highlight changes.",
files=[
LLMFile.from_django_file(case.lab_report_jan),
LLMFile.from_django_file(case.lab_report_feb),
],
triggered_by="user",
)

Running with Memory

When an agent has Short-term memory enabled in the App Panel, it retains conversation history across multiple agent.run() calls within the same session.

Starting a session

On the first call, omit session_id — the agent auto-generates one and returns it on the response.

agent = get_agent("support-agent")

# First turn — no session_id yet
response = agent.run(
input="I need help resetting my password.",
triggered_by="user",
)

session_id = response.session_id # save this for subsequent turns
print(response.content)

Continuing a session

Pass the same session_id on every subsequent call to load prior conversation history.

# Second turn — agent remembers the first message
response = agent.run(
input="I tried the reset link but it says it's expired.",
session_id=session_id,
triggered_by="user",
)
print(response.content)

# Third turn
response = agent.run(
input="OK I got a new link, it worked. Thanks!",
session_id=session_id,
triggered_by="user",
)
print(response.content)

Persisting session_id

Store response.session_id and pass it back on subsequent calls — for example in the browser session, a database record, or returned in an API response so the client can echo it on the next request.

agent = get_agent("chat-agent")
response = agent.run(
input=user_message,
session_id=session_id, # None on first turn, session_id on subsequent turns
user_ref=str(request.user.pk),
triggered_by="user",
)
# Pass response.session_id back to the caller so the next request can continue the session

Clearing a session

Call agent.clear_session() to deactivate a session and delete its stored messages. Useful when a conversation is complete or a user explicitly starts fresh.

agent = get_agent("chat-agent")
cleared = agent.clear_session(session_id)
# Returns True if found and cleared, False if not found
note

Memory stores text content only. File attachments are replaced with [file: attachment] placeholders in the session history to avoid storing large base64 blobs.


Running with JSON Output

When an agent's Output Schema is set to JSON in the App Panel, the response includes a parsed_content attribute with the already-parsed dict.

agent = get_agent("structured-extractor")
response = agent.run(
variables={"document_id": 7},
triggered_by="user",
)

# response.content is the raw JSON string
# response.parsed_content is the parsed dict (validated against schema if configured)
data = response.parsed_content
print(data["total_amount"])
print(data["line_items"])

If the response cannot be parsed as JSON, OutputParseError is raised. If a JSON Schema is configured on the agent and the response doesn't match, OutputValidationError is raised.

from zango.ai.exceptions import OutputParseError, OutputValidationError

try:
response = agent.run(variables={"document_id": 7}, triggered_by="user")
data = response.parsed_content
except OutputParseError:
# LLM returned invalid JSON
...
except OutputValidationError as e:
# JSON didn't match the configured schema
print(e.errors)

Running from an Async Task

Use triggered_by="task" when running an agent from a background job. Zango's tenant context is set automatically inside task execution.

from zango.apps.tasks.base import BaseTask


class NightlyPatientSummaryTask(BaseTask):
name = "nightly_patient_summary"

def run(self):
from zango.ai import get_agent
from .models import Patient

agent = get_agent("patient-summary-agent")
patients = Patient.objects.filter(flagged_for_review=True)

for patient in patients:
response = agent.run(
variables={
"patient_id": patient.id,
"question": "Summarise this patient's recent activity and flag any concerns.",
},
triggered_by="task",
)
patient.ai_summary = response.content
patient.save(update_fields=["ai_summary"])

The triggered_by Parameter

Every agent.run() call requires a triggered_by value. It is stored in invocation history for auditing.

ValueWhen to use
"user"HTTP request triggered by a logged-in user
"task"Background job or scheduled task
"system"Programmatic call with no direct user action

The Response Object

response.content              # str — final text response from the LLM
response.parsed_content # dict | None — parsed JSON (when output_schema=JSON)
response.session_id # str | None — memory session ID (when short_term_memory is enabled)
response.cost_usd # float — total cost of this invocation
response.usage.input_tokens # int
response.usage.output_tokens # int
response.model # str — actual model used
response.latency_ms # int — total request time in milliseconds

Error Handling

All exceptions inherit from ZangoAIError and are importable from zango.ai.exceptions.

ExceptionRaised byWhenUseful attributes
AgentNotFoundget_agent()No agent with that name exists, or it is inactivee.name
AgentDisabledagent.run()Agent exists but is toggled off in the App Panele.name
PromptRenderErroragent.run()A {{variable}} placeholder in the prompt was not supplied in variables=e.missing_vars (list)
BudgetExceededagent.run()The provider's monthly spend limit has been reachede.provider_name, e.budget_limit
RateLimitExceededagent.run()The provider's rate limit was hite.retry_after_seconds
LLMTimeoutErroragent.run()The LLM request timed out
LLMAPIErroragent.run()The provider returned an API-level errore.status_code, e.original_error
OutputParseErroragent.run()Output Schema is JSON but the response couldn't be parsed
OutputValidationErroragent.run()Parsed JSON doesn't match the configured JSON Schemae.field, e.errors (list)
from zango.ai import get_agent
from zango.ai.exceptions import AgentNotFound, ZangoAIError

try:
agent = get_agent("my-agent")
response = agent.run(variables={"patient_id": 42}, triggered_by="user")
except AgentNotFound:
... # name doesn't exist or agent is inactive
except ZangoAIError:
... # catch any other AI framework error (see table above)

Next Steps

Every agent.run() call is recorded automatically. Use Invocation History to inspect prompts, tool calls, costs, and debug failures.