@agentuity/runtime 0.0.95 → 0.0.96
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/AGENTS.md +3 -1
- package/dist/_events.d.ts +64 -0
- package/dist/_events.d.ts.map +1 -0
- package/dist/_events.js +92 -0
- package/dist/_events.js.map +1 -0
- package/dist/_idle.d.ts +1 -1
- package/dist/_idle.d.ts.map +1 -1
- package/dist/_idle.js +2 -16
- package/dist/_idle.js.map +1 -1
- package/dist/_server.d.ts +30 -13
- package/dist/_server.d.ts.map +1 -1
- package/dist/_server.js +39 -572
- package/dist/_server.js.map +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/_standalone.d.ts.map +1 -1
- package/dist/_standalone.js +2 -1
- package/dist/_standalone.js.map +1 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +13 -17
- package/dist/agent.js.map +1 -1
- package/dist/app.d.ts +58 -171
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +119 -218
- package/dist/app.js.map +1 -1
- package/dist/index.d.ts +11 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -3
- package/dist/index.js.map +1 -1
- package/dist/middleware.d.ts +29 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +200 -0
- package/dist/middleware.js.map +1 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +5 -2
- package/dist/router.js.map +1 -1
- package/dist/services/local/vector.d.ts.map +1 -1
- package/dist/services/local/vector.js +3 -2
- package/dist/services/local/vector.js.map +1 -1
- package/dist/services/thread/local.d.ts +20 -0
- package/dist/services/thread/local.d.ts.map +1 -0
- package/dist/services/thread/local.js +76 -0
- package/dist/services/thread/local.js.map +1 -0
- package/dist/session.d.ts +60 -8
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +186 -54
- package/dist/session.js.map +1 -1
- package/dist/web.d.ts +8 -0
- package/dist/web.d.ts.map +1 -0
- package/dist/web.js +66 -0
- package/dist/web.js.map +1 -0
- package/dist/workbench.d.ts +2 -0
- package/dist/workbench.d.ts.map +1 -1
- package/dist/workbench.js +192 -39
- package/dist/workbench.js.map +1 -1
- package/package.json +10 -10
- package/src/_events.ts +142 -0
- package/src/_idle.ts +2 -18
- package/src/_server.ts +48 -681
- package/src/_services.ts +4 -2
- package/src/_standalone.ts +2 -1
- package/src/agent.ts +11 -14
- package/src/app.ts +164 -246
- package/src/index.ts +42 -4
- package/src/middleware.ts +252 -0
- package/src/router.ts +6 -2
- package/src/services/local/vector.ts +3 -2
- package/src/services/thread/local.ts +106 -0
- package/src/session.ts +238 -59
- package/src/web.ts +75 -0
- package/src/workbench.ts +226 -38
package/src/workbench.ts
CHANGED
|
@@ -5,6 +5,9 @@ import { getAgents, createAgentMiddleware } from './agent';
|
|
|
5
5
|
import { createRouter } from './router';
|
|
6
6
|
import type { WebSocketConnection } from './router';
|
|
7
7
|
import { privateContext } from './_server';
|
|
8
|
+
import { getThreadProvider } from './_services';
|
|
9
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
10
|
+
import { join } from 'node:path';
|
|
8
11
|
|
|
9
12
|
export const createWorkbenchExecutionRoute = (): Handler => {
|
|
10
13
|
const authHeader = process.env.AGENTUITY_WORKBENCH_APIKEY
|
|
@@ -28,6 +31,12 @@ export const createWorkbenchExecutionRoute = (): Handler => {
|
|
|
28
31
|
}
|
|
29
32
|
}
|
|
30
33
|
|
|
34
|
+
// Content-type validation
|
|
35
|
+
const contentType = ctx.req.header('Content-Type');
|
|
36
|
+
if (!contentType || !contentType.includes('application/json')) {
|
|
37
|
+
return ctx.json({ error: 'Content-Type must be application/json' }, { status: 400 });
|
|
38
|
+
}
|
|
39
|
+
|
|
31
40
|
try {
|
|
32
41
|
let agentId: string;
|
|
33
42
|
let input: unknown;
|
|
@@ -39,20 +48,25 @@ export const createWorkbenchExecutionRoute = (): Handler => {
|
|
|
39
48
|
return ctx.json({ error: 'Invalid JSON in request body' }, { status: 400 });
|
|
40
49
|
}
|
|
41
50
|
|
|
42
|
-
//
|
|
43
|
-
const
|
|
51
|
+
// Read metadata to find agent name by agentId
|
|
52
|
+
const metadataPath = join(process.cwd(), '.agentuity', 'agentuity.metadata.json');
|
|
53
|
+
if (!existsSync(metadataPath)) {
|
|
54
|
+
return ctx.json({ error: 'Metadata file not found' }, { status: 500 });
|
|
55
|
+
}
|
|
44
56
|
|
|
45
|
-
|
|
46
|
-
|
|
57
|
+
const fileContent = readFileSync(metadataPath, 'utf-8');
|
|
58
|
+
const metadata = JSON.parse(fileContent);
|
|
59
|
+
const agentMeta = metadata.agents?.find((a: { agentId: string }) => a.agentId === agentId);
|
|
47
60
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
agentObj = agent;
|
|
51
|
-
agentName = name;
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
61
|
+
if (!agentMeta) {
|
|
62
|
+
return ctx.text('Agent not found', { status: 404 });
|
|
54
63
|
}
|
|
55
64
|
|
|
65
|
+
// Get runtime agent by name
|
|
66
|
+
const allAgents = getAgents();
|
|
67
|
+
const agentName = agentMeta.name;
|
|
68
|
+
const agentObj = allAgents.get(agentName);
|
|
69
|
+
|
|
56
70
|
if (!agentObj || !agentName) {
|
|
57
71
|
return ctx.text('Agent not found', { status: 404 });
|
|
58
72
|
}
|
|
@@ -76,6 +90,32 @@ export const createWorkbenchExecutionRoute = (): Handler => {
|
|
|
76
90
|
result = await (agentObj as any).handler();
|
|
77
91
|
}
|
|
78
92
|
|
|
93
|
+
// Store input and output in thread state, keyed by agentId
|
|
94
|
+
// This allows multiple agents to have separate message histories in the same thread
|
|
95
|
+
if (ctx.var.thread) {
|
|
96
|
+
const agentMessagesKey = `messages_${agentId}`;
|
|
97
|
+
const existingMessages = ctx.var.thread.state.get(agentMessagesKey);
|
|
98
|
+
const messages = (existingMessages as unknown[] | undefined) || [];
|
|
99
|
+
|
|
100
|
+
messages.push({ type: 'input', data: input });
|
|
101
|
+
|
|
102
|
+
if (result !== undefined && result !== null) {
|
|
103
|
+
messages.push({ type: 'output', data: result });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
ctx.var.thread.state.set(agentMessagesKey, messages);
|
|
107
|
+
|
|
108
|
+
// Manually save the thread to ensure state persists
|
|
109
|
+
try {
|
|
110
|
+
const threadProvider = getThreadProvider();
|
|
111
|
+
await threadProvider.save(ctx.var.thread);
|
|
112
|
+
} catch {
|
|
113
|
+
ctx.var.logger?.warn('Failed to save thread state');
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
ctx.var.logger?.warn('Thread not available in workbench execution route');
|
|
117
|
+
}
|
|
118
|
+
|
|
79
119
|
// Handle cases where result might be undefined/null
|
|
80
120
|
if (result === undefined || result === null) {
|
|
81
121
|
return ctx.json({ success: true, result: null });
|
|
@@ -94,6 +134,97 @@ export const createWorkbenchExecutionRoute = (): Handler => {
|
|
|
94
134
|
};
|
|
95
135
|
};
|
|
96
136
|
|
|
137
|
+
export const createWorkbenchClearStateRoute = (): Handler => {
|
|
138
|
+
const authHeader = process.env.AGENTUITY_WORKBENCH_APIKEY
|
|
139
|
+
? `Bearer ${process.env.AGENTUITY_WORKBENCH_APIKEY}`
|
|
140
|
+
: undefined;
|
|
141
|
+
return async (ctx: Context) => {
|
|
142
|
+
// Authentication check
|
|
143
|
+
if (authHeader) {
|
|
144
|
+
try {
|
|
145
|
+
const authValue = ctx.req.header('Authorization');
|
|
146
|
+
if (
|
|
147
|
+
!authValue ||
|
|
148
|
+
!timingSafeEqual(Buffer.from(authValue, 'utf-8'), Buffer.from(authHeader, 'utf-8'))
|
|
149
|
+
) {
|
|
150
|
+
return ctx.text('Unauthorized', { status: 401 });
|
|
151
|
+
}
|
|
152
|
+
} catch {
|
|
153
|
+
// timing safe equals will throw if the input/output lengths are mismatched
|
|
154
|
+
// so we treat all exceptions as invalid
|
|
155
|
+
return ctx.text('Unauthorized', { status: 401 });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const agentId = ctx.req.query('agentId');
|
|
160
|
+
|
|
161
|
+
if (!agentId) {
|
|
162
|
+
return ctx.json({ error: 'agentId query parameter is required' }, { status: 400 });
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!ctx.var.thread) {
|
|
166
|
+
return ctx.json({ error: 'Thread not available' }, { status: 404 });
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const agentMessagesKey = `messages_${agentId}`;
|
|
170
|
+
|
|
171
|
+
// Remove the messages for this agent
|
|
172
|
+
ctx.var.thread.state.delete(agentMessagesKey);
|
|
173
|
+
|
|
174
|
+
// Save the thread to persist the cleared state
|
|
175
|
+
try {
|
|
176
|
+
const threadProvider = getThreadProvider();
|
|
177
|
+
await threadProvider.save(ctx.var.thread);
|
|
178
|
+
} catch {
|
|
179
|
+
return ctx.json({ error: 'Failed to save thread state' }, { status: 500 });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return ctx.json({ success: true, message: `State cleared for agent ${agentId}` });
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export const createWorkbenchStateRoute = (): Handler => {
|
|
187
|
+
const authHeader = process.env.AGENTUITY_WORKBENCH_APIKEY
|
|
188
|
+
? `Bearer ${process.env.AGENTUITY_WORKBENCH_APIKEY}`
|
|
189
|
+
: undefined;
|
|
190
|
+
return async (ctx: Context) => {
|
|
191
|
+
// Authentication check
|
|
192
|
+
if (authHeader) {
|
|
193
|
+
try {
|
|
194
|
+
const authValue = ctx.req.header('Authorization');
|
|
195
|
+
if (
|
|
196
|
+
!authValue ||
|
|
197
|
+
!timingSafeEqual(Buffer.from(authValue, 'utf-8'), Buffer.from(authHeader, 'utf-8'))
|
|
198
|
+
) {
|
|
199
|
+
return ctx.text('Unauthorized', { status: 401 });
|
|
200
|
+
}
|
|
201
|
+
} catch {
|
|
202
|
+
// timing safe equals will throw if the input/output lengths are mismatched
|
|
203
|
+
// so we treat all exceptions as invalid
|
|
204
|
+
return ctx.text('Unauthorized', { status: 401 });
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const agentId = ctx.req.query('agentId');
|
|
209
|
+
if (!agentId) {
|
|
210
|
+
return ctx.json({ error: 'agentId query parameter is required' }, { status: 400 });
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!ctx.var.thread) {
|
|
214
|
+
return ctx.json({ error: 'Thread not available' }, { status: 404 });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const agentMessagesKey = `messages_${agentId}`;
|
|
218
|
+
const messages = ctx.var.thread.state.get(agentMessagesKey);
|
|
219
|
+
|
|
220
|
+
return ctx.json({
|
|
221
|
+
threadId: ctx.var.thread.id,
|
|
222
|
+
agentId,
|
|
223
|
+
messages: Array.isArray(messages) ? messages : [],
|
|
224
|
+
});
|
|
225
|
+
};
|
|
226
|
+
};
|
|
227
|
+
|
|
97
228
|
/**
|
|
98
229
|
* Creates a workbench router with proper agent middleware for execution routes
|
|
99
230
|
*/
|
|
@@ -131,6 +262,8 @@ export const createWorkbenchRouter = () => {
|
|
|
131
262
|
router.websocket('/_agentuity/workbench/ws', createWorkbenchWebsocketRoute());
|
|
132
263
|
router.get('/_agentuity/workbench/metadata.json', createWorkbenchMetadataRoute());
|
|
133
264
|
router.get('/_agentuity/workbench/sample', createWorkbenchSampleRoute());
|
|
265
|
+
router.get('/_agentuity/workbench/state', createWorkbenchStateRoute());
|
|
266
|
+
router.delete('/_agentuity/workbench/state', createWorkbenchClearStateRoute());
|
|
134
267
|
router.post('/_agentuity/workbench/execute', createWorkbenchExecutionRoute());
|
|
135
268
|
return router;
|
|
136
269
|
};
|
|
@@ -161,17 +294,24 @@ export const createWorkbenchSampleRoute = (): Handler => {
|
|
|
161
294
|
return ctx.json({ error: 'Missing agentId query parameter' }, { status: 400 });
|
|
162
295
|
}
|
|
163
296
|
|
|
164
|
-
//
|
|
165
|
-
const
|
|
297
|
+
// Read metadata to find agent name by agentId
|
|
298
|
+
const metadataPath = join(process.cwd(), '.agentuity', 'agentuity.metadata.json');
|
|
299
|
+
if (!existsSync(metadataPath)) {
|
|
300
|
+
return ctx.json({ error: 'Metadata file not found' }, { status: 500 });
|
|
301
|
+
}
|
|
166
302
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
303
|
+
const fileContent = readFileSync(metadataPath, 'utf-8');
|
|
304
|
+
const metadata = JSON.parse(fileContent);
|
|
305
|
+
const agentMeta = metadata.agents?.find((a: { agentId: string }) => a.agentId === agentId);
|
|
306
|
+
|
|
307
|
+
if (!agentMeta) {
|
|
308
|
+
return ctx.text('Agent not found', { status: 404 });
|
|
173
309
|
}
|
|
174
310
|
|
|
311
|
+
// Get runtime agent by name
|
|
312
|
+
const allAgents = getAgents();
|
|
313
|
+
const agentObj = allAgents.get(agentMeta.name);
|
|
314
|
+
|
|
175
315
|
if (!agentObj) {
|
|
176
316
|
return ctx.text('Agent not found', { status: 404 });
|
|
177
317
|
}
|
|
@@ -287,7 +427,7 @@ export const createWorkbenchMetadataRoute = (): Handler => {
|
|
|
287
427
|
const authHeader = process.env.AGENTUITY_WORKBENCH_APIKEY
|
|
288
428
|
? `Bearer ${process.env.AGENTUITY_WORKBENCH_APIKEY}`
|
|
289
429
|
: undefined;
|
|
290
|
-
|
|
430
|
+
|
|
291
431
|
return async (ctx) => {
|
|
292
432
|
if (authHeader) {
|
|
293
433
|
try {
|
|
@@ -304,27 +444,75 @@ export const createWorkbenchMetadataRoute = (): Handler => {
|
|
|
304
444
|
return ctx.text('Unauthorized', { status: 401 });
|
|
305
445
|
}
|
|
306
446
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
447
|
+
|
|
448
|
+
// Read metadata from agentuity.metadata.json file
|
|
449
|
+
const metadataPath = join(process.cwd(), '.agentuity', 'agentuity.metadata.json');
|
|
450
|
+
|
|
451
|
+
if (!existsSync(metadataPath)) {
|
|
452
|
+
return ctx.json(
|
|
453
|
+
{ error: 'Metadata file not found. Run build to generate metadata.' },
|
|
454
|
+
{ status: 500 }
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
try {
|
|
459
|
+
const fileContent = readFileSync(metadataPath, 'utf-8');
|
|
460
|
+
const metadata = JSON.parse(fileContent);
|
|
461
|
+
|
|
462
|
+
// Get runtime agents for JSON schema generation
|
|
463
|
+
const agents = getAgents();
|
|
464
|
+
const agentsByName = new Map();
|
|
465
|
+
for (const [name, agent] of agents) {
|
|
466
|
+
agentsByName.set(name, agent);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Transform metadata structure to workbench format
|
|
470
|
+
const schemas: { agents: Record<string, unknown> } = { agents: {} };
|
|
471
|
+
|
|
472
|
+
for (const agent of metadata.agents || []) {
|
|
473
|
+
// Try to find runtime agent by name to get JSON schemas
|
|
474
|
+
const runtimeAgent = agentsByName.get(agent.name);
|
|
475
|
+
|
|
476
|
+
schemas.agents[agent.id] = {
|
|
477
|
+
schema: {
|
|
478
|
+
input: agent.schema?.input
|
|
479
|
+
? {
|
|
480
|
+
code: agent.schema.input,
|
|
481
|
+
json: runtimeAgent?.inputSchema
|
|
482
|
+
? toJSONSchema(runtimeAgent.inputSchema)
|
|
483
|
+
: undefined,
|
|
484
|
+
}
|
|
485
|
+
: undefined,
|
|
486
|
+
output: agent.schema?.output
|
|
487
|
+
? {
|
|
488
|
+
code: agent.schema.output,
|
|
489
|
+
json: runtimeAgent?.outputSchema
|
|
490
|
+
? toJSONSchema(runtimeAgent.outputSchema)
|
|
491
|
+
: undefined,
|
|
492
|
+
}
|
|
493
|
+
: undefined,
|
|
494
|
+
},
|
|
495
|
+
metadata: {
|
|
496
|
+
id: agent.id,
|
|
497
|
+
agentId: agent.agentId,
|
|
498
|
+
name: agent.name,
|
|
499
|
+
description: agent.description,
|
|
500
|
+
filename: agent.filename,
|
|
501
|
+
version: agent.version,
|
|
502
|
+
},
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return ctx.json(schemas);
|
|
507
|
+
} catch (error) {
|
|
508
|
+
return ctx.json(
|
|
509
|
+
{
|
|
510
|
+
error: 'Failed to read metadata file',
|
|
511
|
+
message: error instanceof Error ? error.message : String(error),
|
|
323
512
|
},
|
|
324
|
-
|
|
325
|
-
|
|
513
|
+
{ status: 500 }
|
|
514
|
+
);
|
|
326
515
|
}
|
|
327
|
-
return ctx.json(schemas);
|
|
328
516
|
};
|
|
329
517
|
};
|
|
330
518
|
|