@agentuity/runtime 0.0.60 → 0.0.61
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/dist/_context.d.ts +11 -7
- package/dist/_context.d.ts.map +1 -1
- package/dist/_context.js +9 -2
- package/dist/_context.js.map +1 -1
- package/dist/_server.d.ts +4 -2
- package/dist/_server.d.ts.map +1 -1
- package/dist/_server.js +71 -31
- package/dist/_server.js.map +1 -1
- package/dist/_services.d.ts +1 -1
- package/dist/_services.d.ts.map +1 -1
- package/dist/_services.js +4 -2
- package/dist/_services.js.map +1 -1
- package/dist/_waituntil.d.ts.map +1 -1
- package/dist/_waituntil.js +5 -2
- package/dist/_waituntil.js.map +1 -1
- package/dist/agent.d.ts +647 -19
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +55 -6
- package/dist/agent.js.map +1 -1
- package/dist/app.d.ts +205 -28
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +181 -13
- package/dist/app.js.map +1 -1
- package/dist/index.d.ts +41 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/io/email.d.ts.map +1 -1
- package/dist/io/email.js +11 -3
- package/dist/io/email.js.map +1 -1
- package/dist/router.d.ts +282 -32
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +110 -35
- package/dist/router.js.map +1 -1
- package/dist/services/evalrun/http.d.ts.map +1 -1
- package/dist/services/evalrun/http.js +7 -5
- package/dist/services/evalrun/http.js.map +1 -1
- package/dist/services/local/_util.d.ts.map +1 -1
- package/dist/services/local/_util.js +3 -1
- package/dist/services/local/_util.js.map +1 -1
- package/dist/services/session/http.d.ts.map +1 -1
- package/dist/services/session/http.js +4 -3
- package/dist/services/session/http.js.map +1 -1
- package/dist/session.d.ts +284 -4
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +2 -2
- package/dist/session.js.map +1 -1
- package/package.json +5 -4
- package/src/_context.ts +37 -9
- package/src/_server.ts +88 -36
- package/src/_services.ts +9 -2
- package/src/_waituntil.ts +13 -2
- package/src/agent.ts +856 -68
- package/src/app.ts +238 -38
- package/src/index.ts +42 -2
- package/src/io/email.ts +23 -5
- package/src/router.ts +359 -83
- package/src/services/evalrun/http.ts +15 -4
- package/src/services/local/_util.ts +7 -1
- package/src/services/session/http.ts +5 -2
- package/src/session.ts +297 -4
package/src/session.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import type { Context } from 'hono';
|
|
4
4
|
import { getCookie, setCookie } from 'hono/cookie';
|
|
5
5
|
import { type Env, fireEvent } from './app';
|
|
6
|
+
import type { AppState } from './index';
|
|
6
7
|
|
|
7
8
|
export type ThreadEventName = 'destroyed';
|
|
8
9
|
export type SessionEventName = 'completed';
|
|
@@ -17,44 +18,336 @@ type SessionEventCallback<T extends Session> = (
|
|
|
17
18
|
session: T
|
|
18
19
|
) => Promise<void> | void;
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Represents a conversation thread that persists across multiple sessions.
|
|
23
|
+
* Threads maintain state and can contain multiple request-response sessions.
|
|
24
|
+
*
|
|
25
|
+
* Threads are automatically managed by the runtime and stored in cookies.
|
|
26
|
+
* They expire after 1 hour of inactivity by default.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* // Access thread in agent handler
|
|
31
|
+
* const agent = createAgent({
|
|
32
|
+
* handler: async (ctx, input) => {
|
|
33
|
+
* // Get thread ID
|
|
34
|
+
* console.log('Thread:', ctx.thread.id);
|
|
35
|
+
*
|
|
36
|
+
* // Store data in thread state (persists across sessions)
|
|
37
|
+
* ctx.thread.state.set('conversationCount',
|
|
38
|
+
* (ctx.thread.state.get('conversationCount') as number || 0) + 1
|
|
39
|
+
* );
|
|
40
|
+
*
|
|
41
|
+
* // Listen for thread destruction
|
|
42
|
+
* ctx.thread.addEventListener('destroyed', (eventName, thread) => {
|
|
43
|
+
* console.log('Thread destroyed:', thread.id);
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* return 'Response';
|
|
47
|
+
* }
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
20
51
|
export interface Thread {
|
|
52
|
+
/**
|
|
53
|
+
* Unique thread identifier (e.g., "thrd_a1b2c3d4...").
|
|
54
|
+
* Stored in cookie and persists across requests.
|
|
55
|
+
*/
|
|
21
56
|
id: string;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Thread-scoped state storage that persists across multiple sessions.
|
|
60
|
+
* Use this to maintain conversation history or user preferences.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* // Store conversation count
|
|
65
|
+
* ctx.thread.state.set('messageCount',
|
|
66
|
+
* (ctx.thread.state.get('messageCount') as number || 0) + 1
|
|
67
|
+
* );
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
22
70
|
state: Map<string, unknown>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Register an event listener for when the thread is destroyed.
|
|
74
|
+
* Thread is destroyed when it expires or is manually destroyed.
|
|
75
|
+
*
|
|
76
|
+
* @param eventName - Must be 'destroyed'
|
|
77
|
+
* @param callback - Function called when thread is destroyed
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* ctx.thread.addEventListener('destroyed', (eventName, thread) => {
|
|
82
|
+
* console.log('Cleaning up thread:', thread.id);
|
|
83
|
+
* });
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
23
86
|
addEventListener(
|
|
24
87
|
eventName: 'destroyed',
|
|
25
88
|
callback: (eventName: 'destroyed', thread: Thread) => Promise<void> | void
|
|
26
89
|
): void;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Remove a previously registered 'destroyed' event listener.
|
|
93
|
+
*
|
|
94
|
+
* @param eventName - Must be 'destroyed'
|
|
95
|
+
* @param callback - The callback function to remove
|
|
96
|
+
*/
|
|
27
97
|
removeEventListener(
|
|
28
98
|
eventName: 'destroyed',
|
|
29
99
|
callback: (eventName: 'destroyed', thread: Thread) => Promise<void> | void
|
|
30
100
|
): void;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Manually destroy the thread and clean up resources.
|
|
104
|
+
* Fires the 'destroyed' event and removes thread from storage.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* // End conversation
|
|
109
|
+
* await ctx.thread.destroy();
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
31
112
|
destroy(): Promise<void>;
|
|
32
113
|
}
|
|
33
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Represents a single request-response session within a thread.
|
|
117
|
+
* Sessions are scoped to a single agent execution and its sub-agent calls.
|
|
118
|
+
*
|
|
119
|
+
* Each HTTP request creates a new session with a unique ID, but shares the same thread.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const agent = createAgent({
|
|
124
|
+
* handler: async (ctx, input) => {
|
|
125
|
+
* // Get session ID (unique per request)
|
|
126
|
+
* console.log('Session:', ctx.session.id);
|
|
127
|
+
*
|
|
128
|
+
* // Store data in session state (only for this request)
|
|
129
|
+
* ctx.session.state.set('startTime', Date.now());
|
|
130
|
+
*
|
|
131
|
+
* // Access parent thread
|
|
132
|
+
* console.log('Thread:', ctx.session.thread.id);
|
|
133
|
+
*
|
|
134
|
+
* // Listen for session completion
|
|
135
|
+
* ctx.session.addEventListener('completed', (eventName, session) => {
|
|
136
|
+
* const duration = Date.now() - (session.state.get('startTime') as number);
|
|
137
|
+
* console.log(`Session completed in ${duration}ms`);
|
|
138
|
+
* });
|
|
139
|
+
*
|
|
140
|
+
* return 'Response';
|
|
141
|
+
* }
|
|
142
|
+
* });
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
34
145
|
export interface Session {
|
|
146
|
+
/**
|
|
147
|
+
* Unique session identifier for this request.
|
|
148
|
+
* Changes with each HTTP request, even within the same thread.
|
|
149
|
+
*/
|
|
35
150
|
id: string;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The parent thread this session belongs to.
|
|
154
|
+
* Multiple sessions can share the same thread.
|
|
155
|
+
*/
|
|
36
156
|
thread: Thread;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Session-scoped state storage that only exists for this request.
|
|
160
|
+
* Use this for temporary data that shouldn't persist across requests.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```typescript
|
|
164
|
+
* ctx.session.state.set('requestStartTime', Date.now());
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
37
167
|
state: Map<string, unknown>;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Register an event listener for when the session completes.
|
|
171
|
+
* Fired after the agent handler returns and response is sent.
|
|
172
|
+
*
|
|
173
|
+
* @param eventName - Must be 'completed'
|
|
174
|
+
* @param callback - Function called when session completes
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* ctx.session.addEventListener('completed', (eventName, session) => {
|
|
179
|
+
* console.log('Session finished:', session.id);
|
|
180
|
+
* });
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
38
183
|
addEventListener(
|
|
39
184
|
eventName: 'completed',
|
|
40
185
|
callback: (eventName: 'completed', session: Session) => Promise<void> | void
|
|
41
186
|
): void;
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Remove a previously registered 'completed' event listener.
|
|
190
|
+
*
|
|
191
|
+
* @param eventName - Must be 'completed'
|
|
192
|
+
* @param callback - The callback function to remove
|
|
193
|
+
*/
|
|
42
194
|
removeEventListener(
|
|
43
195
|
eventName: 'completed',
|
|
44
196
|
callback: (eventName: 'completed', session: Session) => Promise<void> | void
|
|
45
197
|
): void;
|
|
46
198
|
}
|
|
47
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Provider interface for managing thread lifecycle and persistence.
|
|
202
|
+
* Implement this to customize how threads are stored and retrieved.
|
|
203
|
+
*
|
|
204
|
+
* The default implementation (DefaultThreadProvider) stores threads in-memory
|
|
205
|
+
* with cookie-based identification and 1-hour expiration.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```typescript
|
|
209
|
+
* class RedisThreadProvider implements ThreadProvider {
|
|
210
|
+
* private redis: Redis;
|
|
211
|
+
*
|
|
212
|
+
* async initialize(appState: AppState): Promise<void> {
|
|
213
|
+
* this.redis = await connectRedis();
|
|
214
|
+
* }
|
|
215
|
+
*
|
|
216
|
+
* async restore(ctx: Context<Env>): Promise<Thread> {
|
|
217
|
+
* const threadId = getCookie(ctx, 'atid') || generateId('thrd');
|
|
218
|
+
* const data = await this.redis.get(`thread:${threadId}`);
|
|
219
|
+
* const thread = new DefaultThread(this, threadId);
|
|
220
|
+
* if (data) {
|
|
221
|
+
* thread.state = new Map(JSON.parse(data));
|
|
222
|
+
* }
|
|
223
|
+
* return thread;
|
|
224
|
+
* }
|
|
225
|
+
*
|
|
226
|
+
* async save(thread: Thread): Promise<void> {
|
|
227
|
+
* await this.redis.setex(
|
|
228
|
+
* `thread:${thread.id}`,
|
|
229
|
+
* 3600,
|
|
230
|
+
* JSON.stringify([...thread.state])
|
|
231
|
+
* );
|
|
232
|
+
* }
|
|
233
|
+
*
|
|
234
|
+
* async destroy(thread: Thread): Promise<void> {
|
|
235
|
+
* await this.redis.del(`thread:${thread.id}`);
|
|
236
|
+
* }
|
|
237
|
+
* }
|
|
238
|
+
*
|
|
239
|
+
* // Use custom provider
|
|
240
|
+
* const app = await createApp({
|
|
241
|
+
* services: {
|
|
242
|
+
* thread: new RedisThreadProvider()
|
|
243
|
+
* }
|
|
244
|
+
* });
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
48
247
|
export interface ThreadProvider {
|
|
49
|
-
|
|
248
|
+
/**
|
|
249
|
+
* Initialize the provider when the app starts.
|
|
250
|
+
* Use this to set up connections, start cleanup intervals, etc.
|
|
251
|
+
*
|
|
252
|
+
* @param appState - The app state from createApp setup function
|
|
253
|
+
*/
|
|
254
|
+
initialize(appState: AppState): Promise<void>;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Restore or create a thread from the HTTP request context.
|
|
258
|
+
* Should check cookies for existing thread ID or create a new one.
|
|
259
|
+
*
|
|
260
|
+
* @param ctx - Hono request context
|
|
261
|
+
* @returns The restored or newly created thread
|
|
262
|
+
*/
|
|
50
263
|
restore(ctx: Context<Env>): Promise<Thread>;
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Persist thread state to storage.
|
|
267
|
+
* Called periodically to save thread data.
|
|
268
|
+
*
|
|
269
|
+
* @param thread - The thread to save
|
|
270
|
+
*/
|
|
51
271
|
save(thread: Thread): Promise<void>;
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Destroy a thread and clean up resources.
|
|
275
|
+
* Should fire the 'destroyed' event and remove from storage.
|
|
276
|
+
*
|
|
277
|
+
* @param thread - The thread to destroy
|
|
278
|
+
*/
|
|
52
279
|
destroy(thread: Thread): Promise<void>;
|
|
53
280
|
}
|
|
54
281
|
|
|
282
|
+
/**
|
|
283
|
+
* Provider interface for managing session lifecycle and persistence.
|
|
284
|
+
* Implement this to customize how sessions are stored and retrieved.
|
|
285
|
+
*
|
|
286
|
+
* The default implementation (DefaultSessionProvider) stores sessions in-memory
|
|
287
|
+
* and automatically cleans them up after completion.
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```typescript
|
|
291
|
+
* class PostgresSessionProvider implements SessionProvider {
|
|
292
|
+
* private db: Database;
|
|
293
|
+
*
|
|
294
|
+
* async initialize(appState: AppState): Promise<void> {
|
|
295
|
+
* this.db = appState.db;
|
|
296
|
+
* }
|
|
297
|
+
*
|
|
298
|
+
* async restore(thread: Thread, sessionId: string): Promise<Session> {
|
|
299
|
+
* const row = await this.db.query(
|
|
300
|
+
* 'SELECT state FROM sessions WHERE id = $1',
|
|
301
|
+
* [sessionId]
|
|
302
|
+
* );
|
|
303
|
+
* const session = new DefaultSession(thread, sessionId);
|
|
304
|
+
* if (row) {
|
|
305
|
+
* session.state = new Map(JSON.parse(row.state));
|
|
306
|
+
* }
|
|
307
|
+
* return session;
|
|
308
|
+
* }
|
|
309
|
+
*
|
|
310
|
+
* async save(session: Session): Promise<void> {
|
|
311
|
+
* await this.db.query(
|
|
312
|
+
* 'INSERT INTO sessions (id, thread_id, state) VALUES ($1, $2, $3)',
|
|
313
|
+
* [session.id, session.thread.id, JSON.stringify([...session.state])]
|
|
314
|
+
* );
|
|
315
|
+
* }
|
|
316
|
+
* }
|
|
317
|
+
*
|
|
318
|
+
* // Use custom provider
|
|
319
|
+
* const app = await createApp({
|
|
320
|
+
* services: {
|
|
321
|
+
* session: new PostgresSessionProvider()
|
|
322
|
+
* }
|
|
323
|
+
* });
|
|
324
|
+
* ```
|
|
325
|
+
*/
|
|
55
326
|
export interface SessionProvider {
|
|
56
|
-
|
|
327
|
+
/**
|
|
328
|
+
* Initialize the provider when the app starts.
|
|
329
|
+
* Use this to set up database connections or other resources.
|
|
330
|
+
*
|
|
331
|
+
* @param appState - The app state from createApp setup function
|
|
332
|
+
*/
|
|
333
|
+
initialize(appState: AppState): Promise<void>;
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Restore or create a session for the given thread and session ID.
|
|
337
|
+
* Should load existing session data or create a new session.
|
|
338
|
+
*
|
|
339
|
+
* @param thread - The parent thread for this session
|
|
340
|
+
* @param sessionId - The unique session identifier
|
|
341
|
+
* @returns The restored or newly created session
|
|
342
|
+
*/
|
|
57
343
|
restore(thread: Thread, sessionId: string): Promise<Session>;
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Persist session state and fire completion events.
|
|
347
|
+
* Called after the agent handler completes.
|
|
348
|
+
*
|
|
349
|
+
* @param session - The session to save
|
|
350
|
+
*/
|
|
58
351
|
save(session: Session): Promise<void>;
|
|
59
352
|
}
|
|
60
353
|
|
|
@@ -194,7 +487,7 @@ export class DefaultSession implements Session {
|
|
|
194
487
|
export class DefaultThreadProvider implements ThreadProvider {
|
|
195
488
|
private threads = new Map<string, DefaultThread>();
|
|
196
489
|
|
|
197
|
-
async initialize(): Promise<void> {
|
|
490
|
+
async initialize(_appState: AppState): Promise<void> {
|
|
198
491
|
setInterval(() => {
|
|
199
492
|
for (const [, thread] of this.threads) {
|
|
200
493
|
if (thread.expired()) {
|
|
@@ -256,7 +549,7 @@ export class DefaultThreadProvider implements ThreadProvider {
|
|
|
256
549
|
export class DefaultSessionProvider implements SessionProvider {
|
|
257
550
|
private sessions = new Map<string, DefaultSession>();
|
|
258
551
|
|
|
259
|
-
async initialize(): Promise<void> {
|
|
552
|
+
async initialize(_appState: AppState): Promise<void> {
|
|
260
553
|
// No initialization needed for in-memory provider
|
|
261
554
|
}
|
|
262
555
|
|