@reminix/runtime 0.0.7 → 0.0.8

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @reminix/runtime
2
2
 
3
- Core runtime package for serving AI agents and tools via REST APIs. Provides the `serve()` function, `Agent` class, `tool()` factory, and `AgentAdapter` for building framework integrations.
3
+ Core runtime package for serving AI agents and tools via REST APIs. Provides the `agent()`, `chatAgent()`, and `tool()` factory functions for building and serving AI agents.
4
4
 
5
5
  Built on [Hono](https://hono.dev) for portability across Node.js, Deno, Bun, and edge runtimes.
6
6
 
@@ -15,30 +15,27 @@ npm install @reminix/runtime
15
15
  ## Quick Start
16
16
 
17
17
  ```typescript
18
- import { serve, Agent } from '@reminix/runtime';
18
+ import { agent, chatAgent, serve } from '@reminix/runtime';
19
19
 
20
- // Create an agent with callbacks
21
- const agent = new Agent('my-agent');
22
-
23
- agent.onInvoke(async (request) => {
24
- const task = (request.input as Record<string, string>).task || 'unknown';
25
- return { output: `Completed: ${task}` };
20
+ // Create an agent for task-oriented operations
21
+ const calculator = agent('calculator', {
22
+ description: 'Add two numbers',
23
+ parameters: {
24
+ type: 'object',
25
+ properties: { a: { type: 'number' }, b: { type: 'number' } },
26
+ required: ['a', 'b'],
27
+ },
28
+ execute: async ({ a, b }) => (a as number) + (b as number),
26
29
  });
27
30
 
28
- agent.onChat(async (request) => {
29
- const userMsg = request.messages[request.messages.length - 1].content;
30
- const response = `You said: ${userMsg}`;
31
- return {
32
- output: response,
33
- messages: [
34
- ...request.messages,
35
- { role: 'assistant', content: response },
36
- ],
37
- };
31
+ // Create a chat agent for conversational interactions
32
+ const assistant = chatAgent('assistant', {
33
+ description: 'A helpful assistant',
34
+ execute: async (messages) => `You said: ${messages.at(-1)?.content}`,
38
35
  });
39
36
 
40
- // Serve the agent
41
- serve({ agents: [agent], port: 8080 });
37
+ // Serve the agents
38
+ serve({ agents: [calculator, assistant], port: 8080 });
42
39
  ```
43
40
 
44
41
  ## How It Works
@@ -49,8 +46,7 @@ The runtime creates a REST server (powered by [Hono](https://hono.dev)) with the
49
46
  |----------|--------|-------------|
50
47
  | `/health` | GET | Health check |
51
48
  | `/info` | GET | Runtime discovery (version, agents, tools) |
52
- | `/agents/{name}/invoke` | POST | Stateless invocation |
53
- | `/agents/{name}/chat` | POST | Conversational chat |
49
+ | `/agents/{name}/execute` | POST | Execute an agent |
54
50
  | `/tools/{name}/execute` | POST | Execute a tool |
55
51
 
56
52
  ### Health Endpoint
@@ -73,16 +69,43 @@ Returns runtime information, available agents, and tools:
73
69
  {
74
70
  "runtime": {
75
71
  "name": "reminix-runtime",
76
- "version": "0.0.7",
72
+ "version": "0.0.8",
77
73
  "language": "typescript",
78
74
  "framework": "hono"
79
75
  },
80
76
  "agents": [
81
77
  {
82
- "name": "my-agent",
78
+ "name": "calculator",
83
79
  "type": "agent",
84
- "invoke": { "streaming": false },
85
- "chat": { "streaming": false }
80
+ "description": "Add two numbers",
81
+ "parameters": {
82
+ "type": "object",
83
+ "properties": { "a": { "type": "number" }, "b": { "type": "number" } },
84
+ "required": ["a", "b"]
85
+ },
86
+ "output": { "type": "number" },
87
+ "requestKeys": ["a", "b"],
88
+ "responseKeys": ["output"],
89
+ "streaming": false
90
+ },
91
+ {
92
+ "name": "assistant",
93
+ "type": "chat_agent",
94
+ "description": "A helpful assistant",
95
+ "parameters": {
96
+ "type": "object",
97
+ "properties": {
98
+ "messages": {
99
+ "type": "array",
100
+ "items": { "type": "object", "properties": { "role": { "type": "string" }, "content": { "type": "string" } }, "required": ["role", "content"] }
101
+ }
102
+ },
103
+ "required": ["messages"]
104
+ },
105
+ "output": { "type": "object" },
106
+ "requestKeys": ["messages"],
107
+ "responseKeys": ["message"],
108
+ "streaming": false
86
109
  }
87
110
  ],
88
111
  "tools": [
@@ -97,39 +120,36 @@ Returns runtime information, available agents, and tools:
97
120
  }
98
121
  ```
99
122
 
100
- ### Invoke Endpoint
123
+ ### Agent Execute Endpoint
124
+
125
+ `POST /agents/{name}/execute` - Execute an agent.
101
126
 
102
- `POST /agents/{name}/invoke` - For stateless operations.
127
+ Request keys are defined by the agent's `parameters` schema. For example, a calculator agent with `parameters: { properties: { a, b } }` expects `a` and `b` at the top level:
103
128
 
129
+ **Task-oriented agent:**
104
130
  ```bash
105
- curl -X POST http://localhost:8080/agents/my-agent/invoke \
131
+ curl -X POST http://localhost:8080/agents/calculator/execute \
106
132
  -H "Content-Type: application/json" \
107
- -d '{
108
- "input": {
109
- "task": "summarize",
110
- "text": "Lorem ipsum..."
111
- }
112
- }'
133
+ -d '{"a": 5, "b": 3}'
113
134
  ```
114
135
 
115
136
  **Response:**
116
137
  ```json
117
138
  {
118
- "output": "Summary: ..."
139
+ "output": 8
119
140
  }
120
141
  ```
121
142
 
122
- ### Chat Endpoint
143
+ **Chat agent:**
123
144
 
124
- `POST /agents/{name}/chat` - For conversational interactions.
145
+ Chat agents expect `messages` at the top level and return `message`:
125
146
 
126
147
  ```bash
127
- curl -X POST http://localhost:8080/agents/my-agent/chat \
148
+ curl -X POST http://localhost:8080/agents/assistant/execute \
128
149
  -H "Content-Type: application/json" \
129
150
  -d '{
130
151
  "messages": [
131
- {"role": "system", "content": "You are helpful"},
132
- {"role": "user", "content": "What is the weather?"}
152
+ {"role": "user", "content": "Hello!"}
133
153
  ]
134
154
  }'
135
155
  ```
@@ -137,17 +157,13 @@ curl -X POST http://localhost:8080/agents/my-agent/chat \
137
157
  **Response:**
138
158
  ```json
139
159
  {
140
- "output": "The weather is 72°F and sunny!",
141
- "messages": [
142
- {"role": "system", "content": "You are helpful"},
143
- {"role": "user", "content": "What is the weather?"},
144
- {"role": "assistant", "content": "The weather is 72°F and sunny!"}
145
- ]
160
+ "message": {
161
+ "role": "assistant",
162
+ "content": "You said: Hello!"
163
+ }
146
164
  }
147
165
  ```
148
166
 
149
- The `output` field contains the assistant's response, while `messages` includes the full conversation history.
150
-
151
167
  ### Tool Execute Endpoint
152
168
 
153
169
  `POST /tools/{name}/execute` - Execute a standalone tool.
@@ -155,11 +171,7 @@ The `output` field contains the assistant's response, while `messages` includes
155
171
  ```bash
156
172
  curl -X POST http://localhost:8080/tools/get_weather/execute \
157
173
  -H "Content-Type: application/json" \
158
- -d '{
159
- "input": {
160
- "location": "San Francisco"
161
- }
162
- }'
174
+ -d '{"location": "San Francisco"}'
163
175
  ```
164
176
 
165
177
  **Response:**
@@ -169,9 +181,119 @@ curl -X POST http://localhost:8080/tools/get_weather/execute \
169
181
  }
170
182
  ```
171
183
 
184
+ ## Agents
185
+
186
+ Agents handle requests via the `/agents/{name}/execute` endpoint.
187
+
188
+ ### Task-Oriented Agent
189
+
190
+ Use `agent()` for task-oriented agents that take structured input and return output:
191
+
192
+ ```typescript
193
+ import { agent, serve } from '@reminix/runtime';
194
+
195
+ const calculator = agent('calculator', {
196
+ description: 'Add two numbers',
197
+ parameters: {
198
+ type: 'object',
199
+ properties: {
200
+ a: { type: 'number' },
201
+ b: { type: 'number' },
202
+ },
203
+ required: ['a', 'b'],
204
+ },
205
+ execute: async ({ a, b }) => (a as number) + (b as number),
206
+ });
207
+
208
+ const textProcessor = agent('text-processor', {
209
+ description: 'Process text in various ways',
210
+ parameters: {
211
+ type: 'object',
212
+ properties: {
213
+ text: { type: 'string' },
214
+ operation: { type: 'string', enum: ['uppercase', 'lowercase'] },
215
+ },
216
+ required: ['text'],
217
+ },
218
+ execute: async ({ text, operation }) => {
219
+ const t = text as string;
220
+ return operation === 'uppercase' ? t.toUpperCase() : t.toLowerCase();
221
+ },
222
+ });
223
+
224
+ serve({ agents: [calculator, textProcessor], port: 8080 });
225
+ ```
226
+
227
+ ### Chat Agent
228
+
229
+ Use `chatAgent()` for conversational agents that handle message history:
230
+
231
+ ```typescript
232
+ import { chatAgent, serve } from '@reminix/runtime';
233
+
234
+ const assistant = chatAgent('assistant', {
235
+ description: 'A helpful assistant',
236
+ execute: async (messages) => {
237
+ const lastMsg = messages.at(-1)?.content ?? '';
238
+ return `You said: ${lastMsg}`;
239
+ },
240
+ });
241
+
242
+ // With context support
243
+ const contextualBot = chatAgent('contextual-bot', {
244
+ description: 'Bot with context awareness',
245
+ execute: async (messages, context) => {
246
+ const userId = context?.user_id ?? 'unknown';
247
+ return `Hello user ${userId}!`;
248
+ },
249
+ });
250
+
251
+ serve({ agents: [assistant, contextualBot], port: 8080 });
252
+ ```
253
+
254
+ ### Streaming
255
+
256
+ Both factories support streaming via async generators. When you use an async generator function, the agent automatically supports streaming:
257
+
258
+ ```typescript
259
+ import { agent, chatAgent, serve } from '@reminix/runtime';
260
+
261
+ // Streaming task agent
262
+ const streamer = agent('streamer', {
263
+ description: 'Stream text word by word',
264
+ parameters: {
265
+ type: 'object',
266
+ properties: { text: { type: 'string' } },
267
+ required: ['text'],
268
+ },
269
+ execute: async function* ({ text }) {
270
+ for (const word of (text as string).split(' ')) {
271
+ yield word + ' ';
272
+ }
273
+ },
274
+ });
275
+
276
+ // Streaming chat agent
277
+ const streamingAssistant = chatAgent('streaming-assistant', {
278
+ description: 'Stream responses token by token',
279
+ execute: async function* (messages) {
280
+ const response = `You said: ${messages.at(-1)?.content}`;
281
+ for (const char of response) {
282
+ yield char;
283
+ }
284
+ },
285
+ });
286
+
287
+ serve({ agents: [streamer, streamingAssistant], port: 8080 });
288
+ ```
289
+
290
+ For streaming agents:
291
+ - `stream: true` in the request → chunks are sent via SSE
292
+ - `stream: false` in the request → chunks are collected and returned as a single response
293
+
172
294
  ## Tools
173
295
 
174
- Tools are standalone functions that can be served via the runtime. They're useful for exposing utility functions, external API integrations, or any reusable logic.
296
+ Tools are standalone functions served via `/tools/{name}/execute`. They're useful for exposing utility functions, external API integrations, or any reusable logic.
175
297
 
176
298
  ### Creating Tools
177
299
 
@@ -190,54 +312,50 @@ const getWeather = tool('get_weather', {
190
312
  },
191
313
  required: ['location'],
192
314
  },
193
- // Optional: define output schema for documentation and type inference
194
315
  output: {
195
316
  type: 'object',
196
317
  properties: {
197
318
  temp: { type: 'number' },
198
319
  condition: { type: 'string' },
199
- location: { type: 'string' },
200
320
  },
201
321
  },
202
322
  execute: async (input) => {
203
323
  const location = input.location as string;
204
- // Call weather API...
205
324
  return { temp: 72, condition: 'sunny', location };
206
325
  },
207
326
  });
