Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dashboard — any provider, any deploy target, no lock-in.
- **Streaming events** — `for await (const event of agent.stream(input))` yields a typed, versioned, JSON-serializable event stream (`text.delta` tokens as they arrive, `tool.start`/`tool.done`, steps, approvals, a final `run.done`) ready to forward over SSE or WebSockets; `await run.result` gives the same result as `send()` ([docs/streaming.md](docs/streaming.md))
=======
- **Sessions** — `agent.session()` keeps a multi-turn conversation (in memory, or persisted with `FileSessionStore`)
- **SQLite store** — `new SqliteStore('./.loushy/agent.db')` from `@loushy/build-ai-agent/sqlite` keeps sessions, checkpoints and approvals in one durable, transactional file (built-in `node:sqlite`, no native dependency) — see [Sessions](docs/sessions.md#stores)
- **Project instructions** — `createAgent({ projectInstructions: true })` appends the nearest `AGENTS.md` / `CLAUDE.md` to the instructions (opt-in)
>>>>>>> origin/main
- **Parallel tool calls** — when the model asks for several tools in one turn they run concurrently (cap it with `toolConcurrency`, or `1` for sequential), and results still reach the transcript in the model's call order
Expand Down
44 changes: 44 additions & 0 deletions docs/sessions.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,50 @@ Session ids must match `^[A-Za-z0-9_-]{1,128}$` (they become file names, so
`../x` and `a/b` are refused with an error that says so). Implement
`SessionStore` yourself to keep transcripts in a database or Redis.

## Stores

Sessions, durable-execution checkpoints and approvals each have a store
interface (`SessionStore`, `CheckpointStore`, `ApprovalStore`). Pick the
implementation by where the process runs:

| Store | Sessions | Checkpoints | Approvals | Use it when |
| --- | --- | --- | --- | --- |
| In memory | `MemorySessionStore` | (supply your own) | (supply your own) | Tests, scripts, one process that never restarts |
| Files | `FileSessionStore(dir)` | `LocalStorageCheckpointStore` | `StorageServiceApprovalStore` | One machine, you want plain inspectable files |
| SQLite | `store.sessions` | `store.checkpoints` | `store.approvals` | A Node server: one durable, transactional file, shared safely by several processes |
| Cloudflare KV | - | `KVCheckpointStore` | - | Workers deployments (see [Deployment](deployment.md)) |

`SqliteStore` keeps all three in one database file, using Node's built-in
`node:sqlite` (no native dependency; needs Node 22.13 or newer, and it is not
re-exported from the root entry, so importing the SDK never loads it):

```ts
import { createAgent, AgentExecutor } from '@loushy/build-ai-agent';
import { SqliteStore } from '@loushy/build-ai-agent/sqlite';

const store = new SqliteStore('./.loushy/agent.db'); // or ':memory:'
const session = createAgent({ provider }).session({ id: 'user-42', store: store.sessions });
await session.send('Hello');

// Same file, same store, for durable runs with approvals:
// AgentExecutor.execute({ ..., sessionId, checkpointStore: store.checkpoints, approvalStore: store.approvals })

store.prune({ olderThanMs: 7 * 24 * 60 * 60 * 1000 }); // { sessions, checkpoints, approvals } deleted
store.close();
```

- The directory is created if missing. The schema is versioned with
`PRAGMA user_version` and migrated on open; a database written by a newer
release is refused.
- WAL mode and a 5 s busy timeout let two processes share the file. An approval
can be resolved by only one of them.
- Checkpoints and approval snapshots are stored as opaque JSON, so new fields
round-trip unchanged.
- `prune()` removes sessions and checkpoints not updated within `olderThanMs`,
and approvals resolved that long ago; unresolved approvals are kept.
- A file that is not a SQLite database fails with an error naming the path;
using the store after `close()` throws a clear error.

## Project instructions

Not part of sessions, but often wanted together: see "Project instructions" in
Expand Down
45 changes: 45 additions & 0 deletions llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ dashboard — any provider, any deploy target, no lock-in.
- **Streaming events** — `for await (const event of agent.stream(input))` yields a typed, versioned, JSON-serializable event stream (`text.delta` tokens as they arrive, `tool.start`/`tool.done`, steps, approvals, a final `run.done`) ready to forward over SSE or WebSockets; `await run.result` gives the same result as `send()` ([docs/streaming.md](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/streaming.md))
=======
- **Sessions** — `agent.session()` keeps a multi-turn conversation (in memory, or persisted with `FileSessionStore`)
- **SQLite store** — `new SqliteStore('./.loushy/agent.db')` from `@loushy/build-ai-agent/sqlite` keeps sessions, checkpoints and approvals in one durable, transactional file (built-in `node:sqlite`, no native dependency) — see [Sessions](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/sessions.md#stores)
- **Project instructions** — `createAgent({ projectInstructions: true })` appends the nearest `AGENTS.md` / `CLAUDE.md` to the instructions (opt-in)
>>>>>>> origin/main
- **Parallel tool calls** — when the model asks for several tools in one turn they run concurrently (cap it with `toolConcurrency`, or `1` for sequential), and results still reach the transcript in the model's call order
Expand Down Expand Up @@ -2834,6 +2835,50 @@ Session ids must match `^[A-Za-z0-9_-]{1,128}$` (they become file names, so
`../x` and `a/b` are refused with an error that says so). Implement
`SessionStore` yourself to keep transcripts in a database or Redis.

## Stores

Sessions, durable-execution checkpoints and approvals each have a store
interface (`SessionStore`, `CheckpointStore`, `ApprovalStore`). Pick the
implementation by where the process runs:

| Store | Sessions | Checkpoints | Approvals | Use it when |
| --- | --- | --- | --- | --- |
| In memory | `MemorySessionStore` | (supply your own) | (supply your own) | Tests, scripts, one process that never restarts |
| Files | `FileSessionStore(dir)` | `LocalStorageCheckpointStore` | `StorageServiceApprovalStore` | One machine, you want plain inspectable files |
| SQLite | `store.sessions` | `store.checkpoints` | `store.approvals` | A Node server: one durable, transactional file, shared safely by several processes |
| Cloudflare KV | - | `KVCheckpointStore` | - | Workers deployments (see [Deployment](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/deployment.md)) |

`SqliteStore` keeps all three in one database file, using Node's built-in
`node:sqlite` (no native dependency; needs Node 22.13 or newer, and it is not
re-exported from the root entry, so importing the SDK never loads it):

```ts
import { createAgent, AgentExecutor } from '@loushy/build-ai-agent';
import { SqliteStore } from '@loushy/build-ai-agent/sqlite';

const store = new SqliteStore('./.loushy/agent.db'); // or ':memory:'
const session = createAgent({ provider }).session({ id: 'user-42', store: store.sessions });
await session.send('Hello');

// Same file, same store, for durable runs with approvals:
// AgentExecutor.execute({ ..., sessionId, checkpointStore: store.checkpoints, approvalStore: store.approvals })

store.prune({ olderThanMs: 7 * 24 * 60 * 60 * 1000 }); // { sessions, checkpoints, approvals } deleted
store.close();
```

- The directory is created if missing. The schema is versioned with
`PRAGMA user_version` and migrated on open; a database written by a newer
release is refused.
- WAL mode and a 5 s busy timeout let two processes share the file. An approval
can be resolved by only one of them.
- Checkpoints and approval snapshots are stored as opaque JSON, so new fields
round-trip unchanged.
- `prune()` removes sessions and checkpoints not updated within `olderThanMs`,
and approvals resolved that long ago; unresolved approvals are kept.
- A file that is not a SQLite database fails with an error naming the path;
using the store after `close()` throws a clear error.

## Project instructions

Not part of sessions, but often wanted together: see "Project instructions" in
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@
"import": "./dist/execution/hooks.mjs",
"require": "./dist/execution/hooks.js"
},
"./sqlite": {
"types": "./dist/storage/sqlite/index.d.ts",
"import": "./dist/storage/sqlite/index.mjs",
"require": "./dist/storage/sqlite/index.js"
},
"./triggers": {
"types": "./dist/triggers/index.d.ts",
"import": "./dist/triggers/index.mjs",
Expand Down
3 changes: 2 additions & 1 deletion src/providers/importGraph.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ const NEVER_LOADED_AT_IMPORT = [
'undici',
'dockerode',
'@modelcontextprotocol/sdk',
'node:sqlite', // LOU-W5: only the lazily-loaded /sqlite subpath may use it, and only when a store is constructed
];

const ENTRY_POINTS = ['index', 'core/index', 'tools/index', 'tools/mcp/index', 'flows/index', 'testing/index'];
const ENTRY_POINTS = ['index', 'core/index', 'tools/index', 'tools/mcp/index', 'flows/index', 'testing/index', 'storage/sqlite/index'];

/** Records every module specifier resolved while `body` runs, via synchronous module hooks. */
const RECORDER = `
Expand Down
Loading
Loading