mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 04:03:31 +00:00
feat: add session persistence examples and SQLite driver
This commit is contained in:
parent
64d1324628
commit
3c2a9cbbbb
14 changed files with 524 additions and 11 deletions
18
examples/persist-memory/package.json
Normal file
18
examples/persist-memory/package.json
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "@sandbox-agent/example-persist-memory",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "tsx src/index.ts",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sandbox-agent/example-shared": "workspace:*",
|
||||
"sandbox-agent": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "latest",
|
||||
"tsx": "latest",
|
||||
"typescript": "latest"
|
||||
}
|
||||
}
|
||||
37
examples/persist-memory/src/index.ts
Normal file
37
examples/persist-memory/src/index.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { SandboxAgent, InMemorySessionPersistDriver } from "sandbox-agent";
|
||||
import { startDockerSandbox } from "@sandbox-agent/example-shared/docker";
|
||||
import { detectAgent } from "@sandbox-agent/example-shared";
|
||||
|
||||
const persist = new InMemorySessionPersistDriver();
|
||||
|
||||
console.log("Starting sandbox...");
|
||||
const sandbox = await startDockerSandbox({
|
||||
port: 3000,
|
||||
setupCommands: [
|
||||
"sandbox-agent install-agent claude",
|
||||
"sandbox-agent install-agent codex",
|
||||
],
|
||||
});
|
||||
|
||||
const sdk = await SandboxAgent.connect({ baseUrl: sandbox.baseUrl, persist });
|
||||
|
||||
const session = await sdk.createSession({ agent: detectAgent() });
|
||||
console.log(`Created session ${session.id}`);
|
||||
|
||||
await session.prompt([{ type: "text", text: "Say hello in one sentence." }]);
|
||||
console.log("Prompt complete.");
|
||||
|
||||
const sessions = await sdk.listSessions();
|
||||
console.log(`\nSessions (${sessions.items.length}):`);
|
||||
for (const s of sessions.items) {
|
||||
console.log(` ${s.id} agent=${s.agent}`);
|
||||
}
|
||||
|
||||
const events = await sdk.getEvents({ sessionId: session.id });
|
||||
console.log(`\nSession history (${events.items.length} events):`);
|
||||
for (const e of events.items) {
|
||||
console.log(` [${e.eventIndex}] ${e.sender}: ${JSON.stringify(e.payload).slice(0, 120)}`);
|
||||
}
|
||||
|
||||
await sdk.dispose();
|
||||
await sandbox.cleanup();
|
||||
13
examples/persist-memory/tsconfig.json
Normal file
13
examples/persist-memory/tsconfig.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
21
examples/persist-postgres/package.json
Normal file
21
examples/persist-postgres/package.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "@sandbox-agent/example-persist-postgres",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "tsx src/index.ts",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sandbox-agent/example-shared": "workspace:*",
|
||||
"@sandbox-agent/persist-postgres": "workspace:*",
|
||||
"pg": "latest",
|
||||
"sandbox-agent": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "latest",
|
||||
"@types/pg": "latest",
|
||||
"tsx": "latest",
|
||||
"typescript": "latest"
|
||||
}
|
||||
}
|
||||
76
examples/persist-postgres/src/index.ts
Normal file
76
examples/persist-postgres/src/index.ts
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import { execFileSync } from "node:child_process";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { Client } from "pg";
|
||||
import { setTimeout as delay } from "node:timers/promises";
|
||||
import { SandboxAgent } from "sandbox-agent";
|
||||
import { PostgresSessionPersistDriver } from "@sandbox-agent/persist-postgres";
|
||||
import { startDockerSandbox } from "@sandbox-agent/example-shared/docker";
|
||||
import { detectAgent } from "@sandbox-agent/example-shared";
|
||||
|
||||
// --- Postgres setup (Docker or DATABASE_URL) ---
|
||||
|
||||
let containerId: string | undefined;
|
||||
let connectionString: string;
|
||||
|
||||
if (process.env.DATABASE_URL) {
|
||||
connectionString = process.env.DATABASE_URL;
|
||||
} else {
|
||||
const name = `persist-example-${randomUUID().slice(0, 8)}`;
|
||||
containerId = execFileSync("docker", [
|
||||
"run", "-d", "--rm", "--name", name,
|
||||
"-e", "POSTGRES_USER=postgres", "-e", "POSTGRES_PASSWORD=postgres", "-e", "POSTGRES_DB=sandbox",
|
||||
"-p", "127.0.0.1::5432", "postgres:16-alpine",
|
||||
], { encoding: "utf8" }).trim();
|
||||
const port = execFileSync("docker", ["port", containerId, "5432/tcp"], { encoding: "utf8" })
|
||||
.trim().split("\n")[0]?.match(/:(\d+)$/)?.[1];
|
||||
connectionString = `postgres://postgres:postgres@127.0.0.1:${port}/sandbox`;
|
||||
console.log(`Postgres on port ${port}`);
|
||||
|
||||
const deadline = Date.now() + 30_000;
|
||||
while (Date.now() < deadline) {
|
||||
const c = new Client({ connectionString });
|
||||
try { await c.connect(); await c.query("SELECT 1"); await c.end(); break; }
|
||||
catch { try { await c.end(); } catch {} await delay(250); }
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const persist = new PostgresSessionPersistDriver({ connectionString });
|
||||
|
||||
console.log("Starting sandbox...");
|
||||
const sandbox = await startDockerSandbox({
|
||||
port: 3000,
|
||||
setupCommands: [
|
||||
"sandbox-agent install-agent claude",
|
||||
"sandbox-agent install-agent codex",
|
||||
],
|
||||
});
|
||||
|
||||
const sdk = await SandboxAgent.connect({ baseUrl: sandbox.baseUrl, persist });
|
||||
|
||||
const session = await sdk.createSession({ agent: detectAgent() });
|
||||
console.log(`Created session ${session.id}`);
|
||||
|
||||
await session.prompt([{ type: "text", text: "Say hello in one sentence." }]);
|
||||
console.log("Prompt complete.");
|
||||
|
||||
const sessions = await sdk.listSessions();
|
||||
console.log(`\nSessions (${sessions.items.length}):`);
|
||||
for (const s of sessions.items) {
|
||||
console.log(` ${s.id} agent=${s.agent}`);
|
||||
}
|
||||
|
||||
const events = await sdk.getEvents({ sessionId: session.id });
|
||||
console.log(`\nSession history (${events.items.length} events):`);
|
||||
for (const e of events.items) {
|
||||
console.log(` [${e.eventIndex}] ${e.sender}: ${JSON.stringify(e.payload).slice(0, 120)}`);
|
||||
}
|
||||
|
||||
await persist.close();
|
||||
await sdk.dispose();
|
||||
await sandbox.cleanup();
|
||||
} finally {
|
||||
if (containerId) {
|
||||
try { execFileSync("docker", ["rm", "-f", containerId], { stdio: "ignore" }); } catch {}
|
||||
}
|
||||
}
|
||||
13
examples/persist-postgres/tsconfig.json
Normal file
13
examples/persist-postgres/tsconfig.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
19
examples/persist-sqlite/package.json
Normal file
19
examples/persist-sqlite/package.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "@sandbox-agent/example-persist-sqlite",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "tsx src/index.ts",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sandbox-agent/example-shared": "workspace:*",
|
||||
"@sandbox-agent/persist-sqlite": "workspace:*",
|
||||
"sandbox-agent": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "latest",
|
||||
"tsx": "latest",
|
||||
"typescript": "latest"
|
||||
}
|
||||
}
|
||||
39
examples/persist-sqlite/src/index.ts
Normal file
39
examples/persist-sqlite/src/index.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { SandboxAgent } from "sandbox-agent";
|
||||
import { SQLiteSessionPersistDriver } from "@sandbox-agent/persist-sqlite";
|
||||
import { startDockerSandbox } from "@sandbox-agent/example-shared/docker";
|
||||
import { detectAgent } from "@sandbox-agent/example-shared";
|
||||
|
||||
const persist = new SQLiteSessionPersistDriver({ filename: "./sessions.db" });
|
||||
|
||||
console.log("Starting sandbox...");
|
||||
const sandbox = await startDockerSandbox({
|
||||
port: 3000,
|
||||
setupCommands: [
|
||||
"sandbox-agent install-agent claude",
|
||||
"sandbox-agent install-agent codex",
|
||||
],
|
||||
});
|
||||
|
||||
const sdk = await SandboxAgent.connect({ baseUrl: sandbox.baseUrl, persist });
|
||||
|
||||
const session = await sdk.createSession({ agent: detectAgent() });
|
||||
console.log(`Created session ${session.id}`);
|
||||
|
||||
await session.prompt([{ type: "text", text: "Say hello in one sentence." }]);
|
||||
console.log("Prompt complete.");
|
||||
|
||||
const sessions = await sdk.listSessions();
|
||||
console.log(`\nSessions (${sessions.items.length}):`);
|
||||
for (const s of sessions.items) {
|
||||
console.log(` ${s.id} agent=${s.agent}`);
|
||||
}
|
||||
|
||||
const events = await sdk.getEvents({ sessionId: session.id });
|
||||
console.log(`\nSession history (${events.items.length} events):`);
|
||||
for (const e of events.items) {
|
||||
console.log(` [${e.eventIndex}] ${e.sender}: ${JSON.stringify(e.payload).slice(0, 120)}`);
|
||||
}
|
||||
|
||||
persist.close();
|
||||
await sdk.dispose();
|
||||
await sandbox.cleanup();
|
||||
13
examples/persist-sqlite/tsconfig.json
Normal file
13
examples/persist-sqlite/tsconfig.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue