Decouple the Agent: Why Prompts, Tools, and Models Don't Belong in Your Client | Vivgrid
Log in to Console<br>Decouple the Agent: Why Prompts, Tools, and Models Don't Belong in Your Client<br>A best-practices guide for enterprise AI agents: treat system prompts as runtime config, run tools as Managed Skills, and make models a platform decision — so you can debug faster, ship AI improvements without app releases, and fix production behavior from the console in minutes.<br>Vivgrid Team · June 12, 2026
Here is the agent client most teams ship:
// agent.ts — everything your agent is, compiled into the binary<br>const SYSTEM_PROMPT = `You are a support agent for Acme Corp.<br>Always answer in English. Never discuss pricing...`; // 400 more lines
const MODEL = 'gpt-5.5'; // chosen in a meeting, six months ago
const tools = [<br>{ type: 'function', function: { name: 'lookup_order', /* ... */ } },<br>{ type: 'function', function: { name: 'issue_refund', /* ... */ } },<br>]; // executed locally, with API keys from .env
const res = await openai.chat.completions.create({<br>model: MODEL,<br>messages: [{ role: 'system', content: SYSTEM_PROMPT }, ...history],<br>tools,<br>});
It works. It demos well. And every capitalized constant in that file is a release cycle waiting to happen:
The prompt needs a tweak? Release.
A tool has a bug? Release.
The model gets deprecated, repriced, or outperformed? Release — after someone greps every repo that hardcoded it.
Your agent's interface changes maybe twice a year. Its intelligence needs to change weekly. Coupling them means the slow one sets the pace for both.
The fix is one rule:
The client holds a session, not a brain. System prompts, tools, and models are server-side concerns. The client renders the conversation.
Here is the same agent as a thin client against Vivgrid:
// agent.ts — the whole thing<br>const openai = new OpenAI({<br>baseURL: 'https://api.vivgrid.com/v1',<br>apiKey: process.env.VIVGRID_TOKEN,<br>});
const res = await openai.chat.completions.create({<br>messages: history, // that's it<br>});
Notice what's missing: no model, no tools, no system prompt. They didn't disappear — they moved to where they can change without shipping software. Let's walk through each one.
Best practice #1: Treat the system prompt as runtime config
A system prompt is not source code. It is operational behavior — closer to a feature flag than to a function. It will be edited by people who don't write TypeScript (product, legal, support leads), and it will need to change at the worst possible time.
The 2 a.m. scenario: your agent starts confidently quoting a discount policy that was retired last quarter. With the prompt compiled into the client, the fix is a hotfix release and an app-store review — your agent keeps misquoting policy for days.
With the prompt managed in the Vivgrid Console, the fix is: edit, save. Every conversation that starts after that second uses the corrected prompt. The incident lasts minutes, and the postmortem includes who changed what, when.
The deeper win is iteration. When prompt changes are free, your team actually makes them — tightening tone, patching edge cases, encoding what support learned this week. When every change costs a release, the prompt fossilizes.
Best practice #2: Make the model a platform decision — and enforce it
Hardcoding a model ID feels harmless — it's one string. But that string is a pricing commitment, a latency profile, a compliance surface, and a deprecation timeline, all chosen at compile time and frozen until the next release.
It also shouldn't be every developer's decision. When any engineer can switch the production agent to whatever model they benchmarked last night, your cost and behavior drift one commit at a time. Model selection is a governance decision: run the evals, compare cost and latency on real traffic, then switch — for every agent at once, in the console, with no client change.
A policy is only as good as its enforcement, and enforcement here has two halves:
Clients should not send model. A thin client has no business hardcoding one (look back at the thin client above — it doesn't).
The server should not trust it if they do. The gateway ignores any client-supplied model and replaces it with the value configured for the project.
// even if a stray client sends one…<br>await openai.chat.completions.create({<br>model: 'gpt-4o-mini', // ignored — the console's choice serves the request<br>messages: history,<br>})
Why enforce instead of merely document? Because any honored client value is a bypass. An old install pinning a deprecated model can block your migration. A leaked token that's allowed to pick models can run up your bill on the most expensive one.
Done right, this cuts both ways:
Upgrades : a frontier model ships, your evals confirm it wins, and production is on it the same day — not next quarter when the release train leaves.
Stability : nobody "just tries" a model in production, because the client physically cannot specify one.
Developers lose...