AI Agents
Add artificial intelligence capabilities to your Appivo applications
AI Agents
An AI agent is a named, reusable AI capability you invoke from your app. Give it inputs, it runs an LLM-driven pipeline — optionally calling tools, searching your data, or chaining several steps — and returns a result you can use in code or show in the UI.
Agents are good at the work that's awkward to write by hand: generating code, analysing text, translating, transcribing media, answering questions over your own content, and turning messy input into structured output.
There are two ways in:
- Use a pre-built agent — Appivo ships a library of ready-made agents. Call one and you're done.
- Build a custom agent — define your own agent as JSON: its inputs, model, prompts, tools, and steps.
Start with the pre-built agents; reach for a custom agent when none of them fit.
Pre-built agents
Appivo includes a library of pre-built agents you can call immediately. The most commonly used:
| Agent | What it does |
|---|---|
generate-code | Generates JavaScript for actions, following Appivo patterns |
generate-data-model | Creates Appivo data models from a description |
generate-query | Builds optimized database queries |
frontend-code-analyzer | Reviews code for security, performance, and best practices |
clean-html | Cleans and sanitizes HTML |
extract-keywords | Pulls keywords from text |
translate | Translates text between languages |
transcribe-audio | Transcribes audio to text |
transcribe-image | Extracts text from images (OCR) |
generate-response | Generates a contextual response, often over retrieved content |
Calling an agent
How you call an agent depends on where your code runs.
| Where | How |
|---|---|
| Server-side action | context.getAIFunctions().invokeAgent(name, options) |
| Client-side UI | the <aibutton> widget |
| Custom client UI | a server action that proxies invokeAgent |
From a server-side action
Call invokeAgent with the agent name and an arguments object. The result has a success flag, plus result or error:
const aiFunctions = context.getAIFunctions();
const aiResult = await aiFunctions.invokeAgent('generate-code', {
arguments: {
instructions: 'Create a function to calculate order totals with tax',
context: { model: 'Order' }
}
});
if (aiResult.success) {
return { success: true, data: aiResult.result };
}
return { success: false, error: aiResult.error };
invokeAgent accepts a few optional fields alongside arguments:
await aiFunctions.invokeAgent('agent-name', {
arguments: { query: 'user question', data: someData },
// Prior turns, for conversational context
history: [
{ role: 'user', message: 'previous question' },
{ role: 'ai', message: 'previous response' }
],
// Turn specific built-in tools off for this call
disableTools: ['webSearch'],
// Override the agent's prompts for this call
prompts: {
system: 'Custom system prompt',
user: 'Custom user prompt template'
}
});
From the UI
Drop an <aibutton> into a view to run an agent from the client. Wire onresult to handle the output and onask to show a loading state:
<aibutton
:agent="'generate-data-model'"
:onresult="handleAiResult"
:onask="showLoadingState">
</aibutton>
methods: {
handleAiResult(data) {
this.processGeneratedModel(data);
},
showLoadingState() {
this.isProcessing = true;
}
}
From a custom client UI
For custom interfaces, wrap invokeAgent in a server action and call that action from the client:
// Server action: InvokeAIAgent
const result = await context.getAIFunctions().invokeAgent(params.agent, {
arguments: params.arguments,
history: params.history
});
return result;
// Client
const result = await context.executeAction('InvokeAIAgent', {
agent: 'generate-code',
arguments: { instructions: userPrompt, model: currentModel }
});
Utility AI functions
Beyond invokeAgent, the AI Functions API exposes a few direct helpers:
const aiFunctions = context.getAIFunctions();
// Detect the language of some text → { language: "English", code: "en" }
const langInfo = aiFunctions.detectLanguage(text);
// Summarize a document
const summary = aiFunctions.summarizeDocument(document, {
chunkSize: 4000,
maxOutputTokens: 1000,
temperature: 0.2,
model: 'gemini-2.5-flash'
});
How an agent is built
A custom agent is a small amount of JSON. Three pieces nest inside each other:
- Agent — the named, reusable capability, with its inputs and output shape.
- Chain — the pipeline the agent runs: its tools and its steps.
- Step — one model call, with its own model, prompts, optional retriever, and tool access. Steps run in order and can branch.
Building a custom agent
Define the agent as JSON, then register it (see Registering an agent). A complete example:
{
"name": "CustomerInsightsAgent",
"description": "Analyzes customer feedback and generates actionable insights",
"version": 1,
"input": [
{ "name": "feedback", "type": "string", "description": "Feedback text to analyze" },
{ "name": "category", "type": "string", "description": "product | service | support" }
],
"output": {
"type": "json",
"example": {
"sentiment": "positive|neutral|negative",
"score": 0.85,
"insights": ["insight1", "insight2"],
"actionItems": ["action1", "action2"]
}
},
"steps": [
{
"name": "AnalyzeStep",
"maxCycles": 3,
"model": {
"provider": "google",
"name": "gemini-2.5-pro",
"temperature": 0.7,
"maxOutputTokens": 4096
},
"systemPrompt": {
"text": "You are an expert customer feedback analyst."
},
"userPrompt": {
"type": "template",
"text": "Category: {{input.category}}\nFeedback: {{input.feedback}}\n\nAnalyze and provide insights."
},
"output": { "type": "json" }
}
]
}
Inputs and output
Declare the inputs the agent accepts and the shape it returns.
- Input types:
string,number,boolean,object,array. - Output types:
string(plain text),json(structured),html(formatted).
For json output, include an example — the model uses it as the target shape.
Model
Each step picks its own model and parameters:
"model": {
"provider": "google|openai|anthropic",
"name": "model-name",
"temperature": 0.7,
"maxOutputTokens": 4096,
"topP": 0.95,
"topK": 40
}
| Provider | Models |
|---|---|
gemini-2.5-pro, gemini-2.5-flash, gemini-3-flash-preview | |
| OpenAI | gpt-4o, gpt-4o-mini, gpt-4-turbo |
| Anthropic | claude-3-haiku, claude-3-sonnet, claude-sonnet-4-20250514 |
Match the model to the job: a fast, cheap model (
gemini-2.5-flash,gpt-4o-mini) for simple steps, a stronger one (gemini-2.5-pro) where reasoning matters.
Prompts
A step has a systemPrompt (who the model is) and a userPrompt (the task). Three forms:
// Plain text
"systemPrompt": { "text": "You are a helpful assistant." }
// Template — interpolate inputs with {{ }}
"userPrompt": {
"type": "template",
"text": "Process {{input.data}} for {{input.userName}}"
}
// Multi-part — mix text with document and image attachments
"userPrompt": {
"parts": [
{ "type": "text", "text": "Analyze this document:" },
{ "name": "document", "type": "document" },
{ "name": "image", "type": "image" }
]
}
Multiple steps and branching
Chain steps for multi-stage work. A step's links route to the next step based on its output, so an agent can branch on what it finds:
{
"name": "DocumentProcessor",
"steps": [
{
"name": "ExtractInfo",
"model": { "provider": "google", "name": "gemini-2.5-flash" },
"output": { "type": "json" },
"links": [
{ "condition": "output.documentType == 'invoice'", "nextStep": "ProcessInvoice" },
{ "condition": "output.documentType == 'receipt'", "nextStep": "ProcessReceipt" }
]
},
{ "name": "ProcessInvoice", "model": { "provider": "google", "name": "gemini-2.5-pro" } },
{ "name": "ProcessReceipt", "model": { "provider": "google", "name": "gemini-2.5-flash" } }
]
}
Tools
Tools are capabilities the model can decide to call mid-turn — search your indexes, read a web page, summarize a document, generate a chart or image, run sandboxed code, remember and recall facts, or query a knowledge dataset. Declare them in the chain's tools array; the type field selects each one:
{
"name": "DataAnalysisAgent",
"tools": [
{ "type": "SEARCH", "index": "product-docs", "limit": 8 },
{ "type": "executeCode" }
],
"steps": [
{
"name": "Analyze",
"maxCycles": 5,
"systemPrompt": { "text": "Use the tools to answer questions about the app's data." }
}
]
}
A step that calls tools needs room to work: a tool call plus a final answer is at least two model turns, so set
maxCyclesto 2 or more (higher if you expect several calls in a row).
For every built-in tool — each type, its configuration, defaults, and a copy-paste cheat-sheet — see the AI Agent Tools reference.
Conversation memory
For conversational agents, control how much history a step carries:
{
"name": "ConversationalStep",
"chatWindowSize": 50,
"chatWindowTokens": 32768,
"includeFormat": true
}
For durable, per-user memory that persists across conversations — preferences, facts, decisions — use the memory tools and the AI Memory platform instead.
RAG: answering from your own content
Retrieval-Augmented Generation lets an agent answer from your documents and data instead of the model's general knowledge. You index your content in a search index, then a step retrieves the most relevant pieces and hands them to the model as context.
Create a search index
In the builder, go to Logic → Search Indexes, create an index, pick the data model and attributes to include, and choose a search type:
| Type | How it matches |
|---|---|
| TEXT | Keyword search (BM25) |
| VECTOR | Semantic similarity, using embeddings |
| BOTH | Hybrid — combines both with Reciprocal Rank Fusion |
Indexing options let you preprocess text before indexing, add transformers to generate extra searchable content, and control chunking (2000 characters max per chunk, 200-character overlap by default).
Retrieve inside a step
Attach a retriever to a step; the results land in {{retrievedDocuments}} for the prompt:
{
"name": "AnswerWithContext",
"retriever": {
"type": "searchIndex",
"indexName": "KnowledgeBase",
"maxResults": 5,
"minScore": 0.7
},
"model": { "provider": "google", "name": "gemini-2.5-pro" },
"systemPrompt": { "text": "Answer using the provided context. If it isn't there, say so." },
"userPrompt": {
"type": "template",
"text": "Context:\n{{retrievedDocuments}}\n\nQuestion: {{input.question}}"
}
}
Search from an action
You can also search directly and pass the results to an agent yourself:
const searchResults = await context.searchIndex('KnowledgeBase', {
query: userQuestion,
type: 'BOTH',
limit: 5
});
const answer = await context.getAIFunctions().invokeAgent('generate-response', {
arguments: {
question: userQuestion,
context: searchResults.documents.map(d => d.content).join('\n'),
instructions: 'Answer based on the provided context'
}
});
For exact, relational questions ("how many retail clients", "who worked with Acme"), RAG isn't the right tool — similarity search returns similar text, never a count. Use a Knowledge dataset for that.
Examples
Code review agent
Reviews JavaScript against Appivo best practices and returns a structured verdict:
{
"name": "CodeReviewer",
"description": "Reviews JavaScript code for Appivo best practices",
"input": [
{ "name": "code", "type": "string" },
{ "name": "context", "type": "object" }
],
"output": {
"type": "json",
"example": { "score": 85, "issues": [], "suggestions": [] }
},
"steps": [
{
"name": "ReviewCode",
"model": { "provider": "google", "name": "gemini-2.5-pro", "temperature": 0.3, "maxOutputTokens": 8000 },
"maxCycles": 3,
"systemPrompt": {
"text": "You are an expert Appivo code reviewer. Analyze the code for security, performance, and best practices."
},
"userPrompt": {
"type": "template",
"text": "Review this code from {{input.context.action}}:\n\n```javascript\n{{input.code}}\n```"
},
"output": { "type": "json" }
}
]
}
Translation agent with branching
Detects the language first, confirms if the model is unsure, then translates:
{
"name": "TranslationAgent",
"input": [
{ "name": "text", "type": "string" },
{ "name": "sourceLang", "type": "string" },
{ "name": "targetLang", "type": "string" }
],
"steps": [
{
"name": "DetectLanguage",
"model": { "provider": "google", "name": "gemini-2.5-flash" },
"output": { "type": "json" },
"userPrompt": { "text": "Detect the language of: {{input.text}}" },
"links": [
{ "condition": "output.confidence < 0.8", "nextStep": "ConfirmLanguage" },
{ "condition": "output.confidence >= 0.8", "nextStep": "Translate" }
]
},
{ "name": "ConfirmLanguage", "model": { "provider": "google", "name": "gemini-2.5-pro" } },
{
"name": "Translate",
"model": { "provider": "google", "name": "gemini-2.5-pro" },
"systemPrompt": { "text": "You are a professional translator. Preserve formatting and tone." },
"userPrompt": {
"type": "template",
"text": "Translate from {{input.sourceLang}} to {{input.targetLang}}:\n\n{{input.text}}"
}
}
]
}
Registering an agent
- Open the AI Agents section in the Application Builder.
- Click Create New Agent.
- Paste your JSON configuration.
- Save.
The agent is then callable by name from invokeAgent and <aibutton>.
Best practices
- Be specific. "Create validation for the email field on User — must be unique and a valid format" beats "validate email." Pass the model, field, and requirements as arguments.
- Right-size the model. Simple steps → a fast model; reasoning-heavy steps → a stronger one. Mixed within one agent is fine, step by step.
- Always check
success. Branch on thesuccessflag, readresulton success anderroron failure, and wrap the call intry/catchfor system errors. - Cache repeat work. For frequently requested, deterministic operations, cache on a key derived from the agent and arguments:
const cacheKey = `ai_${agentName}_${JSON.stringify(params)}`;
let result = await context.getCache(cacheKey);
if (!result) {
result = await context.getAIFunctions().invokeAgent(agentName, { arguments: params });
if (result.success) {
await context.setCache(cacheKey, result, 3600); // 1 hour
}
}
Troubleshooting
| Symptom | Things to check |
|---|---|
| Agent not found | Name spelled correctly; agent registered in this app; you have permission to use it. |
| Empty or unexpected result | Give more specific instructions and context; for json output, include an example; review the step prompts. |
| Slow responses | Use a lighter model for simple steps; enable caching; split complex work into steps. |
| Token limit exceeded | Reduce input size; summarize before processing; chunk large operations. |
API reference
| Where | Method | Purpose |
|---|---|---|
| Server | context.getAIFunctions().invokeAgent(name, options) | Run any agent |
| Server | aiFunctions.detectLanguage(text) | Detect a text's language |
| Server | aiFunctions.summarizeDocument(doc, options) | Summarize a document |
| Server | context.searchIndex(name, options) | Search a RAG index |
| Client | <aibutton agent="name"> | Run an agent from the UI |
Related guides
- AI Agent Tools — every built-in tool and how to configure it
- AI Memory — durable, per-user memory across conversations
- Knowledge — exact, relational answers over structured data
- AI Integration Example — end-to-end examples