Getting Started with Agents
Build an AI agent that can call tools, track its own progress, and respond with results. This guide walks you through a complete agent from scratch.
1. Install dependencies
npm install @allem-sdk/agents @allem-sdk/ai ai @ai-sdk/react @ai-sdk/google zod
You can swap @ai-sdk/google for @ai-sdk/anthropic or @ai-sdk/openai.
2. Set your API key
Create a .env.local file in your project root:
GOOGLE_GENERATIVE_AI_API_KEY=your-api-key-here # Or for other providers: # ANTHROPIC_API_KEY=your-api-key-here # OPENAI_API_KEY=your-api-key-here
3. Define your tools (server)
Tools are functions your agent can call. Each tool has a description (so the AI knows when to use it), a zod schema (for typed parameters), and an execute function.
// lib/tools.ts
import { createAllemTool } from "@allem-sdk/agents";
import { z } from "zod";
export const weatherTool = createAllemTool({
description: "Get the current weather for a city",
parameters: z.object({
city: z.string().describe("City name, e.g. 'San Francisco'"),
}),
execute: async ({ city }) => {
// Replace with a real API call
const data = await fetch(
`https://api.weatherapi.com/v1/current.json?q=${city}`
).then((r) => r.json());
return {
city,
temperature: data.current.temp_f,
condition: data.current.condition.text,
};
},
});
export const calculatorTool = createAllemTool({
description: "Perform a math calculation",
parameters: z.object({
expression: z.string().describe("Math expression, e.g. '2 + 2'"),
}),
execute: async ({ expression }) => {
const result = Function(`"use strict"; return (${expression})`)();
return { expression, result };
},
});4. Create the API route (server)
The agent handler receives messages from the client, passes them to the AI model with your tools, and streams the response back.
// app/api/agent/route.ts
import { createAllemAgentHandler } from "@allem-sdk/agents";
import { google } from "@ai-sdk/google";
import { weatherTool, calculatorTool } from "@/lib/tools";
export const POST = createAllemAgentHandler({
providers: {
google: (model) => google(model ?? "gemini-2.0-flash"),
},
tools: {
weather: weatherTool,
calculator: calculatorTool,
},
systemPrompt: "You are a helpful assistant. Use the available tools when needed to answer questions accurately.",
});5. Build the agent UI (client)
The useAllemAgent hook gives you everything you need: messages, agent status, tool call tracking, and step history.
// app/page.tsx
"use client";
import { useState } from "react";
import { AllemAIProvider } from "@allem-sdk/ai";
import { useAllemAgent } from "@allem-sdk/agents";
export default function Home() {
return (
<AllemAIProvider api="/api/agent" provider="google">
<Agent />
</AllemAIProvider>
);
}
function Agent() {
const [input, setInput] = useState("");
const {
messages,
sendMessage,
agentStatus,
steps,
currentToolCalls,
isAgentRunning,
} = useAllemAgent();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!input.trim() || isAgentRunning) return;
const text = input;
setInput("");
await sendMessage({ text });
};
return (
<div style={{ maxWidth: 600, margin: "0 auto", padding: 24 }}>
<h1>AI Agent</h1>
{/* Status indicator */}
<AgentStatusBadge status={agentStatus} toolCalls={currentToolCalls} />
{/* Messages */}
<div style={{ marginTop: 16 }}>
{messages.map((m) => (
<div
key={m.id}
style={{
padding: 12,
marginBottom: 8,
borderRadius: 8,
background: m.role === "user" ? "#e8f0fe" : "#f8f9fa",
}}
>
<strong>{m.role === "user" ? "You" : "Agent"}</strong>
<div>
{m.parts
?.filter((p) => p.type === "text")
.map((p, i) => <p key={i}>{p.text}</p>)}
</div>
</div>
))}
</div>
{/* Step history */}
{steps.length > 0 && (
<div style={{ marginTop: 16, fontSize: 13, color: "#666" }}>
<strong>Steps taken: {steps.length}</strong>
<ul>
{steps.map((step) => (
<li key={step.stepIndex}>
Step {step.stepIndex + 1}:{" "}
{step.toolCalls.map((tc) => tc.toolName).join(", ")}
</li>
))}
</ul>
</div>
)}
{/* Input */}
<form onSubmit={handleSubmit} style={{ marginTop: 16, display: "flex", gap: 8 }}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Ask something..."
disabled={isAgentRunning}
style={{ flex: 1, padding: 8, borderRadius: 6, border: "1px solid #ddd" }}
/>
<button
type="submit"
disabled={isAgentRunning}
style={{ padding: "8px 16px", borderRadius: 6, background: "#4f46e5", color: "#fff", border: "none" }}
>
Send
</button>
</form>
</div>
);
}6. Show agent status
The agentStatus property tracks the agent lifecycle. Use it to show contextual feedback to the user.
| Status | When | What to show |
|---|---|---|
| idle | No conversation yet, or agent finished | Input field, ready state |
| thinking | AI is generating a response | Loading spinner, "Thinking..." |
| calling-tool | AI decided to call a tool | Tool name, "Looking up weather..." |
| done | Agent finished its response | Final answer, step summary |
function AgentStatusBadge({
status,
toolCalls,
}: {
status: "idle" | "thinking" | "calling-tool" | "done";
toolCalls: { toolName: string }[];
}) {
if (status === "idle") return null;
const labels = {
thinking: "Thinking...",
"calling-tool": `Using tool: ${toolCalls[0]?.toolName ?? "..."}`,
done: "Done",
};
return (
<div style={{
padding: "6px 12px",
borderRadius: 6,
fontSize: 13,
background: status === "calling-tool" ? "#fef3c7" : "#e0e7ff",
color: status === "calling-tool" ? "#92400e" : "#3730a3",
}}>
{labels[status]}
</div>
);
}7. Try it out
Start your dev server and try these prompts:
- "What's the weather in Tokyo?" → agent calls the weather tool, returns the result
- "What's 1847 * 293?" → agent calls the calculator tool
- "What's the weather in Paris and London?" → agent may call the tool twice in separate steps
- "Tell me a joke" → agent responds directly without calling any tools
What's happening under the hood
- User sends a message via
sendMessage() - The message is sent to your
/api/agentroute createAllemAgentHandlerpasses it to the AI model with your tools- The AI model decides whether to respond directly or call a tool
- If it calls a tool, the
executefunction runs and the result is sent back to the model - The model generates a final response incorporating the tool result
- On the client,
useAllemAgenttracks each step:thinking → calling-tool → done
Next steps
- Add more tools with createAllemTool
- Display tool metadata in your UI with AgentProvider
- Customize the API endpoint and headers via useAllemAgent options
- Use a different provider by swapping
@ai-sdk/googlefor@ai-sdk/anthropicor@ai-sdk/openai