hybrid 1.2.5 → 1.2.7
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 +40 -141
- package/README.md.old +167 -0
- package/dist/index.cjs +71 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +71 -7
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/server/listen.ts +56 -4
- package/src/server/processor.ts +30 -4
package/README.md
CHANGED
|
@@ -1,167 +1,66 @@
|
|
|
1
|
-
# Hybrid
|
|
2
|
-
|
|
3
|
-
A flexible framework for building AI agents with plugin-based HTTP server extensions.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **AI Agent Core**: Built on AI SDK 5 with streaming and tool support
|
|
8
|
-
- **Plugin System**: Extensible HTTP server with Hono integration
|
|
9
|
-
- **XMTP Integration**: Built-in XMTP messaging capabilities
|
|
10
|
-
- **Blockchain Events**: Ponder integration for blockchain event handling
|
|
11
|
-
- **TypeScript First**: Full type safety and modern TypeScript patterns
|
|
12
|
-
|
|
13
|
-
## Quick Start
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
import { Agent, XMTPPlugin, PonderPlugin } from "hybrid"
|
|
17
|
-
|
|
18
|
-
// Create an agent
|
|
19
|
-
const agent = new Agent({
|
|
20
|
-
name: "my-agent",
|
|
21
|
-
model: "gpt-4",
|
|
22
|
-
instructions: "You are a helpful AI assistant."
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
// Start the server with plugins
|
|
26
|
-
await agent.listen({
|
|
27
|
-
port: "3000",
|
|
28
|
-
filter: async ({ message }) => {
|
|
29
|
-
console.log("Received message:", message)
|
|
30
|
-
return true // Accept all messages
|
|
31
|
-
},
|
|
32
|
-
plugins: [
|
|
33
|
-
XMTPPlugin(),
|
|
34
|
-
PonderPlugin()
|
|
35
|
-
]
|
|
36
|
-
})
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Plugin System
|
|
40
|
-
|
|
41
|
-
The framework uses a plugin-based architecture that allows you to extend the agent's HTTP server with additional functionality.
|
|
42
|
-
|
|
43
|
-
### Built-in Plugins
|
|
44
|
-
|
|
45
|
-
- **XMTPPlugin**: Provides XMTP messaging capabilities
|
|
46
|
-
- **PonderPlugin**: Handles blockchain events via Ponder
|
|
47
|
-
|
|
48
|
-
### Creating Custom Plugins
|
|
49
|
-
|
|
50
|
-
```typescript
|
|
51
|
-
import type { Plugin } from "hybrid"
|
|
52
|
-
import { Hono } from "hono"
|
|
53
|
-
|
|
54
|
-
function MyCustomPlugin(): Plugin {
|
|
55
|
-
return {
|
|
56
|
-
name: "my-custom",
|
|
57
|
-
description: "My custom functionality",
|
|
58
|
-
apply: (app) => {
|
|
59
|
-
app.get("/custom", (c) => c.json({ message: "Hello from custom plugin!" }))
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Use the plugin
|
|
65
|
-
const agent = new Agent({
|
|
66
|
-
name: "my-agent",
|
|
67
|
-
model: "gpt-4",
|
|
68
|
-
instructions: "You are a helpful AI assistant."
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
// Start server with plugins
|
|
72
|
-
await agent.listen({
|
|
73
|
-
port: "3000",
|
|
74
|
-
plugins: [
|
|
75
|
-
XMTPPlugin(),
|
|
76
|
-
PonderPlugin(),
|
|
77
|
-
MyCustomPlugin()
|
|
78
|
-
]
|
|
79
|
-
})
|
|
80
|
-
```
|
|
1
|
+
# Hybrid - Typescript Framework for building commerce-connected AI Agents.
|
|
81
2
|
|
|
82
|
-
|
|
3
|
+
An open-source agent framework for building conversational AI agents on XMTP.
|
|
83
4
|
|
|
84
|
-
|
|
5
|
+
Hybrid makes it easy for developers to create intelligent agents that can understand natural language, process messages, and respond through XMTP's decentralized messaging protocol.
|
|
85
6
|
|
|
86
|
-
|
|
87
|
-
// Register a plugin after agent creation
|
|
88
|
-
agent.use(MyCustomPlugin())
|
|
7
|
+
See [http://hybriddev.com](http://hybrid.dev) for more information.
|
|
89
8
|
|
|
90
|
-
|
|
91
|
-
console.log(`Agent has ${agent.plugins.size} plugins`)
|
|
9
|
+
## 📦 Quickstart
|
|
92
10
|
|
|
93
|
-
|
|
94
|
-
const plugin = agent.plugins.get("my-custom")
|
|
11
|
+
Getting started with Hybrid is simple:
|
|
95
12
|
|
|
96
|
-
|
|
97
|
-
if (agent.plugins.has("xmtp")) {
|
|
98
|
-
console.log("XMTP plugin is registered")
|
|
99
|
-
}
|
|
100
|
-
```
|
|
13
|
+
### 1. Initialize your project
|
|
101
14
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
function MyPlugin(): Plugin {
|
|
108
|
-
return {
|
|
109
|
-
name: "my-plugin",
|
|
110
|
-
description: "My plugin",
|
|
111
|
-
apply: (app, context) => {
|
|
112
|
-
if (context) {
|
|
113
|
-
console.log(`Plugin applied to agent: ${context.agent.name}`)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
app.get("/my-endpoint", (c) => c.json({ message: "Hello!" }))
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
15
|
+
```bash
|
|
16
|
+
npm create hybrid my-agent
|
|
17
|
+
cd my-agent
|
|
120
18
|
```
|
|
121
19
|
|
|
122
|
-
|
|
20
|
+
This creates all the necessary files and configuration for your agent.
|
|
123
21
|
|
|
124
|
-
|
|
22
|
+
### 2. Get your OpenRouter API key
|
|
23
|
+
|
|
24
|
+
Visit [OpenRouter](https://openrouter.ai/keys), create an account and generate an API key
|
|
125
25
|
|
|
126
|
-
|
|
127
|
-
- **Plugin System**: Extensible HTTP server architecture with Hono
|
|
128
|
-
- **Tool System**: AI SDK compatible tool framework
|
|
129
|
-
- **Server**: Hono-based HTTP server with plugin support
|
|
26
|
+
Add it to your `.env` file:
|
|
130
27
|
|
|
131
|
-
|
|
28
|
+
```env
|
|
29
|
+
OPENROUTER_API_KEY=your_openrouter_api_key_here
|
|
30
|
+
```
|
|
132
31
|
|
|
133
|
-
|
|
134
|
-
2. **Application**: When `agent.listen()` is called, all plugins are applied to the Hono app
|
|
135
|
-
3. **Execution**: Plugins can add routes, middleware, and other functionality to the app
|
|
32
|
+
### 3. Generate XMTP keys
|
|
136
33
|
|
|
137
|
-
|
|
34
|
+
```bash
|
|
35
|
+
hybrid keys
|
|
36
|
+
```
|
|
138
37
|
|
|
139
|
-
|
|
38
|
+
or automatically add it to your `.env` file:
|
|
140
39
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
- Custom plugin creation
|
|
145
|
-
- Plugin registry inspection
|
|
146
|
-
- Server startup with plugins
|
|
40
|
+
```bash
|
|
41
|
+
hybrid keys --write
|
|
42
|
+
```
|
|
147
43
|
|
|
148
|
-
|
|
44
|
+
### 4. Register your wallet with XMTP
|
|
149
45
|
|
|
150
46
|
```bash
|
|
151
|
-
|
|
152
|
-
|
|
47
|
+
hybrid register
|
|
48
|
+
```
|
|
153
49
|
|
|
154
|
-
|
|
155
|
-
pnpm build
|
|
50
|
+
This generates secure wallet and encryption keys for your XMTP agent.
|
|
156
51
|
|
|
157
|
-
|
|
158
|
-
pnpm test
|
|
52
|
+
### 5. Register your wallet with XMTP
|
|
159
53
|
|
|
160
|
-
|
|
161
|
-
|
|
54
|
+
```bash
|
|
55
|
+
hybrid register
|
|
162
56
|
```
|
|
163
57
|
|
|
164
|
-
|
|
58
|
+
### 6. Start developing
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
hybrid dev
|
|
62
|
+
```
|
|
165
63
|
|
|
166
|
-
|
|
64
|
+
Your agent will start listening for XMTP messages and you're ready to build!
|
|
167
65
|
|
|
66
|
+
Go to [https://xmtp.chat/dm/](https://xmtp.chat/dm/) and send a message to your agent.
|
package/README.md.old
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Hybrid Agent Framework
|
|
2
|
+
|
|
3
|
+
A flexible framework for building AI agents with plugin-based HTTP server extensions.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **AI Agent Core**: Built on AI SDK 5 with streaming and tool support
|
|
8
|
+
- **Plugin System**: Extensible HTTP server with Hono integration
|
|
9
|
+
- **XMTP Integration**: Built-in XMTP messaging capabilities
|
|
10
|
+
- **Blockchain Events**: Ponder integration for blockchain event handling
|
|
11
|
+
- **TypeScript First**: Full type safety and modern TypeScript patterns
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { Agent, XMTPPlugin, PonderPlugin } from "hybrid"
|
|
17
|
+
|
|
18
|
+
// Create an agent
|
|
19
|
+
const agent = new Agent({
|
|
20
|
+
name: "my-agent",
|
|
21
|
+
model: "gpt-4",
|
|
22
|
+
instructions: "You are a helpful AI assistant."
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
// Start the server with plugins
|
|
26
|
+
await agent.listen({
|
|
27
|
+
port: "3000",
|
|
28
|
+
filter: async ({ message }) => {
|
|
29
|
+
console.log("Received message:", message)
|
|
30
|
+
return true // Accept all messages
|
|
31
|
+
},
|
|
32
|
+
plugins: [
|
|
33
|
+
XMTPPlugin(),
|
|
34
|
+
PonderPlugin()
|
|
35
|
+
]
|
|
36
|
+
})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Plugin System
|
|
40
|
+
|
|
41
|
+
The framework uses a plugin-based architecture that allows you to extend the agent's HTTP server with additional functionality.
|
|
42
|
+
|
|
43
|
+
### Built-in Plugins
|
|
44
|
+
|
|
45
|
+
- **XMTPPlugin**: Provides XMTP messaging capabilities
|
|
46
|
+
- **PonderPlugin**: Handles blockchain events via Ponder
|
|
47
|
+
|
|
48
|
+
### Creating Custom Plugins
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import type { Plugin } from "hybrid"
|
|
52
|
+
import { Hono } from "hono"
|
|
53
|
+
|
|
54
|
+
function MyCustomPlugin(): Plugin {
|
|
55
|
+
return {
|
|
56
|
+
name: "my-custom",
|
|
57
|
+
description: "My custom functionality",
|
|
58
|
+
apply: (app) => {
|
|
59
|
+
app.get("/custom", (c) => c.json({ message: "Hello from custom plugin!" }))
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Use the plugin
|
|
65
|
+
const agent = new Agent({
|
|
66
|
+
name: "my-agent",
|
|
67
|
+
model: "gpt-4",
|
|
68
|
+
instructions: "You are a helpful AI assistant."
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
// Start server with plugins
|
|
72
|
+
await agent.listen({
|
|
73
|
+
port: "3000",
|
|
74
|
+
plugins: [
|
|
75
|
+
XMTPPlugin(),
|
|
76
|
+
PonderPlugin(),
|
|
77
|
+
MyCustomPlugin()
|
|
78
|
+
]
|
|
79
|
+
})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Plugin Registry
|
|
83
|
+
|
|
84
|
+
You can also register plugins dynamically:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
// Register a plugin after agent creation
|
|
88
|
+
agent.use(MyCustomPlugin())
|
|
89
|
+
|
|
90
|
+
// Check registered plugins
|
|
91
|
+
console.log(`Agent has ${agent.plugins.size} plugins`)
|
|
92
|
+
|
|
93
|
+
// Get a specific plugin
|
|
94
|
+
const plugin = agent.plugins.get("my-custom")
|
|
95
|
+
|
|
96
|
+
// Check if a plugin is registered
|
|
97
|
+
if (agent.plugins.has("xmtp")) {
|
|
98
|
+
console.log("XMTP plugin is registered")
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Plugin Context
|
|
103
|
+
|
|
104
|
+
Plugins receive a context object with the agent instance:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
function MyPlugin(): Plugin {
|
|
108
|
+
return {
|
|
109
|
+
name: "my-plugin",
|
|
110
|
+
description: "My plugin",
|
|
111
|
+
apply: (app, context) => {
|
|
112
|
+
if (context) {
|
|
113
|
+
console.log(`Plugin applied to agent: ${context.agent.name}`)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
app.get("/my-endpoint", (c) => c.json({ message: "Hello!" }))
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Architecture
|
|
123
|
+
|
|
124
|
+
The framework consists of several core components:
|
|
125
|
+
|
|
126
|
+
- **Agent**: Main AI agent with streaming and tool support
|
|
127
|
+
- **Plugin System**: Extensible HTTP server architecture with Hono
|
|
128
|
+
- **Tool System**: AI SDK compatible tool framework
|
|
129
|
+
- **Server**: Hono-based HTTP server with plugin support
|
|
130
|
+
|
|
131
|
+
### Plugin Lifecycle
|
|
132
|
+
|
|
133
|
+
1. **Registration**: Plugins are registered during agent creation or via `agent.use()`
|
|
134
|
+
2. **Application**: When `agent.listen()` is called, all plugins are applied to the Hono app
|
|
135
|
+
3. **Execution**: Plugins can add routes, middleware, and other functionality to the app
|
|
136
|
+
|
|
137
|
+
## Examples
|
|
138
|
+
|
|
139
|
+
See the `examples/` directory for complete usage examples:
|
|
140
|
+
|
|
141
|
+
- `plugin-usage.ts`: Comprehensive plugin usage examples
|
|
142
|
+
- Basic plugin registration
|
|
143
|
+
- Dynamic plugin registration
|
|
144
|
+
- Custom plugin creation
|
|
145
|
+
- Plugin registry inspection
|
|
146
|
+
- Server startup with plugins
|
|
147
|
+
|
|
148
|
+
## Development
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# Install dependencies
|
|
152
|
+
pnpm install
|
|
153
|
+
|
|
154
|
+
# Build the package
|
|
155
|
+
pnpm build
|
|
156
|
+
|
|
157
|
+
# Run tests
|
|
158
|
+
pnpm test
|
|
159
|
+
|
|
160
|
+
# Type check
|
|
161
|
+
pnpm typecheck
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
MIT
|
|
167
|
+
|
package/dist/index.cjs
CHANGED
|
@@ -120,8 +120,24 @@ function generateXMTPToolsToken(payload) {
|
|
|
120
120
|
var BG_STARTED = Symbol("BG_STARTED");
|
|
121
121
|
var BG_STATE = Symbol("BG_STATE");
|
|
122
122
|
var BG_STOP = Symbol("BG_STOP");
|
|
123
|
-
function sleep(ms) {
|
|
124
|
-
return new Promise((
|
|
123
|
+
function sleep(ms, signal) {
|
|
124
|
+
return new Promise((resolve, reject) => {
|
|
125
|
+
if (signal?.aborted) {
|
|
126
|
+
reject(new Error("AbortError"));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const timeout = setTimeout(resolve, ms);
|
|
130
|
+
if (signal) {
|
|
131
|
+
signal.addEventListener(
|
|
132
|
+
"abort",
|
|
133
|
+
() => {
|
|
134
|
+
clearTimeout(timeout);
|
|
135
|
+
reject(new Error("AbortError"));
|
|
136
|
+
},
|
|
137
|
+
{ once: true }
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
125
141
|
}
|
|
126
142
|
function createBackgroundMessageProcessor(opts) {
|
|
127
143
|
if (!opts?.agent || !opts?.xmtpClient) {
|
|
@@ -294,10 +310,18 @@ function createBackgroundMessageProcessor(opts) {
|
|
|
294
310
|
);
|
|
295
311
|
}
|
|
296
312
|
}
|
|
297
|
-
|
|
313
|
+
try {
|
|
314
|
+
await sleep(nextDelay, signal);
|
|
315
|
+
} catch (error) {
|
|
316
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
throw error;
|
|
320
|
+
}
|
|
298
321
|
}
|
|
299
322
|
try {
|
|
300
323
|
if (state.listenerRunning) {
|
|
324
|
+
console.log("[XMTP Background] Stopping message listener...");
|
|
301
325
|
await listener.stop();
|
|
302
326
|
}
|
|
303
327
|
} catch (error) {
|
|
@@ -392,11 +416,51 @@ async function listen({
|
|
|
392
416
|
app.notFound((c) => {
|
|
393
417
|
return c.json({ error: "Not found" }, 404);
|
|
394
418
|
});
|
|
395
|
-
(
|
|
396
|
-
|
|
397
|
-
|
|
419
|
+
const httpPort = Number.parseInt(port || "8454");
|
|
420
|
+
const shutdown = async () => {
|
|
421
|
+
console.log("Waiting for graceful termination...");
|
|
422
|
+
try {
|
|
423
|
+
stopBackground();
|
|
424
|
+
} catch (error) {
|
|
425
|
+
console.error("Error stopping background processor:", error);
|
|
426
|
+
}
|
|
427
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
428
|
+
};
|
|
429
|
+
process.once("SIGINT", async () => {
|
|
430
|
+
await shutdown();
|
|
431
|
+
process.exit(0);
|
|
432
|
+
});
|
|
433
|
+
process.once("SIGTERM", async () => {
|
|
434
|
+
await shutdown();
|
|
435
|
+
process.exit(0);
|
|
436
|
+
});
|
|
437
|
+
process.on("uncaughtException", async (error) => {
|
|
438
|
+
console.error("Uncaught exception:", error);
|
|
439
|
+
await shutdown();
|
|
440
|
+
process.exit(1);
|
|
398
441
|
});
|
|
399
|
-
|
|
442
|
+
process.on("unhandledRejection", async (reason) => {
|
|
443
|
+
console.error("Unhandled rejection:", reason);
|
|
444
|
+
await shutdown();
|
|
445
|
+
process.exit(1);
|
|
446
|
+
});
|
|
447
|
+
try {
|
|
448
|
+
(0, import_node_server.serve)({
|
|
449
|
+
fetch: app.fetch,
|
|
450
|
+
port: httpPort
|
|
451
|
+
});
|
|
452
|
+
console.log(`\u2705 XMTP Tools HTTP Server running on port ${httpPort}`);
|
|
453
|
+
} catch (error) {
|
|
454
|
+
if (error.code === "EADDRINUSE") {
|
|
455
|
+
console.error(
|
|
456
|
+
`\u274C Port ${httpPort} is already in use. Please stop the existing server or use a different port.`
|
|
457
|
+
);
|
|
458
|
+
process.exit(1);
|
|
459
|
+
} else {
|
|
460
|
+
console.error("Server error:", error);
|
|
461
|
+
process.exit(1);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
400
464
|
}
|
|
401
465
|
|
|
402
466
|
// src/core/plugin.ts
|