208
327
 
209
- // Serve tools (with or without agents)
210
328
  serve({ tools: [getWeather], port: 8080 });
211
329
  ```
212
330
 
213
- The optional `output` property defines the JSON Schema for the tool's return value. This is included in the `/info` endpoint for documentation and enables better type inference for clients.
214
-
215
331
  ### Serving Agents and Tools Together
216
332
 
217
333
  You can serve both agents and tools from the same runtime:
218
334
 
219
335
  ```typescript
220
- import { Agent, tool, serve } from '@reminix/runtime';
336
+ import { agent, tool, serve } from '@reminix/runtime';
221
337
 
222
- const agent = new Agent('my-agent');
223
- agent.onInvoke(async (req) => ({ output: 'Hello!' }));
338
+ const summarizer = agent('summarizer', {
339
+ description: 'Summarize text',
340
+ parameters: {
341
+ type: 'object',
342
+ properties: { text: { type: 'string' } },
343
+ required: ['text'],
344
+ },
345
+ execute: async ({ text }) => (text as string).slice(0, 100) + '...',
346
+ });
224
347
 
225
348
  const calculator = tool('calculate', {
226
349
  description: 'Perform basic math operations',
227
350
  parameters: {
228
351
  type: 'object',
229
- properties: {
230
- expression: { type: 'string', description: 'Math expression to evaluate' },
231
- },
352
+ properties: { expression: { type: 'string' } },
232
353
  required: ['expression'],
233
354
  },
234
- execute: async (input) => {
235
- const expr = input.expression as string;
236
- return { result: eval(expr) }; // Note: use a safe evaluator in production
237
- },
355
+ execute: async (input) => ({ result: eval(input.expression as string) }),
238
356
  });
