Examples/Database Access: AI Agent with Neon Postgres

Database Access: AI Agent with Neon Postgres

intermediatewrapProvider·openaineon·3 min read

Database Access: AI Agent with Neon Postgres

Keystore doesn't just manage LLM keys — it handles database credentials too. wrapNeon() routes your Neon Postgres connection through the vault, so your agent never sees the connection string.

What you'll build

An agent that queries a Neon Postgres database, summarizes the results with GPT-4o, and writes a summary back to the database. The agent holds only a ks_ token — never a database password or OpenAI key.

Prerequisites

  • A Keystore account with an agent token
  • Neon Postgres and OpenAI keys in your vault
  • Node.js 18+

Setup

1

Install dependencies

bash
1
npm install @keystore/sdk openai @neondatabase/serverless
2

Initialize Keystore with both providers

typescript
1
2
3
4
5
6
7
8
9
10
11
12
import Keystore from "@keystore/sdk";
import { wrapNeon } from "@keystore/sdk/wrap/neon";
import OpenAI from "openai";
import { neon } from "@neondatabase/serverless";

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

// Route all fetch-based providers (OpenAI) through the vault
ks.interceptAll();

// Wrap the Neon client separately — it needs a connection string
const sql = wrapNeon(neon, ks);
i

Neon uses a connection string rather than HTTP headers, so it needs the dedicated wrapNeon() wrapper instead of interceptAll().

3

Query the database

typescript
1
2
3
4
5
6
7
8
9
10
// Query users — the real DATABASE_URL is resolved from the vault
const users = await sql`
  SELECT id, name, email, signup_date
  FROM users
  WHERE active = true
  ORDER BY signup_date DESC
  LIMIT 50
`;

console.log(`Found ${users.length} active users`);
4

Summarize with GPT-4o

typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const openai = new OpenAI();

const summary = await openai.chat.completions.create({
  model: "gpt-4o",
  messages: [
    {
      role: "system",
      content: "You are a data analyst. Summarize user activity concisely.",
    },
    {
      role: "user",
      content: `Summarize these active users:\n${JSON.stringify(users, null, 2)}`,
    },
  ],
});

const summaryText = summary.choices[0].message.content!;
console.log("Summary:", summaryText);
5

Write results back

typescript
1
2
3
4
5
6
7
8
9
10
// Store the AI-generated summary back in the database
await sql`
  INSERT INTO reports (type, content, generated_at)
  VALUES ('user-summary', ${summaryText}, NOW())
`;

console.log("Report saved to database");

// Clean up
ks.restore();

Full example

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
import Keystore from "@keystore/sdk";
import { wrapNeon } from "@keystore/sdk/wrap/neon";
import OpenAI from "openai";
import { neon } from "@neondatabase/serverless";

async function main() {
  const ks = new Keystore({ agentToken: process.env.KS_TOKEN! });
  ks.interceptAll();
  const sql = wrapNeon(neon, ks);

  // Read
  const users = await sql`SELECT id, name, email FROM users WHERE active = true LIMIT 50`;

  // Reason
  const openai = new OpenAI();
  const summary = await openai.chat.completions.create({
    model: "gpt-4o",
    messages: [
      { role: "system", content: "Summarize this user data concisely." },
      { role: "user", content: JSON.stringify(users) },
    ],
  });

  // Write
  const text = summary.choices[0].message.content!;
  await sql`INSERT INTO reports (type, content, generated_at) VALUES ('user-summary', ${text}, NOW())`;

  console.log("Done:", text);
  ks.restore();
}

main();

Security model

With this setup, your agent code contains:

  • A ks_ token — scoped to specific providers and budgets
  • No database password — resolved from the vault at query time
  • No OpenAI key — resolved from the vault at request time

If the agent token leaks, you revoke it in the dashboard. No database passwords or API keys are compromised.

Next steps