@agentuity/claude-code 2.0.10 → 3.0.0-alpha.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.
@@ -1,13 +1,11 @@
1
1
  ---
2
2
  name: agentuity-backend
3
- description: When working with Agentuity SDK backend packages including @agentuity/runtime, @agentuity/schema, @agentuity/drizzle, @agentuity/postgres, @agentuity/evals, @agentuity/core, or @agentuity/server. Activates when writing agent handlers, using ctx.* APIs, setting up schemas, database connections, or evaluation frameworks.
4
- version: 1.0.0
3
+ description: When building AI agents, backend APIs, or server-side logic with Agentuity. Covers @agentuity/runtime for agent handlers and HTTP routing, @agentuity/schema for validation, @agentuity/drizzle and @agentuity/postgres for database access, and @agentuity/evals for testing agent quality.
4
+ version: 2.0.0
5
5
  ---
6
6
 
7
7
  # Agentuity Backend Reference
8
8
 
9
- Deep reference material for the Agentuity SDK backend packages used to build agents, APIs, and server-side applications.
10
-
11
9
  ## Package Overview
12
10
 
13
11
  | Package | Purpose |
@@ -31,450 +29,255 @@ Deep reference material for the Agentuity SDK backend packages used to build age
31
29
  | `zod` | `@agentuity/schema` | Lightweight, built-in, StandardSchemaV1 |
32
30
  | `console.log` | `ctx.logger` | Structured, observable, OpenTelemetry |
33
31
  | Generic SQL clients | Bun's native `sql` | Bun-native, auto-credentials |
32
+ | `createRouter()` wrapper | `new Hono<Env>()` directly | Chained methods enable hc<AppRouter>() type safety |
34
33
 
35
34
  **Note:** Both Zod and @agentuity/schema implement StandardSchemaV1, so agent schemas accept either.
36
35
 
37
- ## Reference URLs
38
-
39
- When uncertain, look up:
40
-
41
- - **SDK Source**: https://github.com/agentuity/sdk/tree/main/packages
42
- - **Docs**: https://agentuity.dev
43
- - **Runtime**: https://github.com/agentuity/sdk/tree/main/packages/runtime/src
44
- - **Examples**: https://github.com/agentuity/sdk/tree/main/apps/testing/integration-suite
45
-
46
- ---
47
-
48
- ## @agentuity/runtime
36
+ ## AI Gateway (Default — No API Keys Needed)
49
37
 
50
- ### createAgent()
38
+ LLM requests automatically route through Agentuity's **AI Gateway** when running via `agentuity dev` or deployed. **Do not ask users for LLM provider API keys.** The gateway supports models from any provider (OpenAI, Anthropic, Groq, etc.) — use the provider SDK that matches the model:
51
39
 
52
40
  ```typescript
53
- import { createAgent } from '@agentuity/runtime';
54
- import { s } from '@agentuity/schema';
55
-
56
- export default createAgent('my-agent', {
57
- description: 'What this agent does',
58
- schema: {
59
- input: s.object({ message: s.string() }),
60
- output: s.object({ reply: s.string() }),
61
- },
62
- // Optional: setup runs once on app startup
63
- setup: async (app) => {
64
- const cache = new Map();
65
- return { cache }; // Available via ctx.config
66
- },
67
- // Optional: cleanup on shutdown
68
- shutdown: async (app, config) => {
69
- config.cache.clear();
70
- },
71
- handler: async (ctx, input) => {
72
- // ctx has all services
73
- return { reply: `Got: ${input.message}` };
74
- },
41
+ // For OpenAI models (gpt-5-mini, gpt-5, etc.) — use the OpenAI SDK
42
+ import OpenAI from 'openai';
43
+ const openai = new OpenAI();
44
+ const res = await openai.chat.completions.create({
45
+ model: 'gpt-5-mini',
46
+ messages: [{ role: 'user', content: input.message }],
75
47
  });
76
48
  ```
77
49
 