239
357
 
240
- serve({ agents: [agent], tools: [calculator], port: 8080 });
358
+ serve({ agents: [summarizer], tools: [calculator], port: 8080 });
241
359
  ```
242
360
 
243
361
  ## Framework Adapters
@@ -278,6 +396,77 @@ const app = createApp({ agents: [myAgent], tools: [myTool] });
278
396
  // Use with any runtime: Node.js, Deno, Bun, Cloudflare Workers, etc.
279
397
  ```
280
398
 
399
+ ### `agent(name, options)`
400
+
401
+ Factory function to create a task-oriented agent.
402
+
403
+ | Parameter | Type | Description |
404
+ |-----------|------|-------------|
405
+ | `name` | `string` | Unique identifier for the agent |
406
+ | `options.description` | `string` | Human-readable description |
407
+ | `options.parameters` | `object` | JSON Schema for input parameters |
408
+ | `options.output` | `object` | Optional JSON Schema for output |
409
+ | `options.execute` | `function` | Async function or async generator to execute |
410
+
411
+ ```typescript
412
+ import { agent } from '@reminix/runtime';
413
+
414
+ // Regular agent
415
+ const myAgent = agent('my-agent', {
416
+ description: 'Does something useful',
417
+ parameters: {
418
+ type: 'object',
419
+ properties: { input: { type: 'string' } },
420
+ required: ['input'],
421
+ },
422
+ execute: async ({ input }) => ({ result: input }),
423
+ });
424
+
425
+ // Streaming agent
426
+ const streamingAgent = agent('streaming-agent', {
427
+ description: 'Streams output',
428
+ parameters: { type: 'object', properties: { text: { type: 'string' } }, required: ['text'] },
429
+ execute: async function* ({ text }) {
430
+ for (const word of (text as string).split(' ')) {
431
+ yield word + ' ';
432
+ }
433
+ },
434
+ });
435
+ ```
436
+
437
+ ### `chatAgent(name, options)`
438
+
439
+ Factory function to create a chat agent.
440
+
441
+ | Parameter | Type | Description |
442
+ |-----------|------|-------------|
443
+ | `name` | `string` | Unique identifier for the agent |
444
+ | `options.description` | `string` | Human-readable description |
445
+ | `options.execute` | `function` | Async function or async generator receiving messages |
446
+
447
+ ```typescript
448
+ import { chatAgent } from '@reminix/runtime';
449
+
450
+ // Regular chat agent
451
+ const bot = chatAgent('bot', {
452
+ description: 'A simple bot',
453
+ execute: async (messages) => `You said: ${messages.at(-1)?.content}`,
454
+ });
455
+
456
+ // With context
457
+ const contextBot = chatAgent('context-bot', {
458
+ execute: async (messages, context) => `Hello ${context?.user_id}!`,
459
+ });
460
+
461
+ // Streaming chat agent
462
+ const streamingBot = chatAgent('streaming-bot', {
463
+ execute: async function* (messages) {
464
+ yield 'Hello';
465
+ yield ' world!';
466
+ },
467
+ });
468
+ ```
469
+
281
470
  ### `tool(name, options)`
