@reminix/runtime 0.0.7 → 0.0.9

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/agent.js CHANGED
@@ -2,24 +2,29 @@
2
2
  * Agent classes for Reminix Runtime.
3
3
  */
4
4
  import { VERSION } from './version.js';
5
+ /**
6
+ * Default parameters schema for agents.
7
+ * Request: { prompt: '...' }
8
+ */
9
+ const DEFAULT_AGENT_PARAMETERS = {
10
+ type: 'object',
11
+ properties: {
12
+ prompt: { type: 'string', description: 'The prompt or task for the agent' },
13
+ },
14
+ required: ['prompt'],
15
+ };
5
16
  /**
6
17
  * Abstract base class defining the agent interface.
7
18
  *
8
19
  * This is the core contract that all agents must fulfill.
9
20
  * Use `Agent` for callback-based registration or extend
10
- * `BaseAdapter` for framework adapters.
21
+ * `AgentAdapter` for framework adapters.
11
22
  */
12
23
  export class AgentBase {
13
24
  /**
14
- * Whether invoke supports streaming. Override to enable.
15
- */
16
- get invokeStreaming() {
17
- return false;
18
- }
19
- /**
20
- * Whether chat supports streaming. Override to enable.
25
+ * Whether execute supports streaming. Override to enable.
21
26
  */
22
- get chatStreaming() {
27
+ get streaming() {
23
28
  return false;
24
29
  }
25
30
  /**
@@ -27,20 +32,18 @@ export class AgentBase {
27
32
  * Override this to provide custom metadata.
28
33
  */
29
34
  get metadata() {
30
- return { type: 'agent' };
31
- }
32
- /**
33
- * Handle a streaming invoke request.
34
- */
35
- // eslint-disable-next-line require-yield
36
- async *invokeStream(_request) {
37
- throw new Error('Streaming not implemented for this agent');
35
+ return {
36
+ type: 'agent',
37
+ parameters: DEFAULT_AGENT_PARAMETERS,
38
+ requestKeys: ['prompt'],
39
+ responseKeys: ['content'],
40
+ };
38
41
  }
39
42
  /**
40
- * Handle a streaming chat request.
43
+ * Handle a streaming execute request.
41
44
  */
42
45
  // eslint-disable-next-line require-yield
43
- async *chatStream(_request) {
46
+ async *executeStream(_request) {
44
47
  throw new Error('Streaming not implemented for this agent');
45
48
  }
46
49
  /**
@@ -53,7 +56,7 @@ export class AgentBase {
53
56
  * ```typescript
54
57
  * // Vercel Edge Function
55
58
  * const agent = new Agent('my-agent');
56
- * agent.onInvoke(async (req) => ({ output: 'Hello!' }));
59
+ * agent.onExecute(async (req) => ({ output: 'Hello!' }));
57
60
  * export default agent.toHandler();
58
61
  *
59
62
  * // Cloudflare Worker
@@ -93,30 +96,41 @@ export class AgentBase {
93
96
  {
94
97
  name: this.name,
95
98
  ...this.metadata,
96
- invoke: { streaming: this.invokeStreaming },
97
- chat: { streaming: this.chatStreaming },
99
+ streaming: this.streaming,
98
100
  },
99
101
  ],
100
102
  }, { headers: corsHeaders });
101
103
  }
102
- // POST /agents/{name}/invoke
103
- const invokeMatch = path.match(/^\/agents\/([^/]+)\/invoke$/);
104
- if (method === 'POST' && invokeMatch) {
105
- const agentName = invokeMatch[1];
104
+ // POST /agents/{name}/execute
105
+ const executeMatch = path.match(/^\/agents\/([^/]+)\/execute$/);
106
+ if (method === 'POST' && executeMatch) {
107
+ const agentName = executeMatch[1];
106
108
  if (agentName !== this.name) {
107
109
  return Response.json({ error: `Agent '${agentName}' not found` }, { status: 404, headers: corsHeaders });
108
110
  }
109
111
  const body = (await request.json());
110
- if (!body.input || Object.keys(body.input).length === 0) {
111
- return Response.json({ error: 'input is required and must not be empty' }, { status: 400, headers: corsHeaders });
112
+ // Get requestKeys from agent metadata (all agents have defaults)
113
+ const requestKeys = this.metadata.requestKeys ?? [];
114
+ // Extract declared keys from body into input object
115
+ // e.g., requestKeys: ['prompt'] with body { prompt: '...' } -> input = { prompt: '...' }
116
+ const input = {};
117
+ for (const key of requestKeys) {
118
+ if (key in body) {
119
+ input[key] = body[key];
120
+ }
112
121
  }
122
+ const executeRequest = {
123
+ input,
124
+ stream: body.stream === true,
125
+ context: body.context,
126
+ };
113
127
  // Handle streaming
114
- if (body.stream) {
128
+ if (executeRequest.stream) {
115
129
  const stream = new ReadableStream({
116
130
  start: async (controller) => {
117
131
  const encoder = new TextEncoder();
118
132
  try {
119
- for await (const chunk of this.invokeStream(body)) {
133
+ for await (const chunk of this.executeStream(executeRequest)) {
120
134
  controller.enqueue(encoder.encode(`data: ${chunk}\n\n`));
121
135
  }
122
136
  controller.enqueue(encoder.encode('data: [DONE]\n\n'));
@@ -137,48 +151,7 @@ export class AgentBase {
137
151
  },
138
152
  });
139
153
  }
140
- const response = await this.invoke(body);
141
- return Response.json(response, { headers: corsHeaders });
142
- }
143
- // POST /agents/{name}/chat
144
- const chatMatch = path.match(/^\/agents\/([^/]+)\/chat$/);
145
- if (method === 'POST' && chatMatch) {
146
- const agentName = chatMatch[1];
147
- if (agentName !== this.name) {
148
- return Response.json({ error: `Agent '${agentName}' not found` }, { status: 404, headers: corsHeaders });
149
- }
150
- const body = (await request.json());
151
- if (!body.messages || body.messages.length === 0) {
152
- return Response.json({ error: 'messages is required and must not be empty' }, { status: 400, headers: corsHeaders });
153
- }
154
- // Handle streaming
155
- if (body.stream) {
156
- const stream = new ReadableStream({
157
- start: async (controller) => {
158
- const encoder = new TextEncoder();
159
- try {
160
- for await (const chunk of this.chatStream(body)) {
161
- controller.enqueue(encoder.encode(`data: ${chunk}\n\n`));
162
- }
163
- controller.enqueue(encoder.encode('data: [DONE]\n\n'));
164
- }
165
- catch (error) {
166
- const message = error instanceof Error ? error.message : 'Unknown error';
167
- controller.enqueue(encoder.encode(`data: ${JSON.stringify({ error: message })}\n\n`));
168
- }
169
- controller.close();
170
- },
171
- });
172
- return new Response(stream, {
173
- headers: {
174
- ...corsHeaders,
175
- 'Content-Type': 'text/event-stream',
176
- 'Cache-Control': 'no-cache',
177
- Connection: 'keep-alive',
178
- },
179
- });
180
- }
181
- const response = await this.chat(body);
154
+ const response = await this.execute(executeRequest);
182
155
  return Response.json(response, { headers: corsHeaders });
183
156
  }
184
157
  // Not found
@@ -199,28 +172,22 @@ export class AgentBase {
199
172
  * ```typescript
200
173
  * const agent = new Agent('my-agent');
201
174
  *
202
- * agent.onInvoke(async (request) => {
175
+ * agent.onExecute(async (request) => {
203
176
  * return { output: 'Hello!' };
204
177
  * });
205
178
  *
206
- * agent.onChat(async (request) => {
207
- * return { output: 'Hi!', messages: [...] };
208
- * });
209
- *
210
179
  * serve({ agents: [agent], port: 8080 });
211
180
  * ```
212
181
  */
213
182
  export class Agent extends AgentBase {
214
183
  _name;
215
184
  _metadata;
216
- _invokeHandler = null;
217
- _chatHandler = null;
218
- _invokeStreamHandler = null;
219
- _chatStreamHandler = null;
185
+ _executeHandler = null;
186
+ _executeStreamHandler = null;
220
187
  /**
221
188
  * Create a new agent.
222
189
  *
223
- * @param name - The agent name (used in URLs like /agents/{name}/invoke)
190
+ * @param name - The agent name (used in URLs like /agents/{name}/execute)
224
191
  * @param options - Optional configuration
225
192
  */
226
193
  constructor(name, options) {
@@ -238,104 +205,364 @@ export class Agent extends AgentBase {
238
205
  * Return agent metadata for discovery.
239
206
  */
240
207
  get metadata() {
241
- return { type: 'agent', ...this._metadata };
242
- }
243
- /**
244
- * Whether invoke supports streaming.
245
- */
246
- get invokeStreaming() {
247
- return this._invokeStreamHandler !== null;
208
+ return {
209
+ type: 'agent',
210
+ parameters: DEFAULT_AGENT_PARAMETERS,
211
+ requestKeys: ['prompt'],
212
+ responseKeys: ['content'],
213
+ ...this._metadata,
214
+ };
248
215
  }
249
216
  /**
250
- * Whether chat supports streaming.
217
+ * Whether execute supports streaming.
251
218
  */
252
- get chatStreaming() {
253
- return this._chatStreamHandler !== null;
219
+ get streaming() {
220
+ return this._executeStreamHandler !== null;
254
221
  }
255
222
  /**
256
- * Register an invoke handler.
223
+ * Register an execute handler.
257
224
  *
258
225
  * @example
259
- * agent.onInvoke(async (request) => {
226
+ * agent.onExecute(async (request) => {
260
227
  * return { output: 'Hello!' };
261
228
  * });
262
229
  */
263
- onInvoke(handler) {
264
- this._invokeHandler = handler;
265
- return this;
266
- }
267
- /**
268
- * Register a chat handler.
269
- *
270
- * @example
271
- * agent.onChat(async (request) => {
272
- * return { output: 'Hi!', messages: [...] };
273
- * });
274
- */
275
- onChat(handler) {
276
- this._chatHandler = handler;
230
+ onExecute(handler) {
231
+ this._executeHandler = handler;
277
232
  return this;
278
233
  }
279
234
  /**
280
- * Register a streaming invoke handler.
235
+ * Register a streaming execute handler.
281
236
  *
282
237
  * @example
283
- * agent.onInvokeStream(async function* (request) {
238
+ * agent.onExecuteStream(async function* (request) {
284
239
  * yield '{"chunk": "Hello"}';
285
240
  * yield '{"chunk": " world!"}';
286
241
  * });
287
242
  */
288
- onInvokeStream(handler) {
289
- this._invokeStreamHandler = handler;
243
+ onExecuteStream(handler) {
244
+ this._executeStreamHandler = handler;
290
245
  return this;
291
246
  }
292
247
  /**
293
- * Register a streaming chat handler.
294
- *
295
- * @example
296
- * agent.onChatStream(async function* (request) {
297
- * yield '{"chunk": "Hi"}';
298
- * });
299
- */
300
- onChatStream(handler) {
301
- this._chatStreamHandler = handler;
302
- return this;
303
- }
304
- /**
305
- * Handle an invoke request.
248
+ * Handle an execute request.
306
249
  */
307
- async invoke(request) {
308
- if (this._invokeHandler === null) {
309
- throw new Error(`No invoke handler registered for agent '${this._name}'`);
250
+ async execute(request) {
251
+ if (this._executeHandler === null) {
252
+ throw new Error(`No execute handler registered for agent '${this._name}'`);
310
253
  }
311
- return this._invokeHandler(request);
254
+ return this._executeHandler(request);
312
255
  }
313
256
  /**
314
- * Handle a chat request.
257
+ * Handle a streaming execute request.
315
258
  */
316
- async chat(request) {
317
- if (this._chatHandler === null) {
318
- throw new Error(`No chat handler registered for agent '${this._name}'`);
259
+ async *executeStream(request) {
260
+ if (this._executeStreamHandler === null) {
261
+ throw new Error(`No streaming execute handler registered for agent '${this._name}'`);
319
262
  }
320
- return this._chatHandler(request);
263
+ yield* this._executeStreamHandler(request);
321
264
  }
322
- /**
323
- * Handle a streaming invoke request.
324
- */
325
- async *invokeStream(request) {
326
- if (this._invokeStreamHandler === null) {
327
- throw new Error(`No streaming invoke handler registered for agent '${this._name}'`);
328
- }
329
- yield* this._invokeStreamHandler(request);
265
+ }
266
+ /**
267
+ * Detect if a function is an async generator function.
268
+ */
269
+ function isAsyncGeneratorFunction(fn) {
270
+ return fn?.constructor?.name === 'AsyncGeneratorFunction';
271
+ }
272
+ /**
273
+ * Wrap output schema to match the full response structure based on responseKeys.
274
+ *
275
+ * If responseKeys = ["output"], wraps the schema as { output: <schema> }
276
+ * If responseKeys = ["message"], wraps the schema as { message: <schema> }
277
+ * If responseKeys = ["message", "output"], wraps as { message: <schema>, output: <schema> }
278
+ *
279
+ * @param outputSchema - The schema for the return value (or undefined)
280
+ * @param responseKeys - List of top-level response keys
281
+ * @returns Wrapped schema describing the full response object, or undefined if outputSchema is undefined
282
+ */
283
+ function wrapOutputSchemaForResponseKeys(outputSchema, responseKeys) {
284
+ if (outputSchema === undefined || responseKeys.length === 0) {
285
+ return undefined;
330
286
  }
331
- /**
332
- * Handle a streaming chat request.
333
- */
334
- async *chatStream(request) {
335
- if (this._chatStreamHandler === null) {
336
- throw new Error(`No streaming chat handler registered for agent '${this._name}'`);
337
- }
338
- yield* this._chatStreamHandler(request);
287
+ // If single response key, wrap the output schema
288
+ if (responseKeys.length === 1) {
289
+ return {
290
+ type: 'object',
291
+ properties: { [responseKeys[0]]: outputSchema },
292
+ required: responseKeys,
293
+ };
294
+ }
295
+ // Multiple response keys - need to split the output schema
296
+ // For now, assume the output schema describes the first key's value
297
+ // and other keys are optional/unknown
298
+ const properties = { [responseKeys[0]]: outputSchema };
299
+ const required = [responseKeys[0]];
300
+ // For additional keys, we don't know their schema, so mark as optional
301
+ // Users can override via metadata if they need full schema
302
+ for (const key of responseKeys.slice(1)) {
303
+ properties[key] = { type: 'object' }; // Placeholder - should be overridden
304
+ }
305
+ return {
306
+ type: 'object',
307
+ properties,
308
+ required,
309
+ };
310
+ }
311
+ /**
312
+ * Create an agent from a configuration object.
313
+ *
314
+ * By default, agents expect `{ prompt: string }` in the request body and
315
+ * return `{ output: ... }`. You can customize by providing `parameters`.
316
+ *
317
+ * @example
318
+ * ```typescript
319
+ * // Simple agent with default parameters
320
+ * // Request: { prompt: 'Hello world' }
321
+ * // Response: { output: 'You said: Hello world' }
322
+ * const echo = agent('echo', {
323
+ * description: 'Echo the prompt',
324
+ * execute: async ({ prompt }) => `You said: ${prompt}`,
325
+ * });
326
+ *
327
+ * // Agent with custom parameters
328
+ * // Request: { a: 1, b: 2 }
329
+ * // Response: { output: 3 }
330
+ * const calculator = agent('calculator', {
331
+ * description: 'Add two numbers',
332
+ * parameters: {
333
+ * type: 'object',
334
+ * properties: { a: { type: 'number' }, b: { type: 'number' } },
335
+ * required: ['a', 'b'],
336
+ * },
337
+ * execute: async ({ a, b }) => (a as number) + (b as number),
338
+ * });
339
+ *
340
+ * // Streaming agent (async generator)
341
+ * // Request: { prompt: 'hello world' }
342
+ * // Response: { output: 'hello world ' } (streamed)
343
+ * const streamer = agent('streamer', {
344
+ * description: 'Stream text word by word',
345
+ * execute: async function* ({ prompt }) {
346
+ * for (const word of (prompt as string).split(' ')) {
347
+ * yield word + ' ';
348
+ * }
349
+ * },
350
+ * });
351
+ * ```
352
+ */
353
+ export function agent(name, options) {
354
+ // Use provided parameters or default to { prompt: string }
355
+ const parameters = options.parameters ?? DEFAULT_AGENT_PARAMETERS;
356
+ // Derive requestKeys from parameters.properties
357
+ const requestKeys = Object.keys(parameters.properties);
358
+ // Default responseKeys (can be overridden via metadata)
359
+ const responseKeys = ['content'];
360
+ // Wrap output schema to match responseKeys structure
361
+ const wrappedOutput = wrapOutputSchemaForResponseKeys(options.output, responseKeys);
362
+ // Build metadata (allow metadata override to change responseKeys)
363
+ const baseMetadata = {
364
+ type: 'agent',
365
+ description: options.description,
366
+ parameters,
367
+ requestKeys,
368
+ responseKeys,
369
+ };
370
+ // If metadata override includes responseKeys, re-wrap output schema
371
+ const finalResponseKeys = options.metadata?.responseKeys ?? responseKeys;
372
+ const finalWrappedOutput = options.metadata?.responseKeys !== undefined
373
+ ? wrapOutputSchemaForResponseKeys(options.output, finalResponseKeys)
374
+ : wrappedOutput;
375
+ if (finalWrappedOutput !== undefined) {
376
+ baseMetadata.output = finalWrappedOutput;
377
+ }
378
+ const agentInstance = new Agent(name, {
379
+ metadata: {
380
+ ...baseMetadata,
381
+ ...options.metadata,
382
+ },
383
+ });
384
+ // Detect if execute is an async generator function
385
+ const isStreaming = isAsyncGeneratorFunction(options.execute);
386
+ // Get the response keys from the agent's metadata (allows custom override)
387
+ const getResponseKeys = () => {
388
+ const keys = agentInstance.metadata.responseKeys;
389
+ return keys && keys.length > 0 ? keys : ['content'];
390
+ };
391
+ if (isStreaming) {
392
+ const streamExecute = options.execute;
393
+ // Register streaming execute handler
394
+ agentInstance.onExecuteStream(async function* (request) {
395
+ yield* streamExecute(request.input, request.context);
396
+ });
397
+ // Also register non-streaming handler that collects chunks
398
+ agentInstance.onExecute(async (request) => {
399
+ const chunks = [];
400
+ for await (const chunk of streamExecute(request.input, request.context)) {
401
+ chunks.push(chunk);
402
+ }
403
+ const result = chunks.join('');
404
+ // If result is dict, use as-is; otherwise wrap in first responseKey
405
+ if (typeof result === 'object' && result !== null && !Array.isArray(result)) {
406
+ return result;
407
+ }
408
+ const responseKeys = getResponseKeys();
409
+ return { [responseKeys[0]]: result };
410
+ });
411
+ }
412
+ else {
413
+ const regularExecute = options.execute;
414
+ agentInstance.onExecute(async (request) => {
415
+ const result = await regularExecute(request.input, request.context);
416
+ // If result is dict with all responseKeys, use as-is; otherwise wrap in first responseKey
417
+ const responseKeys = getResponseKeys();
418
+ if (typeof result === 'object' &&
419
+ result !== null &&
420
+ !Array.isArray(result) &&
421
+ responseKeys.every((key) => key in result)) {
422
+ return result;
423
+ }
424
+ return { [responseKeys[0]]: result };
425
+ });
426
+ }
427
+ return agentInstance;
428
+ }
429
+ /**
430
+ * Create a chat agent from a configuration object.
431
+ *
432
+ * This is a convenience factory that creates an agent with a standard chat
433
+ * interface (messages in, message out).
434
+ *
435
+ * Request: `{ messages: [...] }`
436
+ * Response: `{ message: { role: 'assistant', content: '...' } }`
437
+ *
438
+ * @example
439
+ * ```typescript
440
+ * // Non-streaming chat agent
441
+ * // Request: { messages: [{ role: 'user', content: 'hello' }] }
442
+ * // Response: { message: { role: 'assistant', content: 'You said: hello' } }
443
+ * const bot = chatAgent('bot', {
444
+ * description: 'A simple chatbot',
445
+ * execute: async (messages) => {
446
+ * const lastMsg = messages.at(-1)?.content ?? '';
447
+ * return { role: 'assistant', content: `You said: ${lastMsg}` };
448
+ * },
449
+ * });
450
+ *
451
+ * // Streaming chat agent (async generator)
452
+ * const streamingBot = chatAgent('streaming-bot', {
453
+ * description: 'A streaming chatbot',
454
+ * execute: async function* (messages) {
455
+ * yield 'Hello';
456
+ * yield ' ';
457
+ * yield 'world!';
458
+ * },
459
+ * });
460
+ * ```
461
+ */
462
+ export function chatAgent(name, options) {
463
+ // Chat agents have default request/response keys (can be overridden via metadata)
464
+ const requestKeys = ['messages'];
465
+ const responseKeys = ['message'];
466
+ // Define standard chat agent schemas
467
+ const parametersSchema = {
468
+ type: 'object',
469
+ properties: {
470
+ messages: {
471
+ type: 'array',
472
+ items: {
473
+ type: 'object',
474
+ properties: {
475
+ role: { type: 'string' },
476
+ content: { type: 'string' },
477
+ },
478
+ required: ['role', 'content'],
479
+ },
480
+ },
481
+ },
482
+ required: ['messages'],
483
+ };
484
+ // Message schema (the value, not the full response)
485
+ const messageSchema = {
486
+ type: 'object',
487
+ properties: {
488
+ role: { type: 'string' },
489
+ content: { type: 'string' },
490
+ },
491
+ required: ['role', 'content'],
492
+ };
493
+ // Wrap message schema to match responseKeys structure
494
+ const wrappedOutput = wrapOutputSchemaForResponseKeys(messageSchema, responseKeys);
495
+ // Build metadata (allow metadata override to change responseKeys)
496
+ const baseMetadata = {
497
+ type: 'chat_agent',
498
+ description: options.description,
499
+ parameters: parametersSchema,
500
+ requestKeys,
501
+ responseKeys,
502
+ };
503
+ // If metadata override includes responseKeys, re-wrap output schema
504
+ const finalResponseKeys = options.metadata?.responseKeys ?? responseKeys;
505
+ const finalWrappedOutput = options.metadata?.responseKeys !== undefined
506
+ ? wrapOutputSchemaForResponseKeys(messageSchema, finalResponseKeys)
507
+ : wrappedOutput;
508
+ if (finalWrappedOutput !== undefined) {
509
+ baseMetadata.output = finalWrappedOutput;
510
+ }
511
+ const agentInstance = new Agent(name, {
512
+ metadata: {
513
+ ...baseMetadata,
514
+ ...options.metadata,
515
+ },
516
+ });
517
+ // Detect if execute is an async generator function
518
+ const isStreaming = isAsyncGeneratorFunction(options.execute);
519
+ // Get the response keys from the agent's metadata (allows custom override)
520
+ const getResponseKeys = () => {
521
+ const keys = agentInstance.metadata.responseKeys;
522
+ return keys && keys.length > 0 ? keys : ['message'];
523
+ };
524
+ if (isStreaming) {
525
+ const streamExecute = options.execute;
526
+ // Register streaming execute handler
527
+ agentInstance.onExecuteStream(async function* (request) {
528
+ const rawMessages = (request.input.messages ?? []);
529
+ yield* streamExecute(rawMessages, request.context);
530
+ });
531
+ // Also register non-streaming handler that collects chunks
532
+ agentInstance.onExecute(async (request) => {
533
+ const rawMessages = (request.input.messages ?? []);
534
+ const chunks = [];
535
+ for await (const chunk of streamExecute(rawMessages, request.context)) {
536
+ chunks.push(chunk);
537
+ }
538
+ const result = { role: 'assistant', content: chunks.join('') };
539
+ // For chat agents, always wrap in first responseKey (typically "message")
540
+ const responseKeys = getResponseKeys();
541
+ return { [responseKeys[0]]: result };
542
+ });
543
+ }
544
+ else {
545
+ const regularExecute = options.execute;
546
+ agentInstance.onExecute(async (request) => {
547
+ const rawMessages = (request.input.messages ?? []);
548
+ const result = await regularExecute(rawMessages, request.context);
549
+ const responseKeys = getResponseKeys();
550
+ // Check if result is already a full response dict with all responseKeys
551
+ // (This handles cases where responseKeys are overridden and function returns a dict)
552
+ if (typeof result === 'object' &&
553
+ result !== null &&
554
+ !Array.isArray(result) &&
555
+ 'role' in result === false && // Not a Message (Message has 'role' property)
556
+ responseKeys.every((key) => key in result)) {
557
+ return result;
558
+ }
559
+ // Convert Message to dict if needed, then wrap in first responseKey
560
+ const messageDict = typeof result === 'object' && result !== null && 'role' in result && 'content' in result
561
+ ? { role: result.role, content: result.content }
562
+ : result;
563
+ return { [responseKeys[0]]: messageDict };
564
+ });
339
565
  }
566
+ return agentInstance;
340
567
  }
341
568
  //# sourceMappingURL=agent.js.map