78
- **CRITICAL:** Do NOT add type annotations to handler parameters - let TypeScript infer them from schema.
79
-
80
- ### AgentContext (ctx)
81
-
82
- | Property | Purpose |
83
- | ----------------- | ------------------------------------------------------ |
84
- | `ctx.logger` | Structured logging (trace/debug/info/warn/error/fatal) |
85
- | `ctx.tracer` | OpenTelemetry tracing |
86
- | `ctx.kv` | Key-value storage |
87
- | `ctx.vector` | Semantic search |
88
- | `ctx.stream` | Stream storage |
89
- | `ctx.sandbox` | Code execution |
90
- | `ctx.auth` | User authentication (if configured) |
91
- | `ctx.thread` | Conversation context (up to 1 hour) |
92
- | `ctx.session` | Request-scoped context |
93
- | `ctx.state` | Request-scoped Map (sync) |
94
- | `ctx.config` | Agent config from setup() |
95
- | `ctx.app` | App state from createApp setup() |
96
- | `ctx.current` | Agent metadata (name, agentId, version) |
97
- | `ctx.sessionId` | Unique request ID |
98
- | `ctx.waitUntil()` | Background tasks after response |
99
-
100
- ### State Management
101
-
102
50
  ```typescript
103
- handler: async (ctx, input) => {
104
- // Thread state - persists across requests in same conversation (async)
105
- const history = (await ctx.thread.state.get<Message[]>('messages')) || [];
106
- history.push({ role: 'user', content: input.message });
107
- await ctx.thread.state.set('messages', history);
108
-
109
- // Session state - persists for request duration (sync)
110
- ctx.session.state.set('lastInput', input.message);
111
-
112
- // Request state - cleared after handler (sync)
113
- ctx.state.set('startTime', Date.now());
114
-
115
- // KV - persists across threads/projects
116
- await ctx.kv.set('namespace', 'key', value);
117
- };
118
- ```
119
-
120
- ### Calling Other Agents
121
-
122
- ```typescript
123
- // Import at top of file
124
- import otherAgent from '@agent/other-agent';
125
-
126
- handler: async (ctx, input) => {
127
- // Type-safe call
128
- const result = await otherAgent.run({ query: input.text });
129
- return { data: result };
130
- };
51
+ // For Anthropic models (claude-sonnet-4-6, etc.) use the Anthropic SDK
52
+ import Anthropic from '@anthropic-ai/sdk';
53
+ const anthropic = new Anthropic();
54
+ const res = await anthropic.messages.create({
55
+ model: 'claude-sonnet-4-6',
56
+ max_tokens: 1024,
57
+ messages: [{ role: 'user', content: input.message }],
58
+ });
131
59
  ```
132
60
 
133
- ### Streaming Responses
134
-
135
61
  ```typescript
136
- import { createAgent } from '@agentuity/runtime';
137
- import { streamText } from 'ai';
62
+ // Or use the Vercel AI SDK for a provider-agnostic approach
63
+ import { generateText } from 'ai';
138
64
  import { openai } from '@ai-sdk/openai';
139
-
140
- export default createAgent('chat', {
141
- schema: {
142
- input: s.object({ message: s.string() }),
143
- stream: true, // Enable streaming
144
- },
145
- handler: async (ctx, input) => {
146
- const { textStream } = streamText({
147
- model: openai('gpt-4o'),
148
- prompt: input.message,
149
- });
150
- return textStream;
151
- },
65
+ const { text } = await generateText({
66
+ model: openai('gpt-5-mini'),
67
+ prompt: input.message,
152
68
  });
153
69
  ```
154
70
 
155
- ### Background Tasks
71
+ No API keys needed — the gateway sets provider base URLs automatically. **Match the SDK to the model provider** — don't pass Anthropic model names to the OpenAI client or vice versa.
156
72
 
157
- ```typescript
158
- handler: async (ctx, input) => {
159
- // Schedule non-blocking work after response
160
- ctx.waitUntil(async () => {
161
- await ctx.vector.upsert('docs', {
162
- key: input.docId,
163
- document: input.content,
164
- });
165
- });
166
-
167
- return { status: 'Queued for indexing' };
168
- };
169
- ```
73
+ **Important:** The AI Gateway only works when running via `agentuity dev` or when deployed to Agentuity. It does NOT work with raw `bun run app.ts`.
170
74
 
171
- ### Route Validation with agent.validator()
75
+ - Docs: https://agentuity.dev/agents/ai-gateway.md
76
+ - Docs: https://agentuity.dev/agents/ai-sdk-integration.md
172
77
 
