-
Notifications
You must be signed in to change notification settings - Fork 497
feat(experimental): Postgres session providers with Hyperdrive support #1297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
10ee381
8e7405a
1127f46
505f2ff
9a265a8
c4e65a8
8d2e419
9a0e19a
a3c98bb
ba4821a
cab8e7f
4b728c0
bc40a53
bb7fcf3
7f3aaf6
cb667e9
297766c
5f56bf3
e113f9c
5b50885
554dda1
6da600c
6e76bd4
3f615a2
a31bf5a
4fc07f0
3b44768
87a2561
e416388
3c8f820
1bd6fc9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,84 @@ | ||||||
| # PlanetScale Session Example | ||||||
|
|
||||||
| Agent with session history stored in PlanetScale (MySQL) instead of Durable Object SQLite. | ||||||
|
|
||||||
| ## Why PlanetScale? | ||||||
|
|
||||||
| DO SQLite is great for per-user state, but sessions live and die with the DO. PlanetScale gives you: | ||||||
|
|
||||||
| - **Cross-DO queries** — search across all conversations from any Worker | ||||||
| - **Analytics** — run SQL against your conversation data directly | ||||||
| - **Decoupled lifecycle** — session data survives DO eviction, migration, and resets | ||||||
| - **Shared state** — multiple DOs or services can read/write the same session tables | ||||||
|
|
||||||
| ## Setup | ||||||
|
|
||||||
| ### 1. Create a PlanetScale database | ||||||
|
|
||||||
| Sign up at [planetscale.com](https://planetscale.com) and create a database. The free hobby tier works fine for development. | ||||||
|
|
||||||
| ### 2. Get connection credentials | ||||||
|
|
||||||
| In the PlanetScale dashboard → your database → **Connect** → choose `@planetscale/database` → copy the host, username, and password. | ||||||
|
|
||||||
| ### 3. Set Worker secrets | ||||||
|
|
||||||
| ```bash | ||||||
| wrangler secret put PLANETSCALE_HOST | ||||||
| # paste: your-db-xxxxxxx.us-east-2.psdb.cloud | ||||||
|
|
||||||
| wrangler secret put PLANETSCALE_USERNAME | ||||||
| # paste: your username | ||||||
|
|
||||||
| wrangler secret put PLANETSCALE_PASSWORD | ||||||
| # paste: your password | ||||||
| ``` | ||||||
|
Comment on lines
+26
to
+35
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 session-planetscale README describes PlanetScale/MySQL setup but code uses Postgres/Hyperdrive The README describes setting up PlanetScale secrets ( Prompt for agentsWas this helpful? React with 👍 or 👎 to provide feedback. |
||||||
|
|
||||||
| ### 4. Deploy | ||||||
|
|
||||||
| ```bash | ||||||
| npm install | ||||||
| wrangler deploy | ||||||
| ``` | ||||||
|
|
||||||
| Tables (`assistant_messages`, `assistant_compactions`, `cf_agents_context_blocks`) are auto-created on first request. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 session-planetscale README falsely claims tables are auto-created The README states "Tables (
Suggested change
Was this helpful? React with 👍 or 👎 to provide feedback. |
||||||
|
|
||||||
| ## How it works | ||||||
|
|
||||||
| The key difference from the standard `session-memory` example: | ||||||
|
|
||||||
| ```ts | ||||||
| // Standard: auto-wires to DO SQLite | ||||||
| const session = Session.create(this) | ||||||
| .withContext("memory", { maxTokens: 1100 }) | ||||||
| .withCachedPrompt(); | ||||||
|
|
||||||
| // PlanetScale: pass providers explicitly | ||||||
| const conn = connect({ host, username, password }); | ||||||
|
|
||||||
| const session = Session.create(new PlanetScaleSessionProvider(conn, sessionId)) | ||||||
| .withContext("memory", { | ||||||
| maxTokens: 1100, | ||||||
| provider: new PlanetScaleContextProvider(conn, `memory_${sessionId}`) | ||||||
| }) | ||||||
| .withCachedPrompt( | ||||||
| new PlanetScaleContextProvider(conn, `_prompt_${sessionId}`) | ||||||
| ); | ||||||
| ``` | ||||||
|
|
||||||
| When `Session.create()` receives a `SessionProvider` (not a `SqlProvider`), it skips all SQLite auto-wiring. Context blocks and the prompt cache need explicit providers since there's no DO storage to fall back to. | ||||||
|
|
||||||
| ## Connection interface | ||||||
|
|
||||||
| The providers work with `@planetscale/database` out of the box, but any driver matching this interface works: | ||||||
|
|
||||||
| ```ts | ||||||
| interface PlanetScaleConnection { | ||||||
| execute( | ||||||
| query: string, | ||||||
| args?: (string | number | boolean | null)[] | ||||||
| ): Promise<{ rows: Record<string, unknown>[] }>; | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| This means you can also use [Neon](https://neon.tech), [Turso](https://turso.tech), or any MySQL/Postgres driver with a compatible `execute()` method. | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| declare namespace Cloudflare { | ||
| interface Env { | ||
| AI: Ai; | ||
| HYPERDRIVE: Hyperdrive; | ||
| } | ||
| } | ||
| interface Env extends Cloudflare.Env {} |
Uh oh!
There was an error while loading. Please reload this page.