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