173
- ```typescript
174
- import { createRouter } from '@agentuity/runtime';
175
- import myAgent from '@agent/my-agent';
78
+ ## Key Concepts
176
79
 
177
- const router = createRouter();
80
+ - Agents are created with `createAgent('name', { description, schema, handler })` from `@agentuity/runtime`
81
+ - Agents must be barrel-exported from `src/agent/index.ts` and passed to `createApp({ agents })`
82
+ - Handler receives `ctx` (AgentContext) and typed `input`
83
+ - `ctx` provides: logger, tracer, kv, vector, stream, sandbox, auth, thread, session, state, config
84
+ - Schemas use `@agentuity/schema` (or Zod — both implement StandardSchemaV1)
85
+ - Call other agents via `@agent/<name>` import alias
86
+ - DON'T add type annotations to handler params — let TS infer from schema
178
87
 
179
- // Use agent's schema for automatic validation
180
- router.post('/', myAgent.validator(), async (c) => {
181
- const data = c.req.valid('json'); // Fully typed!
182
- return c.json(await myAgent.run(data));
183
- });
88
+ ## Agents Need API Routes
89
+
90
+ **Agents are NOT HTTP endpoints.** To expose an agent over HTTP, create a route in `src/api/` that calls it. Use Hono directly with chained methods for type safety:
91
+
92
+ ```typescript
93
+ // src/api/index.ts — compose all routes into a single Hono instance
94
+ import { Hono } from 'hono';
95
+ import type { Env } from '@agentuity/runtime';
96
+ import chat from '@agent/chat';
97
+
98
+ const router = new Hono<Env>()
99
+ .post('/chat', chat.validator(), async (c) => {
100
+ const data = c.req.valid('json');
101
+ const result = await chat.run(data);
102
+ return c.json(result);
103
+ });
104
+
105
+ export default router;
184
106
  ```
185
107
 
186
- ---
108
+ For streaming responses, use the `stream()` middleware:
187
109
 
188
- ## @agentuity/schema
110
+ ```typescript
111
+ import { Hono } from 'hono';
112
+ import type { Env } from '@agentuity/runtime';
113
+ import { stream } from '@agentuity/runtime';
114
+ import chat from '@agent/chat';
115
+
116
+ const router = new Hono<Env>()
117
+ .post('/chat', stream(async (c) => {
118
+ const body = await c.req.json();
119
+ return chat.run(body);
120
+ }));
121
+
122
+ export default router;
123
+ ```
189
124
 
190
- Lightweight schema validation implementing StandardSchemaV1.
125
+ For routes that don't call agents, use the standalone `validator()` for schema validation:
191
126
 
192
127
  ```typescript
128
+ import { Hono } from 'hono';
129
+ import type { Env } from '@agentuity/runtime';
130
+ import { validator } from '@agentuity/runtime';
193
131
  import { s } from '@agentuity/schema';
194
132
 
