@camplax/plax 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/LICENSE +6 -0
  2. package/README.md +117 -2
  3. package/bin/plax.mjs +176 -0
  4. package/dist/agent.d.ts +316 -0
  5. package/dist/agent.d.ts.map +1 -0
  6. package/dist/agents-md.d.ts +3 -0
  7. package/dist/agents-md.d.ts.map +1 -0
  8. package/dist/agents-md.js +82 -0
  9. package/dist/agents-md.js.map +1 -0
  10. package/dist/ai.d.ts +130 -0
  11. package/dist/ai.d.ts.map +1 -0
  12. package/dist/app.d.ts +82 -0
  13. package/dist/app.d.ts.map +1 -0
  14. package/dist/better-auth.d.ts +18 -0
  15. package/dist/better-auth.d.ts.map +1 -0
  16. package/dist/cron.d.ts +49 -0
  17. package/dist/cron.d.ts.map +1 -0
  18. package/dist/doctor.d.ts +20 -0
  19. package/dist/doctor.d.ts.map +1 -0
  20. package/dist/doctor.js +242 -0
  21. package/dist/doctor.js.map +1 -0
  22. package/dist/email.d.ts +93 -0
  23. package/dist/email.d.ts.map +1 -0
  24. package/dist/env.d.ts +6 -0
  25. package/dist/env.d.ts.map +1 -0
  26. package/dist/errors.d.ts +34 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/events.d.ts +42 -0
  29. package/dist/events.d.ts.map +1 -0
  30. package/dist/http.d.ts +27 -0
  31. package/dist/http.d.ts.map +1 -0
  32. package/dist/index.d.ts +26 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +2714 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/inspect.d.ts +10 -0
  37. package/dist/inspect.d.ts.map +1 -0
  38. package/dist/inspect.js +26 -0
  39. package/dist/inspect.js.map +1 -0
  40. package/dist/kv.d.ts +32 -0
  41. package/dist/kv.d.ts.map +1 -0
  42. package/dist/manifest.d.ts +98 -0
  43. package/dist/manifest.d.ts.map +1 -0
  44. package/dist/plugin.d.ts +31 -0
  45. package/dist/plugin.d.ts.map +1 -0
  46. package/dist/plugin.js +67 -0
  47. package/dist/plugin.js.map +1 -0
  48. package/dist/postgres.d.ts +33 -0
  49. package/dist/postgres.d.ts.map +1 -0
  50. package/dist/queue.d.ts +83 -0
  51. package/dist/queue.d.ts.map +1 -0
  52. package/dist/realtime.d.ts +54 -0
  53. package/dist/realtime.d.ts.map +1 -0
  54. package/dist/resource.d.ts +92 -0
  55. package/dist/resource.d.ts.map +1 -0
  56. package/dist/scaffold.d.ts +12 -0
  57. package/dist/scaffold.d.ts.map +1 -0
  58. package/dist/scaffold.js +47 -0
  59. package/dist/scaffold.js.map +1 -0
  60. package/dist/secrets.d.ts +6 -0
  61. package/dist/secrets.d.ts.map +1 -0
  62. package/dist/session.d.ts +23 -0
  63. package/dist/session.d.ts.map +1 -0
  64. package/dist/signature.d.ts +34 -0
  65. package/dist/signature.d.ts.map +1 -0
  66. package/dist/stream.d.ts +40 -0
  67. package/dist/stream.d.ts.map +1 -0
  68. package/dist/webhook.d.ts +160 -0
  69. package/dist/webhook.d.ts.map +1 -0
  70. package/package.json +61 -3
