AI Agent with ToolsAI Workflow
An autonomous AI agent that can search the web, query a database, and send Slack messages — all through LLM function calling. Define tools once, let the model decide when to use them.
Prerequisites
Environment variables
OPENAI_KEYSLACK_BOT_TOKENInstall
npx radzor@latest recipe add ai-agentAI Prompt
“Run `npx radzor@latest add function-calling web-scraper embeddings-store slack-bot` to install 4 Radzor components. Then read components/radzor/function-calling/radzor.manifest.json, components/radzor/web-scraper/radzor.manifest.json, components/radzor/embeddings-store/radzor.manifest.json, components/radzor/slack-bot/radzor.manifest.json and each component's llm/integration.md. Wire them together to an autonomous AI agent that can search the web, query a database, and send Slack messages — all through LLM function calling. Define tools once, let the model decide when to use them. Use the manifest's inputs (check envVar for required environment variables), outputs (check fields for object shapes), composability (check mapField for field extraction), and actions — don't invent custom interfaces.”
Paste this into Claude Code, Cursor, Windsurf, or any AI coding agent.
Pipeline
FunctionCalling
LLM decides which tools to call
WebScraper
Fetches web pages on demand
EmbeddingsStore
Searches internal knowledge base
SlackBot
Posts messages to Slack
Scaffolded Code
// npx radzor@latest add function-calling web-scraper embeddings-store slack-bot
import { FunctionCalling } from "./components/radzor/function-calling"
import { WebScraper } from "./components/radzor/web-scraper"
import { EmbeddingsStore } from "./components/radzor/embeddings-store"
import { SlackBot } from "./components/radzor/slack-bot"
const agent = new FunctionCalling({ provider: "openai", apiKey: process.env.OPENAI_KEY!, model: "gpt-4o", maxIterations: 5, systemPrompt: "You are a helpful assistant with access to tools." })
const scraper = new WebScraper({ timeout: 10000 })
const kb = new EmbeddingsStore({ provider: "openai", apiKey: process.env.OPENAI_KEY! })
const slack = new SlackBot({ botToken: process.env.SLACK_BOT_TOKEN! })
// Define tools the agent can use
agent.define([
{
name: "search_web",
description: "Fetch and return the text content of a web page",
schema: { url: { type: "string", description: "URL to fetch" } },
handler: async (input: { url: string }) => scraper.fetchHtml(input.url),
},
{
name: "search_knowledge_base",
description: "Search the internal knowledge base by semantic similarity",
schema: { query: { type: "string" }, topK: { type: "number" } },
handler: async (input: { query: string; topK: number }) => kb.search(input.query, input.topK),
},
{
name: "send_slack_message",
description: "Send a message to a Slack channel",
schema: { channel: { type: "string" }, text: { type: "string" } },
handler: async (input: { channel: string; text: string }) => slack.sendMessage(input.channel, input.text),
},
])
// Run the agent
const { response, toolCallLog } = await agent.run("Find our refund policy and post a summary in #support")
console.log(`Agent used ${toolCallLog.length} tools: ${toolCallLog.map(t => t.tool).join(", ")}`)Components used
LLM tip
Pass all 4 radzor.manifest.json files to your agent at once. It will read the outputs of each step and match them against the inputs of the next — wiring the full pipeline without any extra instructions.