// projects / building-a-multi-provider-ai-weather-agent-in-node-js
Building a Multi-Provider AI Weather Agent in Node.js
How I built a minimal AI agent with a tool-calling loop that runs on Anthropic Claude, OpenAI, Gemini, DeepSeek, and Kimi — all sharing one weather tool, with provider switching from the CLI.
Building a Multi-Provider AI Weather Agent in Node.js
Most AI agent tutorials lock you into a single provider. I wanted to understand what an agent's tool-calling loop actually looks like under the hood — and how much of it changes (or doesn't) when you swap the model behind it. So I built weather-ai-agent: a small Node.js project where the same weather-lookup agent runs on five different LLM providers.
Repo: github.com/marsab14/weather-ai-agent
What it does
You ask a natural-language question like "What's the weather like in Pune right now?" and the agent:
Sends your message to the LLM along with a
get_weathertool definitionThe model decides it needs the tool and returns a structured tool call
The agent executes the tool locally and feeds the result back to the model
The model composes a final natural-language answer
The loop keeps running until the model stops asking for tools — that's the whole "agent" pattern in its simplest form.
Five providers, one agent
The project supports Anthropic (Claude), OpenAI (GPT), Google Gemini, DeepSeek, and Kimi (Moonshot). You pick the provider with a CLI flag or an environment variable:
bash
node index.js # defaults to Anthropic
node index.js --provider openai
node index.js --provider deepseek
node index.js --provider kimi
AI_PROVIDER=gemini node index.jsA nice trick here: DeepSeek and Kimi both expose OpenAI-compatible APIs, so they reuse the OpenAI adapter with just a different baseURL and API key. That means five providers are covered by only three adapters.
How it's structured
The codebase is deliberately small and readable:
index.js— entry point; picks a provider and runs the agent with a sample questioncli.js— parses the--providerflag /AI_PROVIDERenv varproviders.js— one config object per provider (model name, SDK client factory, API kind)tools.js— a single source of truth for theget_weathertool, exported in each provider's native schema format (Anthropicinput_schema, OpenAIfunction, GeminifunctionDeclarations)agent.js— a thin router that dispatches to the right adapteradapters/— the actual tool-calling loops for Anthropic, OpenAI-compatible, and Gemini APIs
The most interesting file is tools.js. Every provider wants tool definitions in a slightly different shape, but the underlying schema — name, description, JSON Schema parameters — is identical. Defining it once and re-exporting it per provider keeps things DRY and makes the API differences obvious at a glance.
The tool-calling loop
Here's the core of the Anthropic adapter — the other adapters follow the same rhythm with provider-specific message shapes:
javascript
while (true) {
const response = await client.messages.create({
model: config.model,
max_tokens: 1024,
system: SYSTEM_PROMPT,
tools: ANTHROPIC_TOOLS,
messages,
});
messages.push({ role: "assistant", content: response.content });
if (response.stop_reason !== "tool_use") {
return response.content
.filter((b) => b.type === "text")
.map((b) => b.text)
.join("");
}
// Execute each requested tool and send the results back
const toolResults = [];
for (const block of response.content) {
if (block.type === "tool_use") {
toolResults.push({
type: "tool_result",
tool_use_id: block.id,
content: runTool(block.name, block.input),
});
}
}
messages.push({ role: "user", content: toolResults });
}That's it. No framework, no LangChain — just the raw request/response cycle, which makes it a great way to actually understand what agent frameworks abstract away.
A note on the weather tool
The get_weather implementation is currently a mock — it returns a fixed sunny-and-31°C payload for any city. That's intentional for a learning project: the focus is the agent loop and multi-provider plumbing, not the weather API. Swapping in a real API like Open-Meteo or OpenWeatherMap is a one-function change, and it's the obvious next step.
Getting started
bash
git clone https://github.com/marsab14/weather-ai-agent
cd weather-ai-agent
npm install
cp .env.example .env # add your API keys
node index.js --provider anthropicYou only need the API key for whichever provider you want to run.
Takeaways
The agent loop is the same everywhere: call model → check for tool requests → run tools → feed results back → repeat
Provider differences live almost entirely in message/tool schemas, not in the logic
OpenAI-compatible APIs (DeepSeek, Kimi) make multi-provider support surprisingly cheap
Building this without a framework is the fastest way to demystify how agents work
Check out the full source on GitHub