195
- const userSchema = s.object({
196
- name: s.string(),
197
- email: s.string(),
198
- age: s.number().optional(),
199
- role: s.enum(['admin', 'user', 'guest']),
200
- metadata: s
201
- .object({
202
- createdAt: s.string(),
203
- })
204
- .optional(),
205
- tags: s.array(s.string()),
133
+ const OutputSchema = s.object({
134
+ history: s.array(s.object({ text: s.string(), timestamp: s.string() })),
206
135
  });
207
136
 
208
- // Type inference
209
- type User = s.Infer<typeof userSchema>;
137
+ const router = new Hono<Env>()
138
+ .get('/history', validator({ output: OutputSchema }), async (c) => {
139
+ const history = (await c.var.thread.state.get('history')) ?? [];
140
+ return c.json({ history });
141
+ });
210
142
 
211
- // Coercion schemas
212
- s.coerce.string(); // Coerces to string
213
- s.coerce.number(); // Coerces to number
214
- s.coerce.boolean(); // Coerces to boolean
215
- s.coerce.date(); // Coerces to Date
143
+ export default router;
216
144
  ```
217
145
 
218
- **When to use Zod instead:**
146
+ - Docs: https://agentuity.dev/routes/http.md
219
147
 
220
- - Complex validation rules (.email(), .url(), .min(), .max())
221
- - User prefers Zod
222
- - Existing Zod schemas in codebase
148
+ ## Agent Context vs Route Context
223
149
 
224
- Both work with StandardSchemaV1 - agent schemas accept either.
150
+ **Different APIs for agents and routes don't mix them up:**
225
151
 
226
- ---
152
+ | Service | In agents (`handler`) | In routes (`router`) |
153
+ | --- | --- | --- |
154
+ | Logger | `ctx.logger` | `c.var.logger` |
155
+ | KV Storage | `ctx.kv` | `c.var.kv` |
156
+ | Vector | `ctx.vector` | `c.var.vector` |
157
+ | Stream | `ctx.stream` | `c.var.stream` |
158
+ | Sandbox | `ctx.sandbox` | `c.var.sandbox` |
159
+ | Thread | `ctx.thread` | `c.var.thread` |
160
+ | Session | `ctx.session` | `c.var.session` |
227
161
 
228
- ## @agentuity/drizzle
162
+ - Docs: https://agentuity.dev/agents/creating-agents.md
229
163
 
230
- **ALWAYS use this instead of drizzle-orm directly for Agentuity projects.**
164
+ ## KV Storage API
231
165
 
232
- ```typescript
233
- import { createPostgresDrizzle, pgTable, text, serial, eq } from '@agentuity/drizzle';
234
-
235
- // Define schema
236
- const users = pgTable('users', {
237
- id: serial('id').primaryKey(),
238
- name: text('name').notNull(),
239
- email: text('email').notNull().unique(),
240
- });
241
-
242
- // Create database instance (uses DATABASE_URL by default)
243
- const { db, client, close } = createPostgresDrizzle({
244
- schema: { users },
245
- });
246
-
247
- // Or with explicit configuration
248
- const { db, close } = createPostgresDrizzle({
249
- connectionString: 'postgres://user:pass@localhost:5432/mydb',
250
- schema: { users },
251
- logger: true,
252
- reconnect: {
253
- maxAttempts: 5,
254
- initialDelayMs: 100,
255
- },
256
- onReconnected: () => console.log('Reconnected!'),
257
- });
258
-
259
- // Execute type-safe queries
260
- const allUsers = await db.select().from(users);
261
- const user = await db.select().from(users).where(eq(users.id, 1));
262
-
263
- // Clean up
264
- await close();
265
- ```
266
-
267
- ### Integration with @agentuity/auth
166
+ **`ctx.kv` requires a namespace and key — NOT just a key.** Returns a `DataResult<T>` discriminated union, not `T | null`:
268
167
 
269
168
  ```typescript
270
- import { createPostgresDrizzle, drizzleAdapter } from '@agentuity/drizzle';
271
- import { createAuth } from '@agentuity/auth';
272
- import * as schema from './schema';
169
+ // GET check .exists before accessing .data
170
+ const result = await ctx.kv.get<MyType>('my-namespace', 'my-key');
171
+ const data: MyType[] = result.exists ? result.data : [];
273
172
 
274
- const { db, close } = createPostgresDrizzle({ schema });
173
+ // SET — namespace, key, value, optional params
174
+ await ctx.kv.set('my-namespace', 'my-key', { count: 42 }, { ttl: 3600 });
275
175
 
276
- const auth = createAuth({
277
- database: drizzleAdapter(db, { provider: 'pg' }),
278
- });
176
+ // DELETE
177
+ await ctx.kv.delete('my-namespace', 'my-key');
279
178
  ```
280
179
 
281
- ### Re-exports
282
-
283
- The package re-exports commonly used items:
284
-
285
- - From drizzle-orm: `sql`, `eq`, `and`, `or`, `not`, `desc`, `asc`, `gt`, `gte`, `lt`, `lte`, etc.
286
- - From drizzle-orm/pg-core: `pgTable`, `pgSchema`, `pgEnum`, column types
287
- - From @agentuity/postgres: `postgres`, `PostgresClient`, etc.
180
+ Namespaces are auto-created on first write with a 7-day default TTL. Override per-key via `{ ttl: seconds }` (min 60s, max 365 days). In routes, use `c.var.kv` instead of `ctx.kv` — same API.
288
181
 
289
- ---
182
+ - Docs: https://agentuity.dev/services/storage/key-value.md
290
183
 
291
- ## @agentuity/postgres
184
+ ## Agent Evaluations
292
185
 
293
- **ALWAYS use this instead of pg/postgres for Agentuity projects.**
186
+ Use `@agentuity/evals` for preset evaluations and `agent.createEval()` for custom ones:
294
187
 
295
188
  ```typescript
296
- import { postgres } from '@agentuity/postgres';
297
-
298
- // Create client (uses DATABASE_URL by default)
299
- const sql = postgres();
300
-
301
- // Or with explicit config
302
- const sql = postgres({
303
- hostname: 'localhost',
304
- port: 5432,
305
- database: 'mydb',
306
- reconnect: {
307
- maxAttempts: 5,
308
- initialDelayMs: 100,
309
- },
189
+ // Preset eval (e.g., adversarial testing)
190
+ import { adversarial } from '@agentuity/evals';
191
+ import agent from './index';
192
+
193
+ export const adversarialEval = agent.createEval(
194
+ adversarial({
195
+ middleware: {
196
+ transformInput: (input) => ({ request: input.text }),
197
+ transformOutput: (output) => ({ response: output.result }),
198
+ },
199
+ })
200
+ );
201
+
202
+ // Custom eval
203
+ export const qualityEval = agent.createEval('quality-check', {
204
+ description: 'Verifies output quality meets threshold',
205
+ handler: async (ctx, input, output) => {
206
+ return {
207
+ passed: output.result.length > 0,
208
+ reason: output.result.length > 0 ? 'Output is non-empty' : 'Empty output',
209
+ };
210
+ },
310
211
  });
311
-
312
- // Query using tagged template literals
313
- const users = await sql`SELECT * FROM users WHERE active = ${true}`;
314
-
315
- // Transactions
316
- const tx = await sql.begin();
317
- try {
318
- await tx`INSERT INTO users (name) VALUES (${name})`;
319
- await tx.commit();
320
- } catch (error) {
321
- await tx.rollback();
322
- throw error;
323
- }
324
212
  ```
325
213
 
326
- ### Key Features
327
-
328
- - **Lazy connections**: Connection established on first query (set `preconnect: true` for immediate)
329
- - **Auto-reconnection**: Exponential backoff with jitter
330
- - **Graceful shutdown**: Detects SIGTERM/SIGINT, prevents reconnection during shutdown
331
- - **Global registry**: All clients tracked for coordinated shutdown
214
+ Place eval files alongside the agent: `src/agent/<name>/eval.ts`.
332
215
 
333
- ### When to use Bun SQL instead
216
+ - Docs: https://agentuity.dev/agents/evaluations.md
334
217
 
335
- Use Bun's native `sql` for simple queries:
218
+ ## v2 Migration
336
219
 
337
- ```typescript
338
- import { sql } from 'bun';
339
- const rows = await sql`SELECT * FROM users`;
340
- ```
220
+ If upgrading from v1, run `npx @agentuity/migrate` to auto-convert `createRouter()` to chained Hono style and generate barrel files. See the [Migration Guide](https://agentuity.dev/reference/migration-guide.md).
341
221
 
342
- Use @agentuity/postgres when you need:
222
+ ## Documentation Links
343
223
 
344
- - Resilient connections with auto-retry
345
- - Connection pooling with stats
346
- - Coordinated shutdown across multiple clients
347
-
348
- ---
224
+ | Topic | Link |
225
+ | --- | --- |
226
+ | Creating Agents | https://agentuity.dev/agents/creating-agents.md |
227
+ | State Management | https://agentuity.dev/agents/state-management.md |
228
+ | Streaming Responses | https://agentuity.dev/agents/streaming-responses.md |
229
+ | Schema Libraries | https://agentuity.dev/agents/schema-libraries.md |
230
+ | Calling Other Agents | https://agentuity.dev/agents/calling-other-agents.md |
231
+ | Events & Lifecycle | https://agentuity.dev/agents/events-lifecycle.md |
232
+ | Evaluations | https://agentuity.dev/agents/evaluations.md |
233
+ | AI SDK Integration | https://agentuity.dev/agents/ai-sdk-integration.md |
234
+ | AI Gateway | https://agentuity.dev/agents/ai-gateway.md |
235
+ | Drizzle ORM | https://agentuity.dev/services/database/drizzle.md |
236
+ | Postgres Client | https://agentuity.dev/services/database/postgres.md |
237
+ | SDK Reference | https://agentuity.dev/reference/sdk-reference.md |
238
+ | Migration Guide | https://agentuity.dev/reference/migration-guide.md |
349
239
 
350
- ## @agentuity/evals
240
+ ## Common Mistakes
351
241
 
352
- Agent evaluation framework for testing agent behavior.
242
+ | Mistake | Better Approach | Why |
243
+ | ---------------------------------------------------- | ----------------------------------------------- | ------------------------------ |
244
+ | `handler: async (ctx: AgentContext, input: MyInput)` | `handler: async (ctx, input)` | Let TS infer types from schema |
245
+ | `const schema = { name: s.string() }` | `const schema = s.object({ name: s.string() })` | Must use s.object() wrapper |
246
+ | `console.log('debug')` in production | `ctx.logger.debug('debug')` | Structured, observable |
247
+ | Ignoring connection resilience | Use @agentuity/drizzle or @agentuity/postgres | Auto-reconnect on failures |
248
+ | Asking for OpenAI/Anthropic API keys | Use the AI Gateway (works with SDK key) | LLM requests route through Agentuity automatically |
249
+ | Using `c.var.logger` in agent handlers | Use `ctx.logger` in agents | Agent context and route context have different APIs |
250
+ | Using `ctx.logger` in route handlers | Use `c.var.logger` in routes | Agent context and route context have different APIs |
251
+ | Exposing agents without routes | Create API routes in `src/api/` | Agents are not HTTP endpoints |
252
+ | Skipping agent evaluations | Add eval.ts alongside agent index.ts | Evals catch regressions and validate quality |
253
+ | Using mutating router style (.get() separately) | Use chained Hono methods (.get().post()) | Chained style required for hc<AppRouter>() types |
254
+ | Missing agent barrel file | Create src/agent/index.ts re-exporting agents | v2 requires explicit agent registration |
255
+ | `ctx.kv.get('key')` (missing namespace) | `ctx.kv.get<T>('namespace', 'key')` — check `.exists` | KV requires namespace + key, returns DataResult not T |
256
+ | Passing Claude model to `new OpenAI()` | Use `new Anthropic()` for Claude models | Match the SDK to the model provider — gateway routes automatically |
257
+ | Running `new OpenAI()` outside `agentuity dev` | Always run via `agentuity dev` or deploy first | AI Gateway only sets provider base URLs in the Agentuity runtime |
258
+
259
+ ## Example
353
260
 
354
261
  ```typescript
355
- import { createPresetEval, type BaseEvalOptions } from '@agentuity/evals';
262
+ import { createAgent } from '@agentuity/runtime';
356
263
  import { s } from '@agentuity/schema';
357
264
 
358
- // Define custom options
359
- type ToneEvalOptions = BaseEvalOptions & {
360
- expectedTone: 'formal' | 'casual' | 'friendly';
361
- };
362
-
363
- // Create preset eval
364
- export const toneEval = createPresetEval<
365
- typeof inputSchema, // TInput
366
- typeof outputSchema, // TOutput
367
- ToneEvalOptions // TOptions
368
- >({
369
- name: 'tone-check',
370
- description: 'Evaluates if response matches expected tone',
371
- options: {
372
- model: openai('gpt-4o'), // LanguageModel instance from AI SDK
373
- expectedTone: 'friendly',
265
+ export default createAgent('my-agent', {
266
+ schema: {
267
+ input: s.object({ message: s.string() }),
268
+ output: s.object({ reply: s.string() }),
374
269
  },
375
- handler: async (ctx, input, output, options) => {
376
- // Evaluation logic - use options.model for LLM calls
377
- return {
378
- passed: true,
379
- score: 0.85, // optional (0.0-1.0)
380
- reason: 'Response matches friendly tone',
381
- };
270
+ handler: async (ctx, input) => {
271
+ // ctx provides: logger, kv, vector, stream, sandbox, auth, thread, session, state
272
+ return { reply: `Got: ${input.message}` };
382
273
  },
383
274
  });
384
-
385
- // Usage on agent
386
- agent.createEval(toneEval()); // Use defaults
387
- agent.createEval(toneEval({ expectedTone: 'formal' })); // Override options
388
- ```
389
-
390
- **Key points:**
391
-
392
- - Use `s.object({...})` for typed input/output, or `undefined` for generic evals
393
- - Options are flattened (not nested under `options`)
394
- - Return `{ passed, score?, reason? }` - throw on error
395
- - Use middleware to transform agent input/output to eval's expected types
396
-
397
- ---
398
-
399
- ## @agentuity/core
400
-
401
- Foundational types and utilities used by all Agentuity packages.
402
-
403
- ### StructuredError
404
-
405
- ```typescript
406
- import { StructuredError } from '@agentuity/core';
407
-
408
- const MyError = StructuredError('MyError', 'Something went wrong')<{
409
- code: string;
410
- details: string;
411
- }>();
412
-
413
- throw new MyError({ code: 'ERR_001', details: 'More info' });
414
- ```
415
-
416
- ### Core Types
417
-
418
- - **StructuredError**: Create typed errors with structured data
419
- - **StandardSchemaV1**: Interface for schema validation (implemented by @agentuity/schema and Zod)
420
- - **Json types**: Type utilities for JSON-serializable data
421
- - **Service interfaces**: KeyValueStorage, VectorStorage, StreamStorage
422
-
423
- ---
424
-
425
- ## @agentuity/server
426
-
427
- Server utilities that work in both Node.js and Bun.
428
-
429
- ```typescript
430
- import { validateDatabaseName, validateBucketName } from '@agentuity/server';
431
-
432
- // Validate before provisioning
433
- const dbResult = validateDatabaseName(userInput);
434
- if (!dbResult.valid) {
435
- throw new Error(dbResult.error);
436
- }
437
-
438
- const bucketResult = validateBucketName(userInput);
439
- if (!bucketResult.valid) {
440
- throw new Error(bucketResult.error);
441
- }
442
275
  ```
443
276
 
444
- ---
445
-
446
- ## Common Patterns
277
+ ## When In Doubt, Check the Docs
447
278
 
448
- ### Project Structure (after `agentuity new`)
279
+ If you're unsure about any API signature, context method, or pattern, **check the documentation first** rather than guessing:
449
280
 
450
- ```
451
- ├── agentuity.json # Project config (projectId, orgId)
452
- ├── agentuity.config.ts # Build config
453
- ├── package.json
454
- ├── src/
455
- │ ├── agent/<name>/ # Each agent in its own folder
456
- │ │ ├── agent.ts # Agent definition
457
- │ │ └── index.ts # Exports
458
- │ ├── api/ # API routes (Hono)
459
- │ └── web/ # React frontend
460
- └── .env # AGENTUITY_SDK_KEY, DATABASE_URL, etc.
461
- ```
462
-
463
- ### Bun-First Runtime
464
-
465
- Always prefer Bun built-in APIs:
466
-
467
- - `Bun.file(f).exists()` not `fs.existsSync(f)`
468
- - `import { sql } from 'bun'` for simple queries
469
- - `import { s3 } from 'bun'` for object storage
470
-
471
- ---
472
-
473
- ## Common Mistakes
474
-
475
- | Mistake | Better Approach | Why |
476
- | ---------------------------------------------------- | ----------------------------------------------- | ------------------------------ |
477
- | `handler: async (ctx: AgentContext, input: MyInput)` | `handler: async (ctx, input)` | Let TS infer types from schema |
478
- | `const schema = { name: s.string() }` | `const schema = s.object({ name: s.string() })` | Must use s.object() wrapper |
479
- | `console.log('debug')` in production | `ctx.logger.debug('debug')` | Structured, observable |
480
- | Ignoring connection resilience | Use @agentuity/drizzle or @agentuity/postgres | Auto-reconnect on failures |
281
+ - Full docs: https://agentuity.dev
282
+ - LLM-friendly index: https://agentuity.dev/llms.txt
283
+ - AI Gateway: https://agentuity.dev/agents/ai-gateway.md