package/LICENSE ADDED
@@ -0,0 +1,6 @@
1
+ Copyright (c) 2026 Camplax. All rights reserved.
2
+
3
+ This software, including its source code, is proprietary to Camplax. You may
4
+ use it only as part of the Camplax service and under the Camplax Terms of
5
+ Service (https://camplax.dev/legal/terms). No other right to use, copy,
6
+ modify, publish or distribute it, in whole or in part, is granted.
package/README.md CHANGED
@@ -1,3 +1,118 @@
1
- # Temporary Holding Version
1
+ # @camplax/plax
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Plax is the Camplax app framework: a Node server with params and auth-guarded routes, Better Auth sessions, owner-scoped PostgreSQL resources, server-only AI, in-app agents with tools and budgets, a machine-readable manifest, doctor, and codegen.
4
+
5
+ ```ts
6
+ import { createPlaxApp, defineResource, postgresStore, agent, tool } from "@camplax/plax";
7
+ ```
8
+
9
+ Run an app with the `plax` command, the way a Next.js app runs with `next`:
10
+
11
+ ```sh
12
+ plax dev # run and restart on every change
13
+ plax build # type-check and confirm the entry
14
+ plax start # run for production
15
+ ```
16
+
17
+ The entry is `src/server.ts`. `plax start` runs it in the same Node process (no child, no wrapper), on Node 22.18 or newer.
18
+
19
+ CLI: `camplax create`, `camplax doctor`, `camplax check`, `camplax add resource|agent <name>`, `camplax add --list`.
20
+
21
+ ## Routes
22
+
23
+ ```ts
24
+ const app = createPlaxApp({
25
+ session: sessionLookup, // required if any route uses auth: true
26
+ staticDir: "public", // static files + index.html SPA fallback
27
+ routes: {
28
+ "GET /probe": (req, res) => sendOk(res, { ok: true }), // public
29
+ "GET /api/notes/:id": { // authed —
30
+ auth: true, // ctx.user guaranteed
31
+ handler: (req, res, ctx) => sendOk(res, { id: ctx.params.id }),
32
+ },
33
+ },
34
+ });
35
+ ```
36
+
37
+ - `:param` segments capture into `ctx.params`; literal routes beat parameterized ones.
38
+ - `{ auth: true }` resolves the session before the handler runs; no `session` lookup at boot = throw. Anonymous → 401.
39
+ - Thrown `PlaxFail`s are sent as-is; other errors log server-side and return a generic 500 — internals never reach the client.
40
+ - `readJsonBody(req)` parses with a 256 KB cap (throws `PayloadTooLargeError`).
41
+
42
+ ## Resources
43
+
44
+ `defineResource` scopes list, get, update, and delete by `ownerField` (default `userId`) inside the database query. The client cannot set ids or owners; only `fields` are writable; `required` and `validate` gate creates. A row the user cannot read is 404, not 403.
45
+
46
+ ```ts
47
+ export const notes = defineResource<Note>({
48
+ name: "notes",
49
+ fields: ["title"],
50
+ required: ["title"],
51
+ store: postgresStore<Note>({ client: db, table: "notes", columns: { id: "id", userId: "user_id", title: "title" } }),
52
+ });
53
+
54
+ routes: { ...notes.routes() } // GET/POST /api/notes + GET/PATCH/DELETE /api/notes/:id
55
+ resources: [notes], // lands in the manifest
56
+ ```
57
+
58
+ `postgresStore` validates configured identifiers and parameterizes every value. `?limit`/`?offset` paginate lists within the store's cap. `memoryStore` backs tests.
59
+
60
+ ## In-app agents
61
+
62
+ ```ts
63
+ const support = agent({
64
+ name: "support",
65
+ ai, // createPlaxAi(...)
66
+ system: "You help users with their orders.",
67
+ tools: {
68
+ lookupOrder: tool({
69
+ args: { id: "string" },
70
+ run: ({ id }, { user }) => orders.get(user, id), // owner-scoped — cannot cross users
71
+ }),
72
+ },
73
+ threads: postgresThreads(db), // tables from `camplax add agent`
74
+ budget: { capUsdPerDay: 0.10, store: postgresBudget(db) },
75
+ approval: { refundOrder: "user" }, // named tools pause for approval
76
+ });
77
+
78
+ routes: { ...support.routes() } // POST /api/support/chat, stream: true → SSE events
79
+ agents: [support],
80
+ ```
81
+
82
+ The loop: model → tool calls → validated args → run → results → repeat, capped by `maxSteps`. Approval-gated tools return `pendingApprovals`; the client POSTs `approve`/`deny` to resume. Budgets claim atomically before every model call (`429 budget_exceeded` when spent); the project's credit wallet still applies beneath.
83
+
84
+ With `stream: true` the reply is SSE: `message_delta`/`reasoning_delta` carry tokens and thinking as they generate, `tool_call`/`tool_result` mark each step, and `message` + `done` close it out. `done` carries `usage` — prompt, completion, reasoning and cached tokens plus `costUsd`, summed over every model call in the turn (also on the JSON reply as `usage`). Reasoning is persisted on the thread and replayed to the model on later turns.
85
+
86
+ `reasoning` sets how hard a reasoning model thinks: an effort (`reasoning: "high"`, `"none"` to switch it off), the full object (`{ max_tokens: 2000 }`, `{ effort: "medium", exclude: true }`), or `(user, input) => …` per request. It is sent on every step, tool calls included.
87
+
88
+ ## Upgrading from 0.0.x
89
+
90
+ Two contracts changed:
91
+
92
+ - Route handlers take `ctx` as the third argument, not `url`. Rename `url` → `ctx`; use `ctx.url`, `ctx.params`, and (on `auth: true` routes) `ctx.user`.
93
+ - `resource.create`/`update` return `PlaxResult` (`{ ok: true, data }` or a `bad_request`/`not_found` failure) instead of the row — check `result.ok` before reading fields.
94
+
95
+ ## The manifest
96
+
97
+ `app.manifest()` returns the app's surface — routes, resources, agents, env needs — as versioned JSON. `writeManifest(app.manifest(), dir)` from `@camplax/plax/inspect` writes `plax.manifest.json`. `camplax check` validates the app against it; coding agents read it instead of parsing source.
98
+
99
+ ## Entry points
100
+
101
+ - `@camplax/plax` — server runtime (app, resources, sessions, AI, agents, manifest builder)
102
+ - `@camplax/plax/doctor` — `camplax doctor` checks
103
+ - `@camplax/plax/plugin` — component/plugin registry
104
+ - `@camplax/plax/scaffold` — `camplax create` plumbing
105
+ - `@camplax/plax/agents-md` — generated AGENTS.md
106
+ - `@camplax/plax/inspect` — manifest file IO
107
+
108
+ Platform helpers, also from `@camplax/plax`. None needs a key or a secret set; they use what Camplax injects:
109
+
110
+ - `verifyCronRequest` — check a cron, one-off or workflow call was signed by Camplax
111
+ - `verifyCamplaxWebhook` — check a project webhook, log drain, alert or status-page call was signed by Camplax
112
+ - `createPlaxEmail` — send mail, claim inboxes and receive what arrives
113
+ - `createPlaxRealtime` — publish to channels and mint tokens for signed-in users
114
+ - `createPlaxEvents` — send events that start or resume workflows
115
+ - `createPlaxKv` — a key/value store on the app's own Postgres
116
+ - `postgresQueues` — durable queues on the app's own Postgres
117
+
118
+ The package is set up to publish publicly (`publishConfig.access` is `public`). Publish it with pnpm (`pnpm publish --access public`), never npm: npm ignores `publishConfig.exports`. Do not put secrets in client files. A resource the user cannot read or mutate is 404, not 403.
package/bin/plax.mjs ADDED
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The `plax` command — `plax dev`, `plax build`, `plax start`.
4
+ *
5
+ * Plain JavaScript on purpose: it runs before anything has been type-checked,
6
+ * from a vendored copy (vendor/plax) as well as the published package, and it
7
+ * keeps Plax's zero-dependency rule (node: builtins only).
8
+ *
9
+ * `plax start` imports the app in this same process instead of spawning a
10
+ * child, so production runs one Node process — the ~40–50 MB idle footprint
11
+ * is the reason Plax exists. The pnpm/npm .bin shim `exec`s node, so nothing
12
+ * else stays resident either.
13
+ */
14
+ import { spawn } from "node:child_process";
15
+ import { existsSync, readFileSync } from "node:fs";
16
+ import { createRequire } from "node:module";
17
+ import { dirname, join, relative, resolve } from "node:path";
18
+ import { pathToFileURL } from "node:url";
19
+
20
+ const ENTRIES = ["src/server.ts", "src/server.js", "server.ts", "server.js"];
21
+
22
+ const HELP = `Plax — the Camplax app framework.
23
+
24
+ Usage:
25
+ plax dev [entry] [--port <n>] Run the app and restart it when a file changes
26
+ plax build Check the app is ready to deploy (types and entry)
27
+ plax start [entry] Run the app for production
28
+ plax --version Print the Plax version
29
+
30
+ The entry defaults to src/server.ts.`;
31
+
32
+ function fail(message) {
33
+ console.error(`plax: ${message}`);
34
+ process.exit(1);
35
+ }
36
+
37
+ function version() {
38
+ const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
39
+ return String(pkg.version ?? "0.0.0");
40
+ }
41
+
42
+ /**
43
+ * Node runs the app's TypeScript by stripping types. That is on by default
44
+ * from Node 22.18 / 23.6; older versions need a flag Plax cannot add to a
45
+ * process that is already running.
46
+ */
47
+ function requireTypeStripping(entry) {
48
+ if (!entry.endsWith(".ts")) return;
49
+ if (process.features?.typescript) return;
50
+ fail(`this app is TypeScript and Node ${process.versions.node} cannot run it. Plax needs Node 22.18 or newer (24 recommended).`);
51
+ }
52
+
53
+ function parse(argv) {
54
+ const args = { entry: null, port: null };
55
+ for (let i = 0; i < argv.length; i++) {
56
+ const arg = argv[i];
57
+ if (arg === "--port" || arg === "-p") {
58
+ const value = argv[++i];
59
+ if (!value || !/^\d+$/.test(value)) fail("--port needs a number.");
60
+ args.port = value;
61
+ } else if (arg.startsWith("--port=")) {
62
+ const value = arg.slice("--port=".length);
63
+ if (!/^\d+$/.test(value)) fail("--port needs a number.");
64
+ args.port = value;
65
+ } else if (arg.startsWith("-")) {
66
+ fail(`unknown option ${arg}. Run plax --help.`);
67
+ } else if (args.entry === null) {
68
+ args.entry = arg;
69
+ } else {
70
+ fail(`unexpected argument ${arg}. Run plax --help.`);
71
+ }
72
+ }
73
+ return args;
74
+ }
75
+
76
+ function findEntry(cwd, explicit) {
77
+ if (explicit) {
78
+ const path = resolve(cwd, explicit);
79
+ if (!existsSync(path)) fail(`no app entry at ${explicit}.`);
80
+ return path;
81
+ }
82
+ for (const candidate of ENTRIES) {
83
+ const path = join(cwd, candidate);
84
+ if (existsSync(path)) return path;
85
+ }
86
+ fail(`no app entry found. Plax looks for ${ENTRIES.join(", ")}.`);
87
+ }
88
+
89
+ /**
90
+ * The app's own TypeScript compiler script, run with this Node — no .bin
91
+ * shim and no shell, so it behaves the same on Linux builders and Windows.
92
+ */
93
+ function findTsc(cwd) {
94
+ try {
95
+ const require = createRequire(join(cwd, "package.json"));
96
+ const pkgPath = require.resolve("typescript/package.json");
97
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
98
+ const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.tsc;
99
+ return bin ? join(dirname(pkgPath), bin) : null;
100
+ } catch {
101
+ return null;
102
+ }
103
+ }
104
+
105
+ function run(script, args, cwd) {
106
+ return new Promise((done) => {
107
+ const child = spawn(process.execPath, [script, ...args], { cwd, stdio: "inherit" });
108
+ child.on("error", () => done(1));
109
+ child.on("exit", (code, signal) => done(signal ? 1 : (code ?? 1)));
110
+ });
111
+ }
112
+
113
+ async function dev(cwd, argv) {
114
+ const { entry: explicit, port } = parse(argv);
115
+ const entry = findEntry(cwd, explicit);
116
+ requireTypeStripping(entry);
117
+ const env = { ...process.env };
118
+ if (port) env.PORT = port;
119
+ // --watch restarts on any change to a file the app imports.
120
+ const child = spawn(process.execPath, ["--watch", entry], { cwd, env, stdio: "inherit" });
121
+ const forward = (signal) => child.kill(signal);
122
+ process.on("SIGINT", forward);
123
+ process.on("SIGTERM", forward);
124
+ child.on("exit", (code, signal) => process.exit(signal ? 1 : (code ?? 0)));
125
+ }
126
+
127
+ async function build(cwd, argv) {
128
+ const { entry: explicit } = parse(argv);
129
+ const entry = findEntry(cwd, explicit);
130
+ console.log(`plax: entry ${relative(cwd, entry).replace(/\\/g, "/")}`);
131
+ if (!existsSync(join(cwd, "tsconfig.json"))) {
132
+ console.log("plax: no tsconfig.json, skipping the type check.");
133
+ return;
134
+ }
135
+ const tsc = findTsc(cwd);
136
+ if (!tsc) fail("could not find TypeScript. Add typescript to devDependencies.");
137
+ console.log("plax: checking types…");
138
+ const code = await run(tsc, ["--noEmit"], cwd);
139
+ if (code !== 0) process.exit(code);
140
+ console.log("plax: ready to deploy.");
141
+ }
142
+
143
+ async function start(cwd, argv) {
144
+ const { entry: explicit, port } = parse(argv);
145
+ if (port) process.env.PORT = port;
146
+ const entry = findEntry(cwd, explicit);
147
+ requireTypeStripping(entry);
148
+ await import(pathToFileURL(entry).href);
149
+ }
150
+
151
+ const [command, ...rest] = process.argv.slice(2);
152
+ const cwd = process.cwd();
153
+
154
+ switch (command) {
155
+ case "dev":
156
+ await dev(cwd, rest);
157
+ break;
158
+ case "build":
159
+ await build(cwd, rest);
160
+ break;
161
+ case "start":
162
+ await start(cwd, rest);
163
+ break;
164
+ case "--version":
165
+ case "-v":
166
+ console.log(version());
167
+ break;
168
+ case undefined:
169
+ case "help":
170
+ case "--help":
171
+ case "-h":
172
+ console.log(HELP);
173
+ break;
174
+ default:
175
+ fail(`unknown command ${command}. Run plax --help.`);
176
+ }
@@ -0,0 +1,316 @@
1
+ import type { PlaxAi, PlaxAiEffort, PlaxAiFailCode, PlaxAiReasoning } from "./ai.ts";
2
+ import type { ToolCallWire } from "./stream.ts";
3
+ import type { PlaxRouteMap } from "./app.ts";
4
+ import { type PlaxResult } from "./errors.ts";
5
+ import type { PlaxUser } from "./session.ts";
6
+ import type { SqlClient } from "./postgres.ts";
7
+ import type { PlaxEvents } from "./events.ts";
8
+ /**
9
+ * plax.agent() — an in-app agent. One loop: model → tool calls → results →
10
+ * repeat, capped. Tools run through the app's own resources, so an agent
11
+ * cannot read another user's rows. Threads are rows in the app's database.
12
+ * Spend draws the project's prepaid credits, capped per end-user.
13
+ */
14
+ export type PlaxToolCtx = {
15
+ user: PlaxUser;
16
+ };
17
+ /** Minimal Standard Schema shape (zod v4, valibot, arktype all expose it). */
18
+ type StandardSchemaLike = {
19
+ "~standard": {
20
+ validate: (input: unknown) => {
21
+ value?: unknown;
22
+ issues?: {
23
+ message: string;
24
+ }[];
25
+ } | Promise<{
26
+ value?: unknown;
27
+ issues?: {
28
+ message: string;
29
+ }[];
30
+ }>;
31
+ };
32
+ };
33
+ /** Shape map: `{ id: "string", count: "number?" }` — `?` marks optional. */
34
+ export type PlaxToolArgs = Record<string, "string" | "number" | "boolean" | "object" | "array" | `${"string" | "number" | "boolean" | "object" | "array"}?`> | StandardSchemaLike;
35
+ export type PlaxTool<A = Record<string, unknown>> = {
36
+ description?: string;
37
+ args?: PlaxToolArgs;
38
+ /**
39
+ * Model-facing JSON Schema for the arguments. Required for Standard-Schema
40
+ * `args` — they validate but cannot describe themselves to the model, so
41
+ * without this the model sees an empty parameter list and guesses.
42
+ */
43
+ parameters?: Record<string, unknown>;
44
+ run: (args: A, ctx: PlaxToolCtx) => unknown | Promise<unknown>;
45
+ };
46
+ export declare function tool<A = Record<string, unknown>>(spec: PlaxTool<A>): PlaxTool<A>;
47
+ /**
48
+ * A tool of any argument type — what `agent({ tools })` holds. `run`'s
49
+ * parameter is contravariant, so `PlaxTool<{ fact: string }>` is not a
50
+ * `PlaxTool<Record<string, unknown>>`; every `PlaxTool<A>` is a
51
+ * `PlaxTool<never>`. The agent validates the model's arguments against
52
+ * `args` before it calls `run`, which is what makes the one cast there safe.
53
+ */
54
+ export type AnyPlaxTool = PlaxTool<never>;
55
+ export type AgentMessage = {
56
+ role: "system" | "user" | "assistant" | "tool";
57
+ content: string | null;
58
+ toolCalls?: ToolCallWire[];
59
+ toolCallId?: string;
60
+ name?: string;
61
+ /** The model's thinking text for this turn — persisted for display. */
62
+ reasoning?: string | null;
63
+ /** Raw reasoning_details, replayed to the model verbatim on later turns. */
64
+ reasoningDetails?: Record<string, unknown>[] | null;
65
+ };
66
+ export type { ToolCallWire };
67
+ /** An image on a user message: a URL string, or `{ url, detail }`. */
68
+ export type AgentImage = string | {
69
+ url: string;
70
+ detail?: "auto" | "low" | "high";
71
+ };
72
+ /** One entry in a user's thread list. */
73
+ export type AgentThreadSummary = {
74
+ id: string;
75
+ title: string | null;
76
+ createdAt: string;
77
+ };
78
+ /** A thread as its owner saw it: user and assistant text only, oldest first. */
79
+ export type AgentThreadView = AgentThreadSummary & {
80
+ messages: {
81
+ role: "user" | "assistant";
82
+ content: string;
83
+ }[];
84
+ };
85
+ /**
86
+ * Thread persistence. postgresThreads in production, memoryThreads in tests.
87
+ * `history` returns the whole thread — long threads grow context and cost, so
88
+ * apps expecting long sessions should window what they store or send.
89
+ * `list`/`get`/`delete` take the user and apply the owner clause themselves.
90
+ */
91
+ export type AgentThreads = {
92
+ /** Verify the thread belongs to the user. Returns false when not found/owned. */
93
+ owns(user: PlaxUser, threadId: string): Promise<boolean>;
94
+ create(user: PlaxUser, title?: string): Promise<string>;
95
+ append(threadId: string, message: AgentMessage): Promise<void>;
96
+ history(threadId: string): Promise<AgentMessage[]>;
97
+ } & Partial<AgentThreadHistory>;
98
+ /**
99
+ * What a store needs for agent.routes() to mount the history routes. The
100
+ * built-in stores implement it; a custom store that does not still works for
101
+ * chat and simply gets no history routes.
102
+ */
103
+ export type AgentThreadHistory = {
104
+ /** The user's threads, newest first — `limit` defaults to 50, capped at 100. */
105
+ list(user: PlaxUser, opts?: {
106
+ limit?: number;
107
+ }): Promise<AgentThreadSummary[]>;
108
+ /**
109
+ * One thread's visible messages (the most recent 500), owner-scoped in the
110
+ * same lookup. Null when the thread is missing or belongs to someone else.
111
+ */
112
+ get(user: PlaxUser, threadId: string): Promise<AgentThreadView | null>;
113
+ /** Delete an owned thread and its messages. False when missing or not owned. */
114
+ delete(user: PlaxUser, threadId: string): Promise<boolean>;
115
+ };
116
+ type MemoryThread = {
117
+ userId: string;
118
+ title: string | null;
119
+ createdAt: Date;
120
+ seq: number;
121
+ messages: AgentMessage[];
122
+ };
123
+ export declare function memoryThreads(): AgentThreads & AgentThreadHistory & {
124
+ threads: Map<string, MemoryThread>;
125
+ };
126
+ /**
127
+ * Threads on the app's own Postgres. Tables come from the `camplax add agent`
128
+ * migration — this store never creates them, so a missing table fails loudly.
129
+ */
130
+ export declare function postgresThreads(client: SqlClient, opts?: {
131
+ threadsTable?: string;
132
+ messagesTable?: string;
133
+ }): AgentThreads & AgentThreadHistory;
134
+ /** Per-end-user AI spend cap, enforced before each model call. */
135
+ export type AgentBudget = {
136
+ /** USD already spent by this user in the current window (UTC day). */
137
+ spentToday(userId: string): Promise<number>;
138
+ /**
139
+ * Atomically add `usd` to today's spend under `capUsd`: returns false when
140
+ * the addition would exceed the cap and nothing is recorded. Check-and-
141
+ * increment in one operation — concurrent requests cannot both pass.
142
+ */
143
+ claim(userId: string, usd: number, capUsd: number): Promise<boolean>;
144
+ /** Post-hoc adjustment — settles the real cost after `claim` reserved a floor. */
145
+ record(userId: string, usd: number): Promise<void>;
146
+ };
147
+ export declare function memoryBudget(): AgentBudget;
148
+ /** Budget on `plax_usage(user_id, day, usd)` — created by the agent migration. */
149
+ export declare function postgresBudget(client: SqlClient, opts?: {
150
+ table?: string;
151
+ }): AgentBudget;
152
+ /**
153
+ * What one respond() spent, summed over every model call it made. Token
154
+ * counts come from the provider's usage report; `costUsd` is the provider's
155
+ * dollar figure (the gateway reports it) — null when no call reported one.
156
+ */
157
+ export type AgentUsage = {
158
+ promptTokens: number;
159
+ completionTokens: number;
160
+ /** Thinking tokens — billed as completion tokens, reported separately. */
161
+ reasoningTokens: number;
162
+ /** Prompt tokens served from the provider's cache. */
163
+ cachedTokens: number;
164
+ costUsd: number | null;
165
+ /** Model calls made. */
166
+ calls: number;
167
+ };
168
+ export type AgentEvent = {
169
+ type: "thread";
170
+ threadId: string;
171
+ } | {
172
+ type: "message_delta";
173
+ content: string;
174
+ } | {
175
+ type: "reasoning_delta";
176
+ content: string;
177
+ } | {
178
+ type: "tool_call";
179
+ id: string;
180
+ name: string;
181
+ args: Record<string, unknown>;
182
+ } | {
183
+ type: "tool_result";
184
+ id: string;
185
+ name: string;
186
+ ok: boolean;
187
+ result: unknown;
188
+ } | {
189
+ type: "approval_required";
190
+ calls: {
191
+ id: string;
192
+ name: string;
193
+ args: Record<string, unknown>;
194
+ }[];
195
+ } | {
196
+ type: "message";
197
+ content: string;
198
+ } | {
199
+ type: "error";
200
+ error: string;
201
+ code: string;
202
+ href?: string;
203
+ }
204
+ /** Always the last event. `usage` is set once at least one model call ran. */
205
+ | {
206
+ type: "done";
207
+ usage?: AgentUsage;
208
+ };
209
+ export type AgentReply = {
210
+ threadId: string | null;
211
+ message: string;
212
+ toolCalls: {
213
+ id: string;
214
+ name: string;
215
+ }[];
216
+ /** Set when the loop paused for tool approval — POST back with approve/deny. */
217
+ pendingApprovals?: {
218
+ id: string;
219
+ name: string;
220
+ args: Record<string, unknown>;
221
+ }[];
222
+ steps: number;
223
+ /** Tokens and dollars this reply spent; absent when no model call ran. */
224
+ usage?: AgentUsage;
225
+ };
226
+ export type AgentInput = {
227
+ threadId?: string;
228
+ message?: string;
229
+ /**
230
+ * Images on this user message, for a vision model: https URLs or
231
+ * `data:image/…;base64,` URLs, at most 8. Sent with this turn; the thread
232
+ * keeps the text and an "[N images attached]" note, not the images.
233
+ */
234
+ images?: AgentImage[];
235
+ /** Tool-call ids to approve or deny on a paused loop. */
236
+ approve?: string[];
237
+ deny?: string[];
238
+ /**
239
+ * Stream the model calls — the client gets `message_delta` and
240
+ * `reasoning_delta` events as tokens arrive, not one message at the end.
241
+ * The route sets this from `body.stream`.
242
+ */
243
+ stream?: boolean;
244
+ /** Aborts the run and the in-flight model call (client disconnects, etc.). */
245
+ signal?: AbortSignal;
246
+ onEvent?: (event: AgentEvent) => void;
247
+ };
248
+ /**
249
+ * A value fixed at construction, or computed per request from the signed-in
250
+ * user and the input — resolved once at the start of each respond().
251
+ */
252
+ export type AgentPerRequest<T> = T | ((user: PlaxUser, input: AgentInput) => T | Promise<T>);
253
+ export type PlaxAgentOptions = {
254
+ /** Slug — used for the default route path and manifest. */
255
+ name: string;
256
+ /** The server-side AI client from createPlaxAi. */
257
+ ai: PlaxAi;
258
+ /**
259
+ * Model id, or `(user, input) => id` for a per-user choice (a plan or a
260
+ * feature flag). Default `openai/gpt-4.1-mini`; an empty result falls back to it.
261
+ */
262
+ model?: AgentPerRequest<string>;
263
+ /**
264
+ * How hard a reasoning model thinks: an effort (`"low"` … `"xhigh"`, or
265
+ * `"none"` to switch thinking off) or the full reasoning object
266
+ * (`{ max_tokens: 2000 }`, `{ effort: "high", exclude: true }`). Or
267
+ * `(user, input) => …` for a per-user choice. Sent on every model call of
268
+ * the turn, tools included; thinking streams as `reasoning_delta`. Unset,
269
+ * the model's own default applies. Models that cannot think ignore it.
270
+ */
271
+ reasoning?: AgentPerRequest<PlaxAiEffort | PlaxAiReasoning | undefined>;
272
+ /**
273
+ * System prompt, or `(user, input) => prompt` — load per-user memory or
274
+ * preferences here instead of building a new agent on every request.
275
+ */
276
+ system?: AgentPerRequest<string>;
277
+ tools?: Record<string, AnyPlaxTool>;
278
+ threads?: AgentThreads;
279
+ budget?: {
280
+ capUsdPerDay: number;
281
+ store: AgentBudget;
282
+ };
283
+ /** Tools listed here pause for explicit user approval before running. Requires threads. */
284
+ approval?: Record<string, "user">;
285
+ /**
286
+ * Tell Camplax workflows about approvals (createPlaxEvents()). A paused
287
+ * loop sends `agent.approval_requested` { agent, threadId, userId, calls };
288
+ * approving or denying sends `agent.approval_resolved` { agent, threadId,
289
+ * userId, approved, denied }. A workflow waits on the second one — match
290
+ * `threadId`, time out after a day — instead of polling the thread.
291
+ * A failed send is logged and never fails the chat reply.
292
+ */
293
+ events?: PlaxEvents;
294
+ /** Max model→tool round trips per message. Default 8. */
295
+ maxSteps?: number;
296
+ /**
297
+ * Byte cap on the chat route's JSON body. Default 256 KB — raise it when
298
+ * clients POST images as data URLs (a phone photo is several MB).
299
+ */
300
+ maxBodyBytes?: number;
301
+ };
302
+ export declare function agent(opts: PlaxAgentOptions): {
303
+ name: string;
304
+ respond: (user: PlaxUser, input: AgentInput) => Promise<PlaxResult<AgentReply, "not_found" | "bad_request" | "failed" | "budget_exceeded" | PlaxAiFailCode>>;
305
+ routes: (path?: string, threadsPath?: string | false) => PlaxRouteMap;
306
+ manifest: {
307
+ model: string;
308
+ tools: string[];
309
+ budget?: {
310
+ capUsdPerDay: number;
311
+ } | undefined;
312
+ threads?: true | undefined;
313
+ };
314
+ };
315
+ export type PlaxAgent = ReturnType<typeof agent>;
316
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** Default AGENTS.md for a Plax app. Coding agents should read this first. */
2
+ export declare function plaxAgentsMd(): string;
3
+ //# sourceMappingURL=agents-md.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents-md.d.ts","sourceRoot":"","sources":["../src/agents-md.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAE9E,wBAAgB,YAAY,IAAI,MAAM,CA4ErC"}