282
471
 
283
472
  Factory function to create a tool.
@@ -287,6 +476,7 @@ Factory function to create a tool.
287
476
  | `name` | `string` | Unique identifier for the tool |
288
477
  | `options.description` | `string` | Human-readable description |
289
478
  | `options.parameters` | `object` | JSON Schema for input parameters |
479
+ | `options.output` | `object` | Optional JSON Schema for output |
290
480
  | `options.execute` | `function` | Async function to execute when called |
291
481
 
292
482
  ```typescript
@@ -296,150 +486,136 @@ const myTool = tool('my_tool', {
296
486
  description: 'Does something useful',
297
487
  parameters: {
298
488
  type: 'object',
299
- properties: {
300
- input: { type: 'string' },
301
- },
489
+ properties: { input: { type: 'string' } },
302
490
  required: ['input'],
303
491
  },
304
- execute: async (input) => {
305
- return { result: input.input };
306
- },
492
+ execute: async (input) => ({ result: input.input }),
307
493
  });
308
494
  ```
309
495
 
310
- ### `Agent`
496
+ ### Request/Response Types
497
+
498
+ ```typescript
499
+ // Request: top-level keys based on agent's requestKeys (derived from parameters)
500
+ // For a calculator agent with parameters { a: number, b: number }:
501
+ interface CalculatorRequest {
502
+ a: number; // Top-level key from parameters
503
+ b: number; // Top-level key from parameters
504
+ stream?: boolean; // Whether to stream the response
505
+ context?: Record<string, unknown>; // Optional metadata
506
+ }
311
507
 
312
- Concrete class for building agents with callbacks.
508
+ // For a chat agent:
509
+ interface ChatRequest {
510
+ messages: Message[]; // Top-level key (requestKeys: ['messages'])
511
+ stream?: boolean;
512
+ context?: Record<string, unknown>;
513
+ }
514
+
515
+ // Response: keys based on agent's responseKeys
516
+ // Regular agent (responseKeys: ['output']):
517
+ interface AgentResponse {
518
+ output: unknown;
519
+ }
520
+
521
+ // Chat agent (responseKeys: ['message']):
522
+ interface ChatResponse {
523
+ message: { role: string; content: string };
524
+ }
525
+ ```
526
+
527
+ ## Advanced
528
+
529
+ ### Agent Class
530
+
531
+ For more control, you can use the `Agent` class directly:
313
532
 
