Skip to content

Agent Data Model ​

Complete reference for the Agent object structure and all enum types used in agent configuration.


Agent Object ​

The core agent object returned by create_agent, update_agent, and get_agent.

Top-Level Fields ​

FieldTypeDescription
idintegerUnique agent identifier
namestringAgent display name
instructionsstringSystem prompt defining agent behavior
uristringURL-friendly identifier (e.g., "support-bot")
public_urlstring | nullFull public URL if access_level is PUBLIC
modelstringLLM model identifier
temperaturefloatResponse creativity (0.0-2.0)
reasoning_effortstringReasoning effort level (for reasoning models)
access_levelstringVisibility level (enum: see below)
domain_idintegerDomain ID for public URL
image_urlstring | nullAgent avatar/logo URL
empty_state_titlestring | nullWelcome screen title
empty_state_descriptionstring | nullWelcome screen description
suggested_promptslist[dict] | nullStarter prompts for users
created_atstringISO 8601 timestamp
updated_atstringISO 8601 timestamp

Nested Objects ​

FieldTypeDescription
knowledge_idslist[int]IDs of attached knowledge sources
knowledge_sourceslist[object]Full knowledge source objects with loading status
trait_idslist[int]IDs of applied personality traits
traitslist[object]Full trait objects
chat_theme_idinteger | nullID of chat theme
chat_themeobject | nullFull chat theme object
data_template_idinteger | nullID of data collection template
data_templateobject | nullFull data collection template object

Example Full Agent Object ​

json
{
  "id": 123,
  "name": "Support Bot",
  "instructions": "You are a helpful customer support agent that answers questions about our products...",
  "uri": "support-bot",
  "public_url": "https://joina.chat/support-bot",
  "model": "gpt-5-mini",
  "temperature": 0.7,
  "reasoning_effort": "medium",
  "access_level": "PUBLIC",
  "domain_id": 1,
  "image_url": "https://example.com/avatar.png",
  "empty_state_title": "Welcome to Support",
  "empty_state_description": "Ask me anything about our products!",
  "suggested_prompts": [
    {
      "icon": "i-heroicons-light-bulb",
      "title": "Get Started",
      "text": "What can you help me with?"
    }
  ],
  "knowledge_ids": [10, 20],
  "knowledge_sources": [
    {
      "id": 10,
      "name": "Product Docs",
      "url": "https://docs.example.com",
      "type": "sitemap",
      "status": "ready"
    },
    {
      "id": 20,
      "name": "FAQ",
      "url": "https://example.com/faq",
      "type": "website",
      "status": "loading"
    }
  ],
  "trait_ids": [1, 3],
  "traits": [
    {"id": 1, "name": "Friendly"},
    {"id": 3, "name": "Professional"}
  ],
  "chat_theme_id": 5,
  "chat_theme": {
    "id": 5,
    "preset": "standard",
    "greeting": "How can I help you today?"
  },
  "data_template_id": 2,
  "data_template": {
    "id": 2,
    "name": "Contact Info",
    "fields": [...]
  },
  "created_at": "2026-01-15T10:30:00Z",
  "updated_at": "2026-01-20T14:22:00Z"
}

Enums ​

access_level ​

Defines who can interact with the agent.

ValueDescriptionUse Case
PRIVATEOnly accessible via API with authenticationInternal tools, authenticated apps
PUBLICAnyone with the joina.chat link can chatPublic-facing agents, website embedding
PASSWORD_PROTECTEDPublic link but requires passwordShared with specific users/teams

Examples:

python
# Internal assistant
create_agent(name="Internal Bot", access_level="PRIVATE")

# Public support bot
create_agent(name="Support", access_level="PUBLIC", uri="support")

# Partner portal
create_agent(name="Partner Bot", access_level="PASSWORD_PROTECTED", password="secret123")

collection_mode ​

Defines how aggressively an agent collects data from conversations.

ValueDescriptionWhen to Use
passiveSilent extraction after conversation endsNon-intrusive, background collection
opportunisticCaptures when user mentions data, brief follow-upsBalanced approach, most common
activeProactively asks for information during chatLead generation, high-value data
guidedFollows custom script (requires custom_prompt)Structured interviews, complex forms

Behavior comparison:

ModeUser mentions emailUser doesn't mention email
passiveCaptures it silentlyDoesn't ask
opportunisticCaptures it + brief "And your phone?"Doesn't ask
activeCaptures it + asks for all missing fieldsAsks for email + all fields
guidedFollows custom scriptFollows custom script

Examples:

python
# Passive: background analytics
data_collection={
    "template_name": "Feedback",
    "fields": [...],
    "collection_mode": "passive"
}

# Active: sales lead capture
data_collection={
    "template_name": "Lead Info",
    "fields": [...],
    "collection_mode": "active"
}

# Guided: job application
data_collection={
    "template_name": "Application",
    "fields": [...],
    "collection_mode": "guided",
    "custom_prompt": "Walk the candidate through each section..."
}

field_type ​

Data types for fields in data collection templates.

