hono-agents 0.0.0 → 0.0.5
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 +104 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -7
- package/src/index.ts +94 -0
package/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# hono-agents
|
|
2
|
+
|
|
3
|
+
🔥 Hono ⨉ 🧠 Cloudflare Agents
|
|
4
|
+
|
|
5
|
+
Add intelligent, stateful AI agents to your Hono app. Create persistent AI agents that can think, communicate, and evolve over time, all integrated seamlessly with your Hono application.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install hono-agents hono agents-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { Hono } from "hono";
|
|
17
|
+
import { agentsMiddleware } from "hono-agents";
|
|
18
|
+
import { Agent } from "agents-sdk";
|
|
19
|
+
|
|
20
|
+
// Define your agent classes
|
|
21
|
+
export class ChatAgent extends Agent {
|
|
22
|
+
async onRequest(request) {
|
|
23
|
+
return new Response("Ready to assist with chat.");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class AssistantAgent extends Agent {
|
|
28
|
+
async onRequest(request) {
|
|
29
|
+
return new Response("I'm your AI assistant.");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Basic setup
|
|
34
|
+
const app = new Hono();
|
|
35
|
+
app.use("*", agentsMiddleware());
|
|
36
|
+
|
|
37
|
+
// or with authentication
|
|
38
|
+
app.use(
|
|
39
|
+
"*",
|
|
40
|
+
agentsMiddleware({
|
|
41
|
+
options: {
|
|
42
|
+
onBeforeConnect: async (req) => {
|
|
43
|
+
const token = req.headers.get("authorization");
|
|
44
|
+
// validate token
|
|
45
|
+
if (!token) return new Response("Unauthorized", { status: 401 });
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
// With error handling
|
|
52
|
+
app.use("*", agentsMiddleware({ onError: (error) => console.error(error) }));
|
|
53
|
+
|
|
54
|
+
// With custom routing
|
|
55
|
+
app.use(
|
|
56
|
+
"*",
|
|
57
|
+
agentsMiddleware({
|
|
58
|
+
options: {
|
|
59
|
+
prefix: "/agents", // Handles /agents/* routes only
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
export default app;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Configuration
|
|
68
|
+
|
|
69
|
+
To properly configure your Cloudflare Workers project to use agents, update your `wrangler.toml` file:
|
|
70
|
+
|
|
71
|
+
```toml
|
|
72
|
+
[durable_objects]
|
|
73
|
+
bindings = [
|
|
74
|
+
{ name = "ChatAgent", class_name = "ChatAgent" },
|
|
75
|
+
{ name = "AssistantAgent", class_name = "AssistantAgent" }
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
[[migrations]]
|
|
79
|
+
tag = "v1"
|
|
80
|
+
new_sqlite_classes = ["ChatAgent", "AssistantAgent"]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## How It Works
|
|
84
|
+
|
|
85
|
+
The `agentsMiddleware` function:
|
|
86
|
+
|
|
87
|
+
1. Detects whether the incoming request is a WebSocket connection or standard HTTP request
|
|
88
|
+
2. Routes the request to the appropriate agent
|
|
89
|
+
3. Handles WebSocket upgrades for persistent connections
|
|
90
|
+
4. Provides error handling and custom routing options
|
|
91
|
+
|
|
92
|
+
Agents can:
|
|
93
|
+
|
|
94
|
+
- Maintain state across requests
|
|
95
|
+
- Handle both HTTP and WebSocket connections
|
|
96
|
+
- Schedule tasks for future execution
|
|
97
|
+
- Communicate with AI services
|
|
98
|
+
- Integrate seamlessly with React applications
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
Learn more about Cloudflare Agents at https://www.npmjs.com/package/agents-sdk
|
|
103
|
+
|
|
104
|
+
ISC
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as hono from "hono";
|
|
2
|
+
import { Env } from "hono";
|
|
3
|
+
import { AgentOptions } from "agents-sdk";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Configuration options for the Cloudflare Agents middleware
|
|
7
|
+
*/
|
|
8
|
+
type AgentMiddlewareContext<E extends Env> = {
|
|
9
|
+
/** Cloudflare Agents-specific configuration options */
|
|
10
|
+
options?: AgentOptions<E>;
|
|
11
|
+
/** Optional error handler for caught errors */
|
|
12
|
+
onError?: (error: Error) => void;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Creates a middleware for handling Cloudflare Agents WebSocket and HTTP requests
|
|
16
|
+
* Processes both WebSocket upgrades and standard HTTP requests, delegating them to Cloudflare Agents
|
|
17
|
+
*/
|
|
18
|
+
declare function agentsMiddleware<E extends Env = Env>(
|
|
19
|
+
ctx?: AgentMiddlewareContext<E>
|
|
20
|
+
): hono.MiddlewareHandler<any, string, {}>;
|
|
21
|
+
|
|
22
|
+
export { agentsMiddleware };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { env } from "hono/adapter";
|
|
3
|
+
import { createMiddleware } from "hono/factory";
|
|
4
|
+
import { routeAgentRequest } from "agents-sdk";
|
|
5
|
+
function agentsMiddleware(ctx) {
|
|
6
|
+
return createMiddleware(async (c, next) => {
|
|
7
|
+
try {
|
|
8
|
+
const handler = isWebSocketUpgrade(c) ? handleWebSocketUpgrade : handleHttpRequest;
|
|
9
|
+
const response = await handler(c, ctx?.options);
|
|
10
|
+
return response === null ? await next() : response;
|
|
11
|
+
} catch (error) {
|
|
12
|
+
if (ctx?.onError) {
|
|
13
|
+
ctx.onError(error);
|
|
14
|
+
return next();
|
|
15
|
+
}
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function isWebSocketUpgrade(c) {
|
|
21
|
+
return c.req.header("upgrade")?.toLowerCase() === "websocket";
|
|
22
|
+
}
|
|
23
|
+
function createRequestFromContext(c) {
|
|
24
|
+
return new Request(c.req.url, {
|
|
25
|
+
method: c.req.method,
|
|
26
|
+
headers: c.req.header(),
|
|
27
|
+
body: c.req.raw.body
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async function handleWebSocketUpgrade(c, options) {
|
|
31
|
+
const req = createRequestFromContext(c);
|
|
32
|
+
const response = await routeAgentRequest(req, env(c), options);
|
|
33
|
+
if (!response?.webSocket) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return new Response(null, {
|
|
37
|
+
status: 101,
|
|
38
|
+
webSocket: response.webSocket
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
async function handleHttpRequest(c, options) {
|
|
42
|
+
const req = createRequestFromContext(c);
|
|
43
|
+
return routeAgentRequest(req, env(c), options);
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
agentsMiddleware
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { env } from \"hono/adapter\";\nimport { createMiddleware } from \"hono/factory\";\nimport { routeAgentRequest } from \"agents-sdk\";\n\nimport type { Context, Env } from \"hono\";\nimport type { AgentOptions } from \"agents-sdk\";\n\n/**\n * Configuration options for the Cloudflare Agents middleware\n */\ntype AgentMiddlewareContext<E extends Env> = {\n /** Cloudflare Agents-specific configuration options */\n options?: AgentOptions<E>;\n /** Optional error handler for caught errors */\n onError?: (error: Error) => void;\n};\n\n/**\n * Creates a middleware for handling Cloudflare Agents WebSocket and HTTP requests\n * Processes both WebSocket upgrades and standard HTTP requests, delegating them to Cloudflare Agents\n */\nexport function agentsMiddleware<E extends Env = Env>(\n ctx?: AgentMiddlewareContext<E>\n) {\n return createMiddleware(async (c, next) => {\n try {\n const handler = isWebSocketUpgrade(c)\n ? handleWebSocketUpgrade\n : handleHttpRequest;\n const response = await handler(c, ctx?.options);\n\n return response === null ? await next() : response;\n } catch (error) {\n if (ctx?.onError) {\n ctx.onError(error as Error);\n return next();\n }\n throw error;\n }\n });\n}\n\n/**\n * Checks if the incoming request is a WebSocket upgrade request\n * Looks for the 'upgrade' header with a value of 'websocket' (case-insensitive)\n */\nfunction isWebSocketUpgrade(c: Context): boolean {\n return c.req.header(\"upgrade\")?.toLowerCase() === \"websocket\";\n}\n\n/**\n * Creates a new Request object from the Hono context\n * Preserves the original request's URL, method, headers, and body\n */\nfunction createRequestFromContext(c: Context) {\n return new Request(c.req.url, {\n method: c.req.method,\n headers: c.req.header(),\n body: c.req.raw.body,\n });\n}\n\n/**\n * Handles WebSocket upgrade requests\n * Returns a WebSocket upgrade response if successful, null otherwise\n */\nasync function handleWebSocketUpgrade<E extends Env>(\n c: Context<E>,\n options?: AgentOptions<E>\n) {\n const req = createRequestFromContext(c);\n const response = await routeAgentRequest(req, env(c), options);\n\n if (!response?.webSocket) {\n return null;\n }\n\n return new Response(null, {\n status: 101,\n webSocket: response.webSocket,\n });\n}\n\n/**\n * Handles standard HTTP requests\n * Forwards the request to Cloudflare Agents and returns the response\n */\nasync function handleHttpRequest<E extends Env>(\n c: Context<E>,\n options?: AgentOptions<E>\n) {\n const req = createRequestFromContext(c);\n return routeAgentRequest(req, env(c), options);\n}\n"],"mappings":";AAAA,SAAS,WAAW;AACpB,SAAS,wBAAwB;AACjC,SAAS,yBAAyB;AAmB3B,SAAS,iBACd,KACA;AACA,SAAO,iBAAiB,OAAO,GAAG,SAAS;AACzC,QAAI;AACF,YAAM,UAAU,mBAAmB,CAAC,IAChC,yBACA;AACJ,YAAM,WAAW,MAAM,QAAQ,GAAG,KAAK,OAAO;AAE9C,aAAO,aAAa,OAAO,MAAM,KAAK,IAAI;AAAA,IAC5C,SAAS,OAAO;AACd,UAAI,KAAK,SAAS;AAChB,YAAI,QAAQ,KAAc;AAC1B,eAAO,KAAK;AAAA,MACd;AACA,YAAM;AAAA,IACR;AAAA,EACF,CAAC;AACH;AAMA,SAAS,mBAAmB,GAAqB;AAC/C,SAAO,EAAE,IAAI,OAAO,SAAS,GAAG,YAAY,MAAM;AACpD;AAMA,SAAS,yBAAyB,GAAY;AAC5C,SAAO,IAAI,QAAQ,EAAE,IAAI,KAAK;AAAA,IAC5B,QAAQ,EAAE,IAAI;AAAA,IACd,SAAS,EAAE,IAAI,OAAO;AAAA,IACtB,MAAM,EAAE,IAAI,IAAI;AAAA,EAClB,CAAC;AACH;AAMA,eAAe,uBACb,GACA,SACA;AACA,QAAM,MAAM,yBAAyB,CAAC;AACtC,QAAM,WAAW,MAAM,kBAAkB,KAAK,IAAI,CAAC,GAAG,OAAO;AAE7D,MAAI,CAAC,UAAU,WAAW;AACxB,WAAO;AAAA,EACT;AAEA,SAAO,IAAI,SAAS,MAAM;AAAA,IACxB,QAAQ;AAAA,IACR,WAAW,SAAS;AAAA,EACtB,CAAC;AACH;AAMA,eAAe,kBACb,GACA,SACA;AACA,QAAM,MAAM,yBAAyB,CAAC;AACtC,SAAO,kBAAkB,KAAK,IAAI,CAAC,GAAG,OAAO;AAC/C;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,12 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono-agents",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"main": "index.
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"main": "src/index.ts",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"scripts": {
|
|
6
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"build": "tsx ./scripts/build.ts"
|
|
7
9
|
},
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"require": "./dist/index.js",
|
|
18
|
+
"import": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"cloudflare",
|
|
23
|
+
"agents",
|
|
24
|
+
"hono"
|
|
25
|
+
],
|
|
26
|
+
"author": "Cloudflare Inc.",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"description": "Add Cloudflare Agents to your Hono app",
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"agents-sdk": "^0.0.17",
|
|
31
|
+
"hono": "^4.6.17"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"agents-sdk": "^0.0.17",
|
|
35
|
+
"hono": "^4.6.17"
|
|
36
|
+
}
|
|
12
37
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { env } from "hono/adapter";
|
|
2
|
+
import { createMiddleware } from "hono/factory";
|
|
3
|
+
import { routeAgentRequest } from "agents-sdk";
|
|
4
|
+
|
|
5
|
+
import type { Context, Env } from "hono";
|
|
6
|
+
import type { AgentOptions } from "agents-sdk";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Configuration options for the Cloudflare Agents middleware
|
|
10
|
+
*/
|
|
11
|
+
type AgentMiddlewareContext<E extends Env> = {
|
|
12
|
+
/** Cloudflare Agents-specific configuration options */
|
|
13
|
+
options?: AgentOptions<E>;
|
|
14
|
+
/** Optional error handler for caught errors */
|
|
15
|
+
onError?: (error: Error) => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates a middleware for handling Cloudflare Agents WebSocket and HTTP requests
|
|
20
|
+
* Processes both WebSocket upgrades and standard HTTP requests, delegating them to Cloudflare Agents
|
|
21
|
+
*/
|
|
22
|
+
export function agentsMiddleware<E extends Env = Env>(
|
|
23
|
+
ctx?: AgentMiddlewareContext<E>
|
|
24
|
+
) {
|
|
25
|
+
return createMiddleware(async (c, next) => {
|
|
26
|
+
try {
|
|
27
|
+
const handler = isWebSocketUpgrade(c)
|
|
28
|
+
? handleWebSocketUpgrade
|
|
29
|
+
: handleHttpRequest;
|
|
30
|
+
const response = await handler(c, ctx?.options);
|
|
31
|
+
|
|
32
|
+
return response === null ? await next() : response;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (ctx?.onError) {
|
|
35
|
+
ctx.onError(error as Error);
|
|
36
|
+
return next();
|
|
37
|
+
}
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Checks if the incoming request is a WebSocket upgrade request
|
|
45
|
+
* Looks for the 'upgrade' header with a value of 'websocket' (case-insensitive)
|
|
46
|
+
*/
|
|
47
|
+
function isWebSocketUpgrade(c: Context): boolean {
|
|
48
|
+
return c.req.header("upgrade")?.toLowerCase() === "websocket";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new Request object from the Hono context
|
|
53
|
+
* Preserves the original request's URL, method, headers, and body
|
|
54
|
+
*/
|
|
55
|
+
function createRequestFromContext(c: Context) {
|
|
56
|
+
return new Request(c.req.url, {
|
|
57
|
+
method: c.req.method,
|
|
58
|
+
headers: c.req.header(),
|
|
59
|
+
body: c.req.raw.body,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Handles WebSocket upgrade requests
|
|
65
|
+
* Returns a WebSocket upgrade response if successful, null otherwise
|
|
66
|
+
*/
|
|
67
|
+
async function handleWebSocketUpgrade<E extends Env>(
|
|
68
|
+
c: Context<E>,
|
|
69
|
+
options?: AgentOptions<E>
|
|
70
|
+
) {
|
|
71
|
+
const req = createRequestFromContext(c);
|
|
72
|
+
const response = await routeAgentRequest(req, env(c), options);
|
|
73
|
+
|
|
74
|
+
if (!response?.webSocket) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return new Response(null, {
|
|
79
|
+
status: 101,
|
|
80
|
+
webSocket: response.webSocket,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Handles standard HTTP requests
|
|
86
|
+
* Forwards the request to Cloudflare Agents and returns the response
|
|
87
|
+
*/
|
|
88
|
+
async function handleHttpRequest<E extends Env>(
|
|
89
|
+
c: Context<E>,
|
|
90
|
+
options?: AgentOptions<E>
|
|
91
|
+
) {
|
|
92
|
+
const req = createRequestFromContext(c);
|
|
93
|
+
return routeAgentRequest(req, env(c), options);
|
|
94
|
+
}
|