@firtoz/chat-agent 1.0.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.
- package/README.md +443 -0
- package/package.json +74 -0
- package/src/chat-agent-base.ts +1128 -0
- package/src/chat-agent-drizzle.ts +227 -0
- package/src/chat-agent-sql.ts +199 -0
- package/src/chat-messages.ts +472 -0
- package/src/db/index.ts +21 -0
- package/src/db/schema.ts +47 -0
- package/src/index.ts +99 -0
package/README.md
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
# @firtoz/chat-agent
|
|
2
|
+
|
|
3
|
+
DB-agnostic ChatAgent for Cloudflare Durable Objects with OpenRouter - a simplified alternative to `@cloudflare/ai-chat`.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Three classes for different database preferences:
|
|
8
|
+
|
|
9
|
+
- **`ChatAgentBase`** - Abstract base class with all chat logic
|
|
10
|
+
- **`DrizzleChatAgent`** - Type-safe implementation using Drizzle ORM (recommended)
|
|
11
|
+
- **`SqlChatAgent`** - Raw SQL implementation using `this.sql` template tags
|
|
12
|
+
|
|
13
|
+
All implementations share the same API and features:
|
|
14
|
+
- OpenRouter API integration (simpler than AI SDK)
|
|
15
|
+
- Resumable streaming with chunk buffering
|
|
16
|
+
- Server-side and client-side tool execution
|
|
17
|
+
- Cloudflare AI Gateway support
|
|
18
|
+
- Message persistence in SQLite
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
bun add @firtoz/chat-agent @openrouter/sdk agents
|
|
24
|
+
|
|
25
|
+
# For Drizzle implementation:
|
|
26
|
+
bun add drizzle-orm
|
|
27
|
+
bun add -d drizzle-kit
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
### Using DrizzleChatAgent (Recommended)
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { DrizzleChatAgent, defineTool } from "@firtoz/chat-agent";
|
|
36
|
+
import type { AgentContext } from "agents";
|
|
37
|
+
|
|
38
|
+
interface Env {
|
|
39
|
+
OPENROUTER_API_KEY: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
class MyAgent extends DrizzleChatAgent<Env> {
|
|
43
|
+
protected override getSystemPrompt(): string {
|
|
44
|
+
return "You are a helpful assistant.";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
protected override getModel(): string {
|
|
48
|
+
return "anthropic/claude-sonnet-4.5";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
protected override getTools() {
|
|
52
|
+
return [
|
|
53
|
+
defineTool({
|
|
54
|
+
name: "get_time",
|
|
55
|
+
description: "Get current time",
|
|
56
|
+
parameters: { type: "object", properties: {} },
|
|
57
|
+
execute: async () => ({ time: new Date().toISOString() })
|
|
58
|
+
})
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { MyAgent };
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Using SqlChatAgent
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { SqlChatAgent } from "@firtoz/chat-agent";
|
|
70
|
+
|
|
71
|
+
class MyAgent extends SqlChatAgent<Env> {
|
|
72
|
+
// Same API as DrizzleChatAgent
|
|
73
|
+
protected override getSystemPrompt(): string {
|
|
74
|
+
return "You are a helpful assistant.";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Setup Instructions
|
|
80
|
+
|
|
81
|
+
### DrizzleChatAgent Setup
|
|
82
|
+
|
|
83
|
+
#### 1. Add Wrangler Rules
|
|
84
|
+
|
|
85
|
+
**IMPORTANT:** Add this to your `wrangler.jsonc` to import SQL migration files:
|
|
86
|
+
|
|
87
|
+
```jsonc
|
|
88
|
+
{
|
|
89
|
+
/**
|
|
90
|
+
* Rules to import SQL migration files as text
|
|
91
|
+
* Required for Drizzle ORM migrations in Durable Objects
|
|
92
|
+
* @see https://orm.drizzle.team/docs/connect-cloudflare-do
|
|
93
|
+
*/
|
|
94
|
+
"rules": [
|
|
95
|
+
{
|
|
96
|
+
"type": "Text",
|
|
97
|
+
"globs": ["**/*.sql"],
|
|
98
|
+
"fallthrough": true
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### 2. Create Drizzle Config
|
|
105
|
+
|
|
106
|
+
Create `drizzle.config.ts` in your package:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { defineConfig } from "drizzle-kit";
|
|
110
|
+
|
|
111
|
+
export default defineConfig({
|
|
112
|
+
schema: "./node_modules/@firtoz/chat-agent/src/db/schema.ts",
|
|
113
|
+
out: "./drizzle",
|
|
114
|
+
dialect: "sqlite",
|
|
115
|
+
driver: "durable-sqlite",
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Or if you're in the chat-agent package itself:
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { defineConfig } from "drizzle-kit";
|
|
123
|
+
|
|
124
|
+
export default defineConfig({
|
|
125
|
+
schema: "./src/db/schema.ts",
|
|
126
|
+
out: "./drizzle",
|
|
127
|
+
dialect: "sqlite",
|
|
128
|
+
driver: "durable-sqlite",
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### 3. Add Script to package.json
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"scripts": {
|
|
137
|
+
"db:generate": "bunx drizzle-kit generate"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### 4. Generate Migrations
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
bun run db:generate
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
This creates:
|
|
149
|
+
- `drizzle/migrations.js` - Runtime migration imports
|
|
150
|
+
- `drizzle/0000_*.sql` - Migration SQL files
|
|
151
|
+
- `drizzle/meta/` - Journal and snapshots
|
|
152
|
+
|
|
153
|
+
The migrations are automatically run when `DrizzleChatAgent` initializes.
|
|
154
|
+
|
|
155
|
+
### SqlChatAgent Setup
|
|
156
|
+
|
|
157
|
+
No additional setup needed! The SQL version creates tables automatically using `this.sql` template tags in `dbInitialize()`.
|
|
158
|
+
|
|
159
|
+
## ChatAgentBase (Abstract Class)
|
|
160
|
+
|
|
161
|
+
The base class handles all chat logic and defines the abstract database interface that implementations must provide.
|
|
162
|
+
|
|
163
|
+
### Abstract Methods
|
|
164
|
+
|
|
165
|
+
Subclasses must implement these database operations:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
// Initialization
|
|
169
|
+
protected abstract dbInitialize(): void;
|
|
170
|
+
|
|
171
|
+
// Messages
|
|
172
|
+
protected abstract dbLoadMessages(): ChatMessage[];
|
|
173
|
+
protected abstract dbSaveMessage(msg: ChatMessage): void;
|
|
174
|
+
protected abstract dbClearAll(): void;
|
|
175
|
+
|
|
176
|
+
// Stream metadata
|
|
177
|
+
protected abstract dbFindActiveStream(): {
|
|
178
|
+
id: string;
|
|
179
|
+
messageId: string;
|
|
180
|
+
createdAt: Date
|
|
181
|
+
} | null;
|
|
182
|
+
protected abstract dbDeleteStreamWithChunks(streamId: string): void;
|
|
183
|
+
protected abstract dbInsertStreamMetadata(streamId: string, messageId: string): void;
|
|
184
|
+
protected abstract dbUpdateStreamStatus(streamId: string, status: 'completed' | 'error'): void;
|
|
185
|
+
protected abstract dbDeleteOldCompletedStreams(cutoffMs: number): void;
|
|
186
|
+
|
|
187
|
+
// Stream chunks
|
|
188
|
+
protected abstract dbFindMaxChunkIndex(streamId: string): number | null;
|
|
189
|
+
protected abstract dbInsertChunks(chunks: Array<{
|
|
190
|
+
id: string;
|
|
191
|
+
streamId: string;
|
|
192
|
+
content: string;
|
|
193
|
+
chunkIndex: number
|
|
194
|
+
}>): void;
|
|
195
|
+
protected abstract dbGetChunks(streamId: string): string[];
|
|
196
|
+
protected abstract dbDeleteChunks(streamId: string): void;
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Override Methods
|
|
200
|
+
|
|
201
|
+
Customize your agent's behavior:
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
protected getSystemPrompt(): string {
|
|
205
|
+
return "Your custom system prompt";
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
protected getModel(): string {
|
|
209
|
+
// Popular OpenRouter models:
|
|
210
|
+
// - anthropic/claude-opus-4.5 (most capable)
|
|
211
|
+
// - anthropic/claude-sonnet-4.5 (balanced, default)
|
|
212
|
+
// - anthropic/claude-haiku-3.5 (fastest, cheapest)
|
|
213
|
+
return "anthropic/claude-sonnet-4.5";
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
protected getTools(): ToolDefinition[] {
|
|
217
|
+
return [
|
|
218
|
+
// Your tools here
|
|
219
|
+
];
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## DrizzleChatAgent
|
|
224
|
+
|
|
225
|
+
Type-safe implementation using Drizzle ORM.
|
|
226
|
+
|
|
227
|
+
### Database Schema
|
|
228
|
+
|
|
229
|
+
The package provides three tables:
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
// From @firtoz/chat-agent/db/schema
|
|
233
|
+
|
|
234
|
+
export const messagesTable = sqliteTable("messages", {
|
|
235
|
+
id: text("id").primaryKey(),
|
|
236
|
+
role: text("role", { enum: ["user", "assistant", "tool"] }).notNull(),
|
|
237
|
+
messageJson: text("message_json").notNull(),
|
|
238
|
+
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull(),
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
export const streamChunksTable = sqliteTable("stream_chunks", {
|
|
242
|
+
id: text("id").primaryKey(),
|
|
243
|
+
streamId: text("stream_id").notNull(),
|
|
244
|
+
content: text("content").notNull(),
|
|
245
|
+
chunkIndex: integer("chunk_index").notNull(),
|
|
246
|
+
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull(),
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
export const streamMetadataTable = sqliteTable("stream_metadata", {
|
|
250
|
+
id: text("id").primaryKey(),
|
|
251
|
+
messageId: text("message_id").notNull(),
|
|
252
|
+
status: text("status", { enum: ["streaming", "completed", "error"] }).notNull(),
|
|
253
|
+
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull(),
|
|
254
|
+
completedAt: integer("completed_at", { mode: "timestamp_ms" }),
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Implementation Details
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { DrizzleChatAgent } from "@firtoz/chat-agent";
|
|
262
|
+
|
|
263
|
+
// Automatically:
|
|
264
|
+
// - Creates Drizzle DB instance in dbInitialize()
|
|
265
|
+
// - Runs migrations from drizzle/migrations.js
|
|
266
|
+
// - Uses type-safe query builder for all operations
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## SqlChatAgent
|
|
270
|
+
|
|
271
|
+
Raw SQL implementation following `@cloudflare/ai-chat` pattern.
|
|
272
|
+
|
|
273
|
+
### Table Structure
|
|
274
|
+
|
|
275
|
+
Creates these tables automatically:
|
|
276
|
+
|
|
277
|
+
```sql
|
|
278
|
+
CREATE TABLE IF NOT EXISTS cf_ai_chat_agent_messages (
|
|
279
|
+
id TEXT PRIMARY KEY,
|
|
280
|
+
message TEXT NOT NULL,
|
|
281
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
CREATE TABLE IF NOT EXISTS cf_ai_chat_stream_chunks (
|
|
285
|
+
id TEXT PRIMARY KEY,
|
|
286
|
+
stream_id TEXT NOT NULL,
|
|
287
|
+
body TEXT NOT NULL,
|
|
288
|
+
chunk_index INTEGER NOT NULL,
|
|
289
|
+
created_at INTEGER NOT NULL
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
CREATE TABLE IF NOT EXISTS cf_ai_chat_stream_metadata (
|
|
293
|
+
id TEXT PRIMARY KEY,
|
|
294
|
+
request_id TEXT NOT NULL,
|
|
295
|
+
status TEXT NOT NULL,
|
|
296
|
+
created_at INTEGER NOT NULL,
|
|
297
|
+
completed_at INTEGER
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
CREATE INDEX IF NOT EXISTS idx_stream_chunks_stream_id
|
|
301
|
+
ON cf_ai_chat_stream_chunks(stream_id, chunk_index);
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Implementation Details
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
import { SqlChatAgent } from "@firtoz/chat-agent";
|
|
308
|
+
|
|
309
|
+
// Uses Agent's built-in this.sql template tag:
|
|
310
|
+
// - this.sql`SELECT * FROM table WHERE id = ${id}`
|
|
311
|
+
// - No additional dependencies
|
|
312
|
+
// - Tables created automatically in dbInitialize()
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Tools
|
|
316
|
+
|
|
317
|
+
### Server-Side Tools
|
|
318
|
+
|
|
319
|
+
Tools with `execute` function run on the server:
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
defineTool({
|
|
323
|
+
name: "get_weather",
|
|
324
|
+
description: "Get weather for a location",
|
|
325
|
+
parameters: {
|
|
326
|
+
type: "object",
|
|
327
|
+
properties: {
|
|
328
|
+
location: { type: "string" }
|
|
329
|
+
},
|
|
330
|
+
required: ["location"]
|
|
331
|
+
},
|
|
332
|
+
execute: async (args: { location: string }) => {
|
|
333
|
+
// Runs on server, result automatically added to conversation
|
|
334
|
+
const weather = await fetchWeather(args.location);
|
|
335
|
+
return { temperature: weather.temp, condition: weather.condition };
|
|
336
|
+
}
|
|
337
|
+
})
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Client-Side Tools
|
|
341
|
+
|
|
342
|
+
Tools without `execute` are sent to client for execution:
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
defineTool({
|
|
346
|
+
name: "get_user_location",
|
|
347
|
+
description: "Get user's browser location",
|
|
348
|
+
parameters: {
|
|
349
|
+
type: "object",
|
|
350
|
+
properties: {}
|
|
351
|
+
}
|
|
352
|
+
// No execute - client handles this via WebSocket
|
|
353
|
+
})
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## Environment Variables
|
|
357
|
+
|
|
358
|
+
```env
|
|
359
|
+
# Required
|
|
360
|
+
OPENROUTER_API_KEY=sk-or-...
|
|
361
|
+
|
|
362
|
+
# Optional: Cloudflare AI Gateway
|
|
363
|
+
CLOUDFLARE_ACCOUNT_ID=your-account-id
|
|
364
|
+
AI_GATEWAY_NAME=your-gateway-name
|
|
365
|
+
AI_GATEWAY_TOKEN=your-gateway-token
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## API Reference
|
|
369
|
+
|
|
370
|
+
### ChatMessage
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
type UserMessage = {
|
|
374
|
+
id: string;
|
|
375
|
+
role: "user";
|
|
376
|
+
content: string;
|
|
377
|
+
createdAt: number;
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
type AssistantMessage = {
|
|
381
|
+
id: string;
|
|
382
|
+
role: "assistant";
|
|
383
|
+
content: string | null;
|
|
384
|
+
toolCalls?: ToolCall[];
|
|
385
|
+
createdAt: number;
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
type ToolMessage = {
|
|
389
|
+
id: string;
|
|
390
|
+
role: "tool";
|
|
391
|
+
toolCallId: string;
|
|
392
|
+
content: string;
|
|
393
|
+
createdAt: number;
|
|
394
|
+
};
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### ToolDefinition
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
type ToolDefinition = {
|
|
401
|
+
type: "function";
|
|
402
|
+
function: {
|
|
403
|
+
name: string;
|
|
404
|
+
description?: string;
|
|
405
|
+
parameters?: JSONSchema;
|
|
406
|
+
strict?: boolean;
|
|
407
|
+
};
|
|
408
|
+
execute?: (args: any) => unknown | Promise<unknown>;
|
|
409
|
+
};
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## Features
|
|
413
|
+
|
|
414
|
+
### Implemented
|
|
415
|
+
|
|
416
|
+
- ✅ Message persistence (Drizzle or SQL)
|
|
417
|
+
- ✅ Resumable streaming with chunk buffering
|
|
418
|
+
- ✅ Stream restoration on reconnect
|
|
419
|
+
- ✅ Request cancellation via AbortController
|
|
420
|
+
- ✅ Server-side and client-side tools
|
|
421
|
+
- ✅ Tool result handling with auto-continue
|
|
422
|
+
- ✅ Cloudflare AI Gateway support
|
|
423
|
+
- ✅ DB-agnostic architecture
|
|
424
|
+
|
|
425
|
+
### Comparison: Drizzle vs SQL
|
|
426
|
+
|
|
427
|
+
| Feature | DrizzleChatAgent | SqlChatAgent |
|
|
428
|
+
|---------|-----------------|--------------|
|
|
429
|
+
| Type Safety | ✅ Full type inference | ❌ Template string types only |
|
|
430
|
+
| Setup Complexity | ⚠️ Requires migrations | ✅ Auto-creates tables |
|
|
431
|
+
| Dependencies | Drizzle ORM + drizzle-kit | None (uses Agent.sql) |
|
|
432
|
+
| Query Builder | ✅ Yes | ❌ Raw SQL only |
|
|
433
|
+
| Performance | Same | Same |
|
|
434
|
+
| Wrangler Config | ⚠️ Requires rules for .sql | ✅ No special config |
|
|
435
|
+
| Recommended For | New projects, teams | Quick prototypes, SQL experts |
|
|
436
|
+
|
|
437
|
+
## License
|
|
438
|
+
|
|
439
|
+
MIT
|
|
440
|
+
|
|
441
|
+
## Contributing
|
|
442
|
+
|
|
443
|
+
PRs welcome!
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@firtoz/chat-agent",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "ChatAgent for Cloudflare Durable Objects with OpenRouter - a simplified alternative to @cloudflare/ai-chat",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"module": "./src/index.ts",
|
|
7
|
+
"types": "./src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./src/index.ts",
|
|
11
|
+
"import": "./src/index.ts",
|
|
12
|
+
"require": "./src/index.ts"
|
|
13
|
+
},
|
|
14
|
+
"./db/schema": {
|
|
15
|
+
"types": "./src/db/schema.ts",
|
|
16
|
+
"import": "./src/db/schema.ts",
|
|
17
|
+
"require": "./src/db/schema.ts"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"src/**/*.ts",
|
|
22
|
+
"!src/**/*.test.ts",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"typecheck": "tsc --noEmit -p ./tsconfig.json",
|
|
27
|
+
"lint": "biome check --write src",
|
|
28
|
+
"lint:ci": "biome ci src",
|
|
29
|
+
"db:generate": "drizzle-kit generate",
|
|
30
|
+
"format": "biome format src --write"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"typescript",
|
|
34
|
+
"durable-objects",
|
|
35
|
+
"cloudflare",
|
|
36
|
+
"cloudflare-workers",
|
|
37
|
+
"chat",
|
|
38
|
+
"ai",
|
|
39
|
+
"openrouter",
|
|
40
|
+
"drizzle-orm",
|
|
41
|
+
"agents"
|
|
42
|
+
],
|
|
43
|
+
"author": "Firtina Ozbalikchi <firtoz@github.com>",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"homepage": "https://github.com/firtoz/fullstack-toolkit#readme",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/firtoz/fullstack-toolkit.git",
|
|
49
|
+
"directory": "packages/chat-agent"
|
|
50
|
+
},
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/firtoz/fullstack-toolkit/issues"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@cloudflare/workers-types": "^4.20260118.0",
|
|
56
|
+
"@openrouter/sdk": "^0.3.12",
|
|
57
|
+
"agents": "^0.3.4",
|
|
58
|
+
"drizzle-orm": "^0.45.1"
|
|
59
|
+
},
|
|
60
|
+
"optionalDependencies": {
|
|
61
|
+
"zod": "^4.3.5"
|
|
62
|
+
},
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=18.0.0"
|
|
65
|
+
},
|
|
66
|
+
"publishConfig": {
|
|
67
|
+
"access": "public"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"bun-types": "^1.3.6",
|
|
71
|
+
"drizzle-kit": "^0.31.8",
|
|
72
|
+
"typescript": "^5.9.3"
|
|
73
|
+
}
|
|
74
|
+
}
|