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