Constructor
const agent = new ExuluAgent(options: ExuluAgentParams);
Creates a new ExuluAgent instance. See the configuration guide for all available options.
Methods
generateSync()
Generates a synchronous (non-streaming) response from the agent.
async generateSync({
prompt,
user,
session,
inputMessages,
currentTools,
allExuluTools,
statistics,
toolConfigs,
providerapikey,
contexts,
rerankers,
exuluConfig,
outputSchema,
agentInstance,
instructions,
req
}: GenerateSyncOptions): Promise<string | object>
The user’s prompt or question (mutually exclusive with inputMessages)
Array of conversation messages (mutually exclusive with prompt)
User object for access control and personalization
Session ID to load previous conversation history
Tools available to the agent during this execution
Complete list of all available tools (for nested tool calling)
Statistics tracking configuration with label and trigger
Tool-specific configuration overrides
API key for the LLM provider (overrides default)
Available contexts for semantic search
Available rerankers for search optimization
ExuluApp configuration object
Zod schema for structured output generation
Agent database record with configuration
Override default instructions for this execution
Express request object for context
Generated text response, or structured object if outputSchema is provided
// Simple text generation
const response = await agent.generateSync({
prompt: "What is the capital of France?",
agentInstance: agentData,
currentTools: [],
statistics: {
label: "assistant",
trigger: "api"
}
});
console.log(response); // "The capital of France is Paris."
// With tools
const response = await agent.generateSync({
prompt: "Search our docs for authentication information",
agentInstance: agentData,
currentTools: [documentSearchTool, databaseTool],
contexts: [docsContext],
statistics: {
label: "assistant",
trigger: "api"
}
});
// Structured output
const data = await agent.generateSync({
prompt: "Extract contact information from this email",
outputSchema: z.object({
name: z.string(),
email: z.string().email(),
phone: z.string().optional()
}),
agentInstance: agentData,
statistics: {
label: "extractor",
trigger: "api"
}
});
console.log(data.name); // Type-safe access
console.log(data.email);
Use generateSync() for API endpoints, background jobs, or when you need the complete response before proceeding.
generateStream()
Generates a streaming response from the agent for real-time output.
async generateStream({
user,
session,
agentInstance,
message,
previousMessages,
currentTools,
approvedTools,
allExuluTools,
toolConfigs,
providerapikey,
contexts,
rerankers,
exuluConfig,
instructions,
req
}: GenerateStreamOptions): Promise<{
stream: ReturnType<typeof streamText>;
originalMessages: UIMessage[];
previousMessages: UIMessage[];
}>
The new user message to process
Session ID to load and continue conversation history
User object for access control
Agent database record with configuration
Previous messages to include in context
Tools available to the agent
Tool IDs that have been pre-approved for execution
Complete list of all tools
Tool configuration overrides
AI SDK stream object with text chunks and tool calls
All messages including the new one
Messages from before this request
// Stream a response
const { stream, originalMessages } = await agent.generateStream({
message: {
id: "msg-123",
role: "user",
parts: [{ type: "text", text: "Tell me about your services" }]
},
session: sessionId,
user: currentUser,
agentInstance: agentData,
currentTools: tools,
contexts: contexts,
exuluConfig: config
});
// Consume the stream
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}
// Or use with Express
app.post("/chat", async (req, res) => {
const { stream } = await agent.generateStream({
message: req.body.message,
session: req.body.session,
user: req.user,
agentInstance: agentData,
currentTools: tools
});
return stream.toDataStreamResponse();
});
Use generateStream() for interactive chat applications where you want to display responses progressively.
Exports the agent as a tool that other agents can call.
async tool(
instance: string,
agents: ExuluAgent[],
contexts: ExuluContext[],
rerankers: ExuluReranker[]
): Promise<ExuluTool | null>
Agent ID to load from the database
Array of all available agents
Array of all available contexts
Array of all available rerankers
return
Promise<ExuluTool | null>
Tool instance that wraps the agent, or null if agent not found
// Create specialist agent
const sqlAgent = new ExuluAgent({
id: "sql_specialist",
name: "SQL Specialist",
type: "agent",
description: "Expert at writing SQL queries",
provider: "openai",
config: {
name: "gpt-4o",
model: { /* ... */ },
instructions: "You are an expert SQL developer."
},
capabilities: { text: true, images: [], files: [], audio: [], video: [] }
});
// Export as tool
const sqlTool = await sqlAgent.tool(
"sql_specialist",
[sqlAgent],
contexts,
rerankers
);
// Main agent can use it
const mainAgent = new ExuluAgent({
id: "assistant",
name: "Assistant",
// ... config
});
const response = await mainAgent.generateSync({
prompt: "Write a query to find top customers",
currentTools: [sqlTool], // Delegates to SQL specialist
// ... other params
});
Use agent-as-tool for multi-agent workflows where specialized agents handle specific tasks.
Properties
console.log(agent.id); // "customer_support_agent"
Human-readable agent name
console.log(agent.name); // "Customer Support Agent"
provider
console.log(agent.provider); // "openai"
providerName
Computed provider name (empty string if no model configured)
console.log(agent.providerName); // "openai"
modelName
Computed model name from config
console.log(agent.modelName); // "gpt-4o"
description
console.log(agent.description); // "Handles customer support inquiries"
console.log(agent.type); // "agent"
URL-friendly slug for the agent
console.log(agent.slug); // "/agents/customer-support-agent/run"
capabilities
console.log(agent.capabilities);
// {
// text: true,
// images: [".png", ".jpg"],
// files: [".pdf", ".txt"],
// audio: [],
// video: []
// }
config
ExuluAgentConfig | undefined
Agent configuration including model and instructions
console.log(agent.config?.name); // "gpt-4o"
console.log(agent.config?.instructions); // "You are a helpful assistant..."
const languageModel = agent.model?.create({ apiKey: "..." });
maxContextLength
Maximum context window size in tokens
console.log(agent.maxContextLength); // 128000
workflows
workflows
WorkflowConfig | undefined
Workflow configuration
console.log(agent.workflows?.enabled); // true
queue
ExuluQueueConfig | undefined
Queue configuration
console.log(agent.queue?.name); // "agent_tasks"
rateLimit
rateLimit
RateLimiterRule | undefined
Rate limiting configuration
console.log(agent.rateLimit?.points); // 100
Usage examples
Basic text generation
import { ExuluAgent } from "@exulu/backend";
import { createOpenAI } from "@ai-sdk/openai";
const agent = new ExuluAgent({
id: "assistant",
name: "Assistant",
type: "agent",
description: "General AI assistant",
provider: "openai",
config: {
name: "gpt-4o",
model: {
create: ({ apiKey }) => createOpenAI({ apiKey })("gpt-4o")
},
instructions: "You are a helpful assistant."
},
capabilities: {
text: true,
images: [],
files: [],
audio: [],
video: []
}
});
const response = await agent.generateSync({
prompt: "Explain quantum computing in simple terms",
agentInstance: await loadAgent("assistant"),
statistics: { label: "assistant", trigger: "api" }
});
console.log(response);
Streaming chat
const { stream } = await agent.generateStream({
message: {
id: "msg-123",
role: "user",
parts: [{ type: "text", text: "Write a poem about AI" }]
},
session: "session-abc",
user: currentUser,
agentInstance: agentData,
currentTools: []
});
// Stream to console
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}
import { ExuluTool } from "@exulu/backend";
import { z } from "zod";
// Define a tool
const weatherTool = new ExuluTool({
id: "weather",
name: "get_weather",
description: "Gets weather for a location",
type: "function",
inputSchema: z.object({
location: z.string()
}),
config: [],
execute: async ({ location }) => {
const weather = await fetchWeather(location);
return { result: JSON.stringify(weather) };
}
});
// Use with agent
const response = await agent.generateSync({
prompt: "What's the weather in Paris?",
agentInstance: agentData,
currentTools: [weatherTool],
statistics: { label: "assistant", trigger: "api" }
});
Structured output
import { z } from "zod";
const ContactSchema = z.object({
name: z.string(),
email: z.string().email(),
phone: z.string().optional(),
company: z.string().optional(),
role: z.string().optional()
});
const contacts = await agent.generateSync({
prompt: `Extract all contact information from this email:
Hi, I'm John Smith from Acme Corp. You can reach me at
john@acme.com or call me at 555-1234. I'm the CTO.`,
outputSchema: ContactSchema,
agentInstance: agentData,
statistics: { label: "extractor", trigger: "api" }
});
console.log(contacts.name); // "John Smith"
console.log(contacts.email); // "john@acme.com"
console.log(contacts.company); // "Acme Corp"
console.log(contacts.role); // "CTO"
With conversation history
// First message
const { stream: stream1 } = await agent.generateStream({
message: {
id: "msg-1",
role: "user",
parts: [{ type: "text", text: "My name is Alice" }]
},
session: "session-123",
user: currentUser,
agentInstance: agentData,
currentTools: []
});
await stream1.toTextStreamResponse(); // Wait for completion
// Second message - agent remembers context
const { stream: stream2 } = await agent.generateStream({
message: {
id: "msg-2",
role: "user",
parts: [{ type: "text", text: "What's my name?" }]
},
session: "session-123", // Same session
user: currentUser,
agentInstance: agentData,
currentTools: []
});
// Agent responds: "Your name is Alice."
With memory
// Configure agent with memory
const agent = new ExuluAgent({
id: "memory_agent",
name: "Agent with Memory",
type: "agent",
description: "Agent that remembers past interactions",
provider: "openai",
config: {
name: "gpt-4o",
model: { /* ... */ },
instructions: "You are an assistant with memory.",
memory: "agent_memory_context" // Context ID
},
capabilities: { text: true, images: [], files: [], audio: [], video: [] }
});
// Agent automatically searches memory before responding
const response = await agent.generateSync({
prompt: "What did we discuss about the project last week?",
agentInstance: agentData,
contexts: [memoryContext], // Include memory context
statistics: { label: "memory_agent", trigger: "api" }
});
// Agent can also create new memories via the auto-generated tool
Multi-agent workflow
// Create specialist agents
const researchAgent = new ExuluAgent({
id: "researcher",
name: "Research Specialist",
type: "agent",
description: "Conducts research and gathers information",
provider: "openai",
config: {
name: "gpt-4o",
model: { /* ... */ },
instructions: "You are a research specialist. Gather comprehensive information."
},
capabilities: { text: true, images: [], files: [], audio: [], video: [] }
});
const writerAgent = new ExuluAgent({
id: "writer",
name: "Content Writer",
type: "agent",
description: "Writes content based on research",
provider: "anthropic",
config: {
name: "claude-opus-4",
model: { /* ... */ },
instructions: "You are a skilled writer. Create engaging, well-structured content."
},
capabilities: { text: true, images: [], files: [], audio: [], video: [] }
});
// Coordinator agent that delegates
const coordinatorAgent = new ExuluAgent({
id: "coordinator",
name: "Coordinator",
type: "agent",
description: "Coordinates workflow between specialists",
provider: "openai",
config: {
name: "gpt-4o",
model: { /* ... */ },
instructions: "You coordinate work between specialists."
},
capabilities: { text: true, images: [], files: [], audio: [], video: [] }
});
// Export specialists as tools
const researchTool = await researchAgent.tool("researcher", [researchAgent], [], []);
const writerTool = await writerAgent.tool("writer", [writerAgent], [], []);
// Coordinator uses them
const article = await coordinatorAgent.generateSync({
prompt: "Create an article about quantum computing",
currentTools: [researchTool, writerTool],
agentInstance: await loadAgent("coordinator"),
statistics: { label: "coordinator", trigger: "api" }
});
Processing files
const documentAgent = new ExuluAgent({
id: "doc_processor",
name: "Document Processor",
type: "agent",
description: "Processes and analyzes documents",
provider: "openai",
config: {
name: "gpt-4o",
model: { /* ... */ },
instructions: "Analyze documents and extract key information."
},
capabilities: {
text: true,
images: [],
files: [".pdf", ".docx", ".txt"],
audio: [],
video: []
}
});
// Files are automatically converted to text
const { stream } = await documentAgent.generateStream({
message: {
id: "msg-1",
role: "user",
parts: [
{ type: "text", text: "Summarize this document" },
{
type: "file",
mediaType: "application/pdf",
url: "https://example.com/document.pdf",
filename: "document.pdf"
}
]
},
session: sessionId,
user: currentUser,
agentInstance: agentData,
currentTools: []
});
Type definitions
// Agent constructor parameters
interface ExuluAgentParams {
id: string;
name: string;
type: "agent";
description: string;
config?: ExuluAgentConfig;
queue?: ExuluQueueConfig;
maxContextLength?: number;
authenticationInformation?: string;
provider: string;
workflows?: {
enabled: boolean;
queue?: Promise<ExuluQueueConfig>;
};
capabilities?: {
text: boolean;
images: imageTypes[];
files: fileTypes[];
audio: audioTypes[];
video: videoTypes[];
};
rateLimit?: RateLimiterRule;
}
// Agent configuration
interface ExuluAgentConfig {
name: string;
model?: {
create: ({ apiKey }: { apiKey?: string }) => LanguageModel;
};
instructions?: string;
memory?: string;
}
// Capabilities types
type imageTypes = '.png' | '.jpg' | '.jpeg' | '.gif' | '.webp';
type fileTypes = '.pdf' | '.docx' | '.xlsx' | '.xls' | '.csv' |
'.pptx' | '.ppt' | '.txt' | '.md' | '.json';
type audioTypes = '.mp3' | '.wav' | '.m4a' | '.mp4' | '.mpeg';
type videoTypes = '.mp4' | '.m4a' | '.mp3' | '.mpeg' | '.wav';
Best practices
Test with different prompts: Agent behavior can vary significantly with different phrasings. Test edge cases and refine instructions.
Monitor token usage: Track input/output tokens to optimize costs and prevent context window overflow.
Validate structured outputs: Even with schemas, validate critical data before using it in production systems.
Tool selection: Provide only necessary tools. Too many tools can confuse the agent and increase latency.
Next steps