ValueDescriptionValidationExample
textFree-form textNoneName, description, feedback
emailEmail addressValid email formatuser@example.com
phonePhone numberValid phone format+1-555-123-4567
numberNumeric valueMust be numberAge: 25, quantity: 10
dateDate valueISO 8601 or natural language2026-01-15, "next Monday"
urlURLValid URL formathttps://example.com

Examples:

python
fields=[
    {"name": "full_name", "type": "text", "required": True},
    {"name": "email", "type": "email", "required": True},
    {"name": "phone", "type": "phone", "required": False},
    {"name": "age", "type": "number", "required": False},
    {"name": "start_date", "type": "date", "required": False},
    {"name": "website", "type": "url", "required": False}
]

knowledge_source_type ​

Type of knowledge source for RAG-based retrieval.

ValueDescriptionWhen to Use
websiteCrawls pages recursively from starting URLGeneral website content, blogs
sitemapFollows sitemap.xml for page discoveryWell-structured docs sites, large sites
discoveryCrawl-based discovery via NeoReader, no sitemap requiredDefault fallback when no sitemap exists — omit type to get this automatically

The table above describes the stored data_type and how each is loaded. As an input to gnosari_manage_knowledge(action="create"), type behaves differently: omitting it or passing "website" triggers server-side auto-resolve — it probes for a sitemap first and falls back to discovery if none is found (so a website input is stored as sitemap or discovery, never website). Pass single_page=true to store a single-page website source without probing. Most callers never need to pick a value explicitly — see the Manage Resources reference for the full probe order.

Behavior comparison:

TypeDiscovery MethodBest For
websiteRecursive link followingSmall sites, blogs, marketing pages
sitemapReads sitemap.xmlDocumentation sites, large structured sites
discoveryNeoReader crawl at load timeFallback when no sitemap is found — this is what auto-resolve lands on

Examples:

python
# Whole-site (type="website" auto-resolves — same as omitting type)
knowledge_sources=[
    {"name": "Blog", "url": "https://example.com/blog", "type": "website"}
]

# Sitemap-based explicitly (skips the probe)
knowledge_sources=[
    {"name": "Docs", "url": "https://docs.example.com", "type": "sitemap"}
]

# Single page only — opt out of whole-site with single_page
gnosari_manage_knowledge(action="create", name="Pricing", url="https://example.com/pricing", single_page=True)

# Recommended default — omit type, server auto-resolves sitemap -> discovery
gnosari_manage_knowledge(action="create", name="Docs", url="https://docs.example.com")

AgentMutationResult Response ​

When creating or updating agents via create_agent or update_agent, the tool returns an AgentMutationResult Pydantic model with three fields:

FieldTypeDescription
agentAgentReadThe created or updated agent
created_resourceslist[str]String summaries of resources created as side-effects
warningslist[str]Non-fatal issues encountered during the operation

The created_resources list contains human-readable summaries, not structured objects. For details about inline-created resources, use the returned agent.id to call the relevant listing tools.

Example ​

python
result = create_agent(
    name="Sales Bot",
    instructions="...",
    knowledge_sources=[{"name": "Docs", "url": "https://docs.example.com", "type": "sitemap"}],
)

# Access typed attributes directly
print(result.agent.id)            # 123
print(result.agent.name)          # "Sales Bot"
print(result.agent.public_url)    # None (PRIVATE by default)
print(result.created_resources)   # ["knowledge_source: Docs (id=45, status=loading)"]
print(result.warnings)            # ["Knowledge source 'Docs' (ID: 45) is still loading."]

Legacy envelope format (removed) ​

Prior to Plan 18, tools returned {"success": True, "data": {...}} envelopes. That format no longer exists. Use attribute access on the returned Pydantic model:

python
# Old (broken): result["data"]["agent"]["id"]
# New (correct): result.agent.id

Checking inline-created resources ​

json
{
  "agent": {
    "id": 123,
    "name": "Sales Bot",
    "..."
  },
  "created_resources": [
    "knowledge_source: Docs (id=45, status=loading)"
  ],
  "warnings": [
    "Knowledge source 'Docs' (ID: 45) is still loading. Use get_knowledge_source to check status."
  ]
}

Warnings ​

Non-fatal issues that don't prevent agent creation:

WarningMeaningAction
"Knowledge source still loading"Async indexing in progressPoll with get_agent until status is "ready"
"Data template name matched existing"Inline template matched by name, existing one usedVerify with get_agent that correct template applied

Knowledge Source Status ​

Knowledge sources load asynchronously. The status field indicates loading progress.

StatusMeaningAgent BehaviorAction
loadingCurrently indexing pagesAgent works but without this knowledgeWait for completion
readySuccessfully indexedAgent uses this knowledgeNo action needed
failedIndexing failedAgent works without this knowledgeCheck URL accessibility, retry

Monitoring example:

python
# Create agent with knowledge
result = create_agent(
    name="Support Bot",
    instructions="...",
    knowledge_sources=[
        {"name": "Docs", "url": "https://docs.example.com", "type": "sitemap"}
    ]
)

# Check loading status
agent = get_agent(agent_id=result.agent.id)
for source in agent.knowledge_sources:
    print(f"{source.name}: {source.status}")

Next Steps ​