Examples/Wrap a Client: OpenAI Chatbot with Budget Controls

Wrap a Client: OpenAI Chatbot with Budget Controls

beginnerwrap·openai·2 min read

Wrap a Client: OpenAI Chatbot with Budget Controls

ks.wrap() rewrites a single SDK client's baseURL to point at the Keystore vault. Unlike interceptAll(), it targets one client at a time — useful when you want fine-grained control over which clients are proxied.

What you'll build

A multi-turn chatbot powered by OpenAI, with all requests routed through Keystore. You'll configure a monthly budget in the dashboard and see how Keystore enforces it.

Prerequisites

  • A Keystore account with an agent token
  • An OpenAI key in your vault
  • Node.js 18+

Setup

1

Install dependencies

bash
1
npm install @keystore/sdk openai readline
2

Wrap the OpenAI client

typescript
1
2
3
4
5
6
7
import Keystore from "@keystore/sdk";
import OpenAI from "openai";

const ks = new Keystore({ agentToken: process.env.KS_TOKEN! });

// wrap() rewrites the client's baseURL to vault.keystore.com
const openai = ks.wrap(new OpenAI());

After wrap(), openai.baseURL points to the Keystore vault. The apiKey field is replaced with your agent token. Everything else works identically.

3

Build the chat loop

typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import * as readline from "readline";

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

const messages: OpenAI.Chat.ChatCompletionMessageParam[] = [
  { role: "system", content: "You are a helpful assistant." },
];

function ask(prompt: string): Promise<string> {
  return new Promise((resolve) => rl.question(prompt, resolve));
}

async function chat() {
  console.log("Chatbot ready. Type 'exit' to quit.\n");

  while (true) {
    const input = await ask("You: ");
    if (input.toLowerCase() === "exit") break;

    messages.push({ role: "user", content: input });

    const response = await openai.chat.completions.create({
      model: "gpt-4o",
      messages,
    });

    const reply = response.choices[0].message.content!;
    messages.push({ role: "assistant", content: reply });
    console.log(`\nAssistant: ${reply}\n`);
  }

  rl.close();
}

chat();
4

Configure budget in the dashboard

In the Keystore dashboard:

  1. Navigate to your agent
  2. Set a monthly budget (e.g., $10.00)
  3. Optionally set a rate limit (e.g., 100 requests/minute)

When the budget is exceeded, the vault returns a 429 status code. Your agent should handle this gracefully.

Handling budget limits

typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
try {
  const response = await openai.chat.completions.create({
    model: "gpt-4o",
    messages,
  });
  // ... handle response
} catch (err: any) {
  if (err.status === 429) {
    console.log("Budget or rate limit reached. Try again later.");
  } else {
    throw err;
  }
}

wrap() vs interceptAll()

Featurewrap()interceptAll()
ScopeSingle clientAll fetch calls
SetupPer-clientGlobal, one-time
CleanupNone neededCall ks.restore()
Best forTargeted proxyingQuick prototyping
✦

Use wrap() when you want some clients proxied and others direct. Use interceptAll() when every provider call should go through the vault.

Next steps