314
533
  ```typescript
315
- import { Agent } from '@reminix/runtime';
534
+ import { Agent, serve } from '@reminix/runtime';
316
535
 
317
536
  const agent = new Agent('my-agent', { metadata: { version: '1.0' } });
318
537
 
319
- agent.onInvoke(async (request) => {
538
+ agent.onExecute(async (request) => {
320
539
  return { output: 'Hello!' };
321
540
  });
322
541
 
323
- agent.onChat(async (request) => {
324
- return { output: 'Hi!', messages: [...] };
325
- });
326
-
327
- // Optional: streaming handlers
328
- agent.onInvokeStream(async function* (request) {
329
- yield '{"chunk": "Hello"}';
330
- yield '{"chunk": " world!"}';
542
+ // Optional: streaming handler
543
+ agent.onExecuteStream(async function* (request) {
544
+ yield 'Hello';
545
+ yield ' world!';
331
546
  });
332
547
 
333
- agent.onChatStream(async function* (request) {
334
- yield '{"chunk": "Hi"}';
335
- });
548
+ serve({ agents: [agent], port: 8080 });
336
549
  ```
337
550
 
338
- | Method | Description |
339
- |--------|-------------|
340
- | `onInvoke(fn)` | Register invoke handler, returns `this` for chaining |
341
- | `onChat(fn)` | Register chat handler, returns `this` for chaining |
342
- | `onInvokeStream(fn)` | Register streaming invoke handler |
343
- | `onChatStream(fn)` | Register streaming chat handler |
344
- | `toHandler()` | Returns a web-standard fetch handler for serverless |
345
-
346
- ### `agent.toHandler()`
551
+ ### Tool Class
347
552
 
348
- Returns a web-standard `(Request) => Promise<Response>` handler for serverless deployments.
553
+ For programmatic tool creation:
349
554
 
