@agentuity/runtime 0.0.94 → 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 +3 -0
- package/dist/workbench.d.ts.map +1 -1
- package/dist/workbench.js +300 -31
- 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 +367 -30
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
|
*/
|
|
@@ -130,15 +261,173 @@ export const createWorkbenchRouter = () => {
|
|
|
130
261
|
// Add workbench routes
|
|
131
262
|
router.websocket('/_agentuity/workbench/ws', createWorkbenchWebsocketRoute());
|
|
132
263
|
router.get('/_agentuity/workbench/metadata.json', createWorkbenchMetadataRoute());
|
|
264
|
+
router.get('/_agentuity/workbench/sample', createWorkbenchSampleRoute());
|
|
265
|
+
router.get('/_agentuity/workbench/state', createWorkbenchStateRoute());
|
|
266
|
+
router.delete('/_agentuity/workbench/state', createWorkbenchClearStateRoute());
|
|
133
267
|
router.post('/_agentuity/workbench/execute', createWorkbenchExecutionRoute());
|
|
134
268
|
return router;
|
|
135
269
|
};
|
|
136
270
|
|
|
271
|
+
export const createWorkbenchSampleRoute = (): Handler => {
|
|
272
|
+
const authHeader = process.env.AGENTUITY_WORKBENCH_APIKEY
|
|
273
|
+
? `Bearer ${process.env.AGENTUITY_WORKBENCH_APIKEY}`
|
|
274
|
+
: undefined;
|
|
275
|
+
return async (ctx: Context) => {
|
|
276
|
+
// Authentication check
|
|
277
|
+
if (authHeader) {
|
|
278
|
+
try {
|
|
279
|
+
const authValue = ctx.req.header('Authorization');
|
|
280
|
+
if (
|
|
281
|
+
!authValue ||
|
|
282
|
+
!timingSafeEqual(Buffer.from(authValue, 'utf-8'), Buffer.from(authHeader, 'utf-8'))
|
|
283
|
+
) {
|
|
284
|
+
return ctx.text('Unauthorized', { status: 401 });
|
|
285
|
+
}
|
|
286
|
+
} catch {
|
|
287
|
+
return ctx.text('Unauthorized', { status: 401 });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
const agentId = ctx.req.query('agentId');
|
|
293
|
+
if (!agentId) {
|
|
294
|
+
return ctx.json({ error: 'Missing agentId query parameter' }, { status: 400 });
|
|
295
|
+
}
|
|
296
|
+
|
|
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
|
+
}
|
|
302
|
+
|
|
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 });
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Get runtime agent by name
|
|
312
|
+
const allAgents = getAgents();
|
|
313
|
+
const agentObj = allAgents.get(agentMeta.name);
|
|
314
|
+
|
|
315
|
+
if (!agentObj) {
|
|
316
|
+
return ctx.text('Agent not found', { status: 404 });
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Check if agent has input schema
|
|
320
|
+
if (!agentObj.inputSchema) {
|
|
321
|
+
return ctx.json({ error: 'Agent has no input schema' }, { status: 400 });
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Convert schema to JSON Schema
|
|
325
|
+
const jsonSchema = toJSONSchema(agentObj.inputSchema);
|
|
326
|
+
|
|
327
|
+
// Get Agentuity SDK key and gateway URL
|
|
328
|
+
const sdkKey = process.env.AGENTUITY_SDK_KEY;
|
|
329
|
+
const gatewayUrl =
|
|
330
|
+
process.env.AGENTUITY_AIGATEWAY_URL ||
|
|
331
|
+
process.env.AGENTUITY_TRANSPORT_URL ||
|
|
332
|
+
(sdkKey ? 'https://agentuity.ai' : '');
|
|
333
|
+
|
|
334
|
+
if (!sdkKey || !gatewayUrl) {
|
|
335
|
+
return ctx.json(
|
|
336
|
+
{
|
|
337
|
+
error: 'AGENTUITY_SDK_KEY and gateway URL must be configured',
|
|
338
|
+
message:
|
|
339
|
+
'Set AGENTUITY_SDK_KEY and either AGENTUITY_AIGATEWAY_URL, AGENTUITY_TRANSPORT_URL, or use https://agentuity.ai',
|
|
340
|
+
},
|
|
341
|
+
{ status: 500 }
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Generate sample using Groq via Agentuity Gateway
|
|
346
|
+
const prompt = `Generate a realistic sample data object that matches this JSON schema. Return only valid JSON, no markdown code blocks or explanations.
|
|
347
|
+
|
|
348
|
+
JSON Schema:
|
|
349
|
+
${JSON.stringify(jsonSchema, null, 2)}
|
|
350
|
+
|
|
351
|
+
Return a JSON object that matches this schema with realistic values.`;
|
|
352
|
+
|
|
353
|
+
const gatewayEndpoint = `${gatewayUrl}/gateway/groq/openai/v1/chat/completions`;
|
|
354
|
+
const groqResponse = await fetch(gatewayEndpoint, {
|
|
355
|
+
method: 'POST',
|
|
356
|
+
headers: {
|
|
357
|
+
Authorization: `Bearer ${sdkKey}`,
|
|
358
|
+
'Content-Type': 'application/json',
|
|
359
|
+
},
|
|
360
|
+
body: JSON.stringify({
|
|
361
|
+
model: 'llama-3.3-70b-versatile',
|
|
362
|
+
messages: [
|
|
363
|
+
{
|
|
364
|
+
role: 'user',
|
|
365
|
+
content: prompt,
|
|
366
|
+
},
|
|
367
|
+
],
|
|
368
|
+
}),
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
if (!groqResponse.ok) {
|
|
372
|
+
const errorText = await groqResponse.text();
|
|
373
|
+
return ctx.json(
|
|
374
|
+
{
|
|
375
|
+
error: 'Groq API request failed',
|
|
376
|
+
message: `Status ${groqResponse.status}: ${errorText}`,
|
|
377
|
+
},
|
|
378
|
+
{ status: 500 }
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const groqData = (await groqResponse.json()) as {
|
|
383
|
+
choices?: Array<{ message?: { content?: string } }>;
|
|
384
|
+
};
|
|
385
|
+
const text = groqData.choices?.[0]?.message?.content;
|
|
386
|
+
if (!text) {
|
|
387
|
+
return ctx.json(
|
|
388
|
+
{ error: 'Invalid response from Groq API', response: groqData },
|
|
389
|
+
{ status: 500 }
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Parse the JSON response
|
|
394
|
+
let sample: unknown;
|
|
395
|
+
try {
|
|
396
|
+
// Remove markdown code blocks if present
|
|
397
|
+
const cleanedText = text
|
|
398
|
+
.trim()
|
|
399
|
+
.replace(/^```json\s*|\s*```$/g, '')
|
|
400
|
+
.replace(/^```\s*|\s*```$/g, '');
|
|
401
|
+
sample = JSON.parse(cleanedText);
|
|
402
|
+
} catch (parseError) {
|
|
403
|
+
return ctx.json(
|
|
404
|
+
{
|
|
405
|
+
error: 'Failed to parse generated JSON',
|
|
406
|
+
message: parseError instanceof Error ? parseError.message : String(parseError),
|
|
407
|
+
generatedText: text,
|
|
408
|
+
},
|
|
409
|
+
{ status: 500 }
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return ctx.json(sample);
|
|
414
|
+
} catch (error) {
|
|
415
|
+
return ctx.json(
|
|
416
|
+
{
|
|
417
|
+
error: 'Internal server error',
|
|
418
|
+
message: error instanceof Error ? error.message : String(error),
|
|
419
|
+
},
|
|
420
|
+
{ status: 500 }
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
};
|
|
425
|
+
|
|
137
426
|
export const createWorkbenchMetadataRoute = (): Handler => {
|
|
138
427
|
const authHeader = process.env.AGENTUITY_WORKBENCH_APIKEY
|
|
139
428
|
? `Bearer ${process.env.AGENTUITY_WORKBENCH_APIKEY}`
|
|
140
429
|
: undefined;
|
|
141
|
-
|
|
430
|
+
|
|
142
431
|
return async (ctx) => {
|
|
143
432
|
if (authHeader) {
|
|
144
433
|
try {
|
|
@@ -155,27 +444,75 @@ export const createWorkbenchMetadataRoute = (): Handler => {
|
|
|
155
444
|
return ctx.text('Unauthorized', { status: 401 });
|
|
156
445
|
}
|
|
157
446
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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),
|
|
174
512
|
},
|
|
175
|
-
|
|
176
|
-
|
|
513
|
+
{ status: 500 }
|
|
514
|
+
);
|
|
177
515
|
}
|
|
178
|
-
return ctx.json(schemas);
|
|
179
516
|
};
|
|
180
517
|
};
|
|
181
518
|
|