@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 +361 -168
- package/dist/agent-adapter.d.ts +4 -9
- package/dist/agent-adapter.d.ts.map +1 -1
- package/dist/agent-adapter.js +3 -13
- package/dist/agent-adapter.js.map +1 -1
- package/dist/agent.d.ts +149 -80
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +377 -150
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +20 -40
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +8 -13
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
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 `
|
|
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 {
|
|
18
|
+
import { agent, chatAgent, serve } from '@reminix/runtime';
|
|
19
19
|
|
|
20
|
-
// Create an agent
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
|
41
|
-
serve({ agents: [
|
|
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}/
|
|
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.
|
|
72
|
+
"version": "0.0.9",
|
|
77
73
|
"language": "typescript",
|
|
78
74
|
"framework": "hono"
|
|
79
75
|
},
|
|
80
76
|
"agents": [
|
|
81
77
|
{
|
|
82
|
-
"name": "
|
|
78
|
+
"name": "calculator",
|
|
83
79
|
"type": "agent",
|
|
84
|
-
"
|
|
85
|
-
"
|
|
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
|
-
###
|
|
140
|
+
### Agent Execute Endpoint
|
|
141
|
+
|
|
142
|
+
`POST /agents/{name}/execute` - Execute an agent.
|
|
101
143
|
|
|
102
|
-
`
|
|
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/
|
|
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
|
-
"
|
|
156
|
+
"content": 8
|
|
119
157
|
}
|
|
120
158
|
```
|
|
121
159
|
|
|
122
|
-
|
|
160
|
+
**Chat agent:**
|
|
123
161
|
|
|
124
|
-
|
|
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/
|
|
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": "
|
|
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
|
-
"
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
"
|
|
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
|
|
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 {
|
|
353
|
+
import { agent, tool, serve } from '@reminix/runtime';
|
|
221
354
|
|
|
222
|
-
const
|
|
223
|
-
|
|
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: [
|
|
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
|
-
###
|
|
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
|
-
|
|
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.
|
|
555
|
+
agent.onExecute(async (request) => {
|
|
320
556
|
return { output: 'Hello!' };
|
|
321
557
|
});
|
|
322
558
|
|
|
323
|
-
|
|
324
|
-
|
|
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
|
-
|
|
334
|
-
yield '{"chunk": "Hi"}';
|
|
335
|
-
});
|
|
565
|
+
serve({ agents: [agent], port: 8080 });
|
|
336
566
|
```
|
|
337
567
|
|
|
338
|
-
|
|
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
|
-
|
|
570
|
+
For programmatic tool creation:
|
|
349
571
|
|
|
350
572
|
```typescript
|
|
351
|
-
|
|
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
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
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
|
-
|
|
367
|
-
Bun.serve({ fetch: agent.toHandler() });
|
|
585
|
+
serve({ tools: [myTool], port: 8080 });
|
|
368
586
|
```
|
|
369
587
|
|
|
370
|
-
###
|
|
588
|
+
### AgentAdapter
|
|
371
589
|
|
|
372
|
-
|
|
590
|
+
For building framework integrations. See the [framework adapter packages](#framework-adapters) for examples.
|
|
373
591
|
|
|
374
592
|
```typescript
|
|
375
|
-
import { AgentAdapter
|
|
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:
|
|
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()
|
|
602
|
+
get name() {
|
|
395
603
|
return this._name;
|
|
396
604
|
}
|
|
397
605
|
|
|
398
|
-
async
|
|
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
|
-
###
|
|
613
|
+
### Serverless Deployment
|
|
614
|
+
|
|
615
|
+
Use `toHandler()` for serverless deployments:
|
|
421
616
|
|
|
422
617
|
```typescript
|
|
423
|
-
|
|
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
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
620
|
+
const myAgent = agent('my-agent', {
|
|
621
|
+
execute: async ({ task }) => `Completed: ${task}`,
|
|
622
|
+
});
|
|
432
623
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
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
|
-
|
|
440
|
-
|
|
441
|
-
|
|
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
|