350
555
  ```typescript
351
- // Vercel Edge Function
352
- import { Agent } from '@reminix/runtime';
353
-
354
- const agent = new Agent('my-agent');
355
- agent.onInvoke(async (req) => ({ output: 'Hello!' }));
556
+ import { Tool, serve } from '@reminix/runtime';
356
557
 
357
- export const POST = agent.toHandler();
358
- export const GET = agent.toHandler();
359
-
360
- // Cloudflare Workers
361
- export default { fetch: agent.toHandler() };
362
-
363
- // Deno Deploy
364
- Deno.serve(agent.toHandler());
558
+ const myTool = new Tool('get_weather', {
559
+ description: 'Get weather for a location',
560
+ parameters: {
561
+ type: 'object',
562
+ properties: { location: { type: 'string' } },
563
+ required: ['location'],
564
+ },
565
+ execute: async (input) => ({ temp: 72, location: input.location }),
566
+ });
365
567
 
366
- // Bun
367
- Bun.serve({ fetch: agent.toHandler() });
568
+ serve({ tools: [myTool], port: 8080 });
368
569
  ```
369
570
 
370
- ### `AgentAdapter`
571
+ ### AgentAdapter
371
572
 
372
- Abstract base class for framework adapters. Use this when wrapping an existing AI framework.
573
+ For building framework integrations. See the [framework adapter packages](#framework-adapters) for examples.
373
574
 
374
575
  ```typescript
375
- import { AgentAdapter, InvokeRequest, InvokeResponse, ChatRequest, ChatResponse } from '@reminix/runtime';
576
+ import { AgentAdapter } from '@reminix/runtime';
376
577
 
377
578
  class MyFrameworkAdapter extends AgentAdapter {
378
- // Adapter name shown in /info endpoint
379
579
  static adapterName = 'my-framework';
380
-
381
- // AgentAdapter defaults both to true; override if your adapter doesn't support streaming
382
- // override readonly invokeStreaming = false;
383
- // override readonly chatStreaming = false;
384
-
385
- private client: MyFrameworkClient;
386
- private _name: string;
387
580
 
388
- constructor(client: MyFrameworkClient, name = 'my-framework') {
581
+ constructor(private client: MyClient, private _name = 'my-framework') {
389
582
  super();
390
- this.client = client;
391
- this._name = name;
392
583
  }
393
584
 
394
- get name(): string {
585
+ get name() {
395
586
  return this._name;
396
587
  }
397
588
 
398
- async invoke(request: InvokeRequest): Promise<InvokeResponse> {
399
- // Pass input to your framework
589
+ async execute(request) {
400
590
  const result = await this.client.run(request.input);
401
591
  return { output: result };
402
592
  }
403
-
404
- async chat(request: ChatRequest): Promise<ChatResponse> {
405
- // Convert messages and call your framework
406
- const result = await this.client.chat(request.messages);
407
- return {
408
- output: result,
409
- messages: [...request.messages, { role: 'assistant', content: result }],
410
- };
411
- }
412
- }
413
-
414
- // Optional: provide a wrap() factory function
415
- export function wrap(client: MyFrameworkClient, name = 'my-framework'): MyFrameworkAdapter {
416
- return new MyFrameworkAdapter(client, name);
417
593
  }
418
594
  ```
419
595
 
420
- ### Request/Response Types
596
+ ### Serverless Deployment
597
+
598
+ Use `toHandler()` for serverless deployments:
421
599
 
422
600
  ```typescript
423
- interface InvokeRequest {
424
- input: Record<string, unknown>; // Arbitrary input for task execution
425
- stream?: boolean; // Whether to stream the response
426
- context?: Record<string, unknown>; // Optional metadata
427
- }
601
+ import { agent } from '@reminix/runtime';
428
602
 
429
- interface InvokeResponse {
430
- output: unknown; // The result (can be any type)
431
- }
603
+ const myAgent = agent('my-agent', {
604
+ execute: async ({ task }) => `Completed: ${task}`,
605
+ });
432
606
 
433
- interface ChatRequest {
434
- messages: Message[]; // Conversation history
435
- stream?: boolean; // Whether to stream the response
436
- context?: Record<string, unknown>; // Optional metadata
437
- }
607
+ // Vercel Edge Function
608
+ export const POST = myAgent.toHandler();
609
+ export const GET = myAgent.toHandler();
438
610
 
439
- interface ChatResponse {
440
- output: string; // The final answer
441
- messages: Message[]; // Full execution history
442
- }
611
+ // Cloudflare Workers
612
+ export default { fetch: myAgent.toHandler() };
613
+
614
+ // Deno Deploy
615
+ Deno.serve(myAgent.toHandler());
616
+
617
+ // Bun
618
+ Bun.serve({ fetch: myAgent.toHandler() });
443
619
  ```
444
620
 
445
621
  ## Deployment