hono-agents 3.0.10 → 3.0.12
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/LICENSE +21 -0
- package/README.md +37 -12
- package/dist/index.d.ts +5 -3
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/package.json +9 -8
- package/src/index.ts +13 -7
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License Copyright (c) 2025 Cloudflare, Inc.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of
|
|
4
|
+
charge, to any person obtaining a copy of this software and associated
|
|
5
|
+
documentation files (the "Software"), to deal in the Software without
|
|
6
|
+
restriction, including without limitation the rights to use, copy, modify, merge,
|
|
7
|
+
publish, distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice
|
|
12
|
+
(including the next paragraph) shall be included in all copies or substantial
|
|
13
|
+
portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
16
|
+
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
18
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
19
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -19,13 +19,13 @@ import { agentsMiddleware } from "hono-agents";
|
|
|
19
19
|
|
|
20
20
|
// Define your agent classes
|
|
21
21
|
export class ChatAgent extends Agent {
|
|
22
|
-
async onRequest(
|
|
22
|
+
async onRequest(_request: Request) {
|
|
23
23
|
return new Response("Ready to assist with chat.");
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export class AssistantAgent extends Agent {
|
|
28
|
-
async onRequest(
|
|
28
|
+
async onRequest(_request: Request) {
|
|
29
29
|
return new Response("I'm your AI assistant.");
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -34,24 +34,45 @@ export class AssistantAgent extends Agent {
|
|
|
34
34
|
const app = new Hono();
|
|
35
35
|
app.use("*", agentsMiddleware());
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
export default app;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Authentication
|
|
41
|
+
|
|
42
|
+
Replace the basic middleware registration with one that authenticates both
|
|
43
|
+
WebSocket connections and HTTP requests:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
const authorizeAgentRequest = async (req: Request) => {
|
|
47
|
+
const token = req.headers.get("authorization");
|
|
48
|
+
// Validate token
|
|
49
|
+
if (!token) return new Response("Unauthorized", { status: 401 });
|
|
50
|
+
};
|
|
51
|
+
|
|
38
52
|
app.use(
|
|
39
53
|
"*",
|
|
40
54
|
agentsMiddleware({
|
|
41
55
|
options: {
|
|
42
|
-
onBeforeConnect:
|
|
43
|
-
|
|
44
|
-
// validate token
|
|
45
|
-
if (!token) return new Response("Unauthorized", { status: 401 });
|
|
46
|
-
}
|
|
56
|
+
onBeforeConnect: authorizeAgentRequest,
|
|
57
|
+
onBeforeRequest: authorizeAgentRequest
|
|
47
58
|
}
|
|
48
59
|
})
|
|
49
60
|
);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Error handling
|
|
50
64
|
|
|
51
|
-
|
|
65
|
+
Replace the basic middleware registration to add an error handler:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
52
68
|
app.use("*", agentsMiddleware({ onError: (error) => console.error(error) }));
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Custom routing
|
|
72
|
+
|
|
73
|
+
Replace the basic middleware registration to customize routing:
|
|
53
74
|
|
|
54
|
-
|
|
75
|
+
```ts
|
|
55
76
|
app.use(
|
|
56
77
|
"*",
|
|
57
78
|
agentsMiddleware({
|
|
@@ -60,8 +81,6 @@ app.use(
|
|
|
60
81
|
}
|
|
61
82
|
})
|
|
62
83
|
);
|
|
63
|
-
|
|
64
|
-
export default app;
|
|
65
84
|
```
|
|
66
85
|
|
|
67
86
|
## Configuration
|
|
@@ -94,6 +113,12 @@ The `agentsMiddleware` function:
|
|
|
94
113
|
3. Handles WebSocket upgrades for persistent connections
|
|
95
114
|
4. Provides error handling and custom routing options
|
|
96
115
|
|
|
116
|
+
Requests that do not match an Agent route continue through later Hono middleware
|
|
117
|
+
and routes. Once an Agent route matches, its response—including an HTTP
|
|
118
|
+
rejection—is returned without invoking later handlers. Mount `agentsMiddleware`
|
|
119
|
+
on a narrower path or configure a distinct prefix if the app has other WebSocket
|
|
120
|
+
routes under the same URL prefix.
|
|
121
|
+
|
|
97
122
|
Agents can:
|
|
98
123
|
|
|
99
124
|
- Maintain state across requests
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { AgentOptions } from "agents";
|
|
2
|
-
import * as _$hono from "hono";
|
|
3
2
|
import { Env } from "hono";
|
|
4
3
|
|
|
5
4
|
//#region src/index.d.ts
|
|
5
|
+
type AgentEnv<E extends Env> = NonNullable<E["Bindings"]>;
|
|
6
6
|
/**
|
|
7
7
|
* Configuration options for the Cloudflare Agents middleware
|
|
8
8
|
*/
|
|
9
9
|
type AgentMiddlewareContext<E extends Env> = {
|
|
10
|
-
/** Cloudflare Agents-specific configuration options */ options?: AgentOptions<
|
|
10
|
+
/** Cloudflare Agents-specific configuration options */ options?: AgentOptions<
|
|
11
|
+
AgentEnv<E>
|
|
12
|
+
> /** Optional error handler for caught errors */;
|
|
11
13
|
onError?: (error: Error) => void;
|
|
12
14
|
};
|
|
13
15
|
/**
|
|
@@ -16,7 +18,7 @@ type AgentMiddlewareContext<E extends Env> = {
|
|
|
16
18
|
*/
|
|
17
19
|
declare function agentsMiddleware<E extends Env = Env>(
|
|
18
20
|
ctx?: AgentMiddlewareContext<E>
|
|
19
|
-
):
|
|
21
|
+
): import("hono").MiddlewareHandler<E, string, {}, Response>;
|
|
20
22
|
//#endregion
|
|
21
23
|
export { agentsMiddleware };
|
|
22
24
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -29,11 +29,12 @@ function isWebSocketUpgrade(c) {
|
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
31
|
* Handles WebSocket upgrade requests
|
|
32
|
-
* Returns
|
|
32
|
+
* Returns matched HTTP responses unchanged and null only when no Agent route matches
|
|
33
33
|
*/
|
|
34
34
|
async function handleWebSocketUpgrade(c, options) {
|
|
35
35
|
const response = await routeAgentRequest(c.req.raw, env(c), options);
|
|
36
|
-
if (
|
|
36
|
+
if (response === null) return null;
|
|
37
|
+
if (!response.webSocket) return response;
|
|
37
38
|
return new Response(null, {
|
|
38
39
|
status: 101,
|
|
39
40
|
webSocket: response.webSocket
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { AgentOptions } from \"agents\";\nimport { routeAgentRequest } from \"agents\";\nimport type { Context, Env } from \"hono\";\nimport { env } from \"hono/adapter\";\nimport { createMiddleware } from \"hono/factory\";\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
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { AgentOptions } from \"agents\";\nimport { routeAgentRequest } from \"agents\";\nimport type { Context, Env } from \"hono\";\nimport { env } from \"hono/adapter\";\nimport { createMiddleware } from \"hono/factory\";\n\ntype AgentEnv<E extends Env> = NonNullable<E[\"Bindings\"]>;\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<AgentEnv<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<E>(async (c, next) => {\n try {\n const handler = isWebSocketUpgrade(c)\n ? handleWebSocketUpgrade\n : handleHttpRequest;\n\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 * Handles WebSocket upgrade requests\n * Returns matched HTTP responses unchanged and null only when no Agent route matches\n */\nasync function handleWebSocketUpgrade<E extends Env>(\n c: Context<E>,\n options?: AgentOptions<AgentEnv<E>>\n) {\n const response = await routeAgentRequest(\n c.req.raw,\n env(c) as AgentEnv<E>,\n options\n );\n\n if (response === null) {\n return null;\n }\n\n if (!response.webSocket) {\n return response;\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<AgentEnv<E>>\n) {\n return routeAgentRequest(c.req.raw, env(c) as AgentEnv<E>, options);\n}\n"],"mappings":";;;;;;;;AAsBA,SAAgB,iBACd,KACA;CACA,OAAO,iBAAoB,OAAO,GAAG,SAAS;EAC5C,IAAI;GAKF,MAAM,WAAW,OAJD,mBAAmB,CAAC,IAChC,yBACA,kBAAA,CAE2B,GAAG,KAAK,OAAO;GAE9C,OAAO,aAAa,OAAO,MAAM,KAAK,IAAI;EAC5C,SAAS,OAAO;GACd,IAAI,KAAK,SAAS;IAChB,IAAI,QAAQ,KAAc;IAC1B,OAAO,KAAK;GACd;GACA,MAAM;EACR;CACF,CAAC;AACH;;;;;AAMA,SAAS,mBAAmB,GAAqB;CAC/C,OAAO,EAAE,IAAI,OAAO,SAAS,CAAC,EAAE,YAAY,MAAM;AACpD;;;;;AAMA,eAAe,uBACb,GACA,SACA;CACA,MAAM,WAAW,MAAM,kBACrB,EAAE,IAAI,KACN,IAAI,CAAC,GACL,OACF;CAEA,IAAI,aAAa,MACf,OAAO;CAGT,IAAI,CAAC,SAAS,WACZ,OAAO;CAGT,OAAO,IAAI,SAAS,MAAM;EACxB,QAAQ;EACR,WAAW,SAAS;CACtB,CAAC;AACH;;;;;AAMA,eAAe,kBACb,GACA,SACA;CACA,OAAO,kBAAkB,EAAE,IAAI,KAAK,IAAI,CAAC,GAAkB,OAAO;AACpE"}
|
package/package.json
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
},
|
|
6
6
|
"description": "Add Cloudflare Agents to your Hono app",
|
|
7
7
|
"devDependencies": {
|
|
8
|
-
"agents": "^0.
|
|
9
|
-
"hono": "^4.12.
|
|
8
|
+
"agents": "^0.21.0",
|
|
9
|
+
"hono": "^4.12.27"
|
|
10
10
|
},
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"main": "src/index.ts",
|
|
32
32
|
"name": "hono-agents",
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"agents": ">=0.
|
|
34
|
+
"agents": ">=0.17.1 <1.0.0",
|
|
35
35
|
"hono": "^4.6.17"
|
|
36
36
|
},
|
|
37
37
|
"repository": {
|
|
@@ -39,10 +39,11 @@
|
|
|
39
39
|
"type": "git",
|
|
40
40
|
"url": "git+https://github.com/cloudflare/agents.git"
|
|
41
41
|
},
|
|
42
|
-
"scripts": {
|
|
43
|
-
"build": "tsx ./scripts/build.ts"
|
|
44
|
-
},
|
|
45
42
|
"type": "module",
|
|
46
43
|
"types": "dist/index.d.ts",
|
|
47
|
-
"version": "3.0.
|
|
48
|
-
|
|
44
|
+
"version": "3.0.12",
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsx ./scripts/build.ts",
|
|
47
|
+
"test": "vitest --run"
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,12 +4,14 @@ import type { Context, Env } from "hono";
|
|
|
4
4
|
import { env } from "hono/adapter";
|
|
5
5
|
import { createMiddleware } from "hono/factory";
|
|
6
6
|
|
|
7
|
+
type AgentEnv<E extends Env> = NonNullable<E["Bindings"]>;
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
10
|
* Configuration options for the Cloudflare Agents middleware
|
|
9
11
|
*/
|
|
10
12
|
type AgentMiddlewareContext<E extends Env> = {
|
|
11
13
|
/** Cloudflare Agents-specific configuration options */
|
|
12
|
-
options?: AgentOptions<E
|
|
14
|
+
options?: AgentOptions<AgentEnv<E>>;
|
|
13
15
|
/** Optional error handler for caught errors */
|
|
14
16
|
onError?: (error: Error) => void;
|
|
15
17
|
};
|
|
@@ -50,22 +52,26 @@ function isWebSocketUpgrade(c: Context): boolean {
|
|
|
50
52
|
|
|
51
53
|
/**
|
|
52
54
|
* Handles WebSocket upgrade requests
|
|
53
|
-
* Returns
|
|
55
|
+
* Returns matched HTTP responses unchanged and null only when no Agent route matches
|
|
54
56
|
*/
|
|
55
57
|
async function handleWebSocketUpgrade<E extends Env>(
|
|
56
58
|
c: Context<E>,
|
|
57
|
-
options?: AgentOptions<E
|
|
59
|
+
options?: AgentOptions<AgentEnv<E>>
|
|
58
60
|
) {
|
|
59
61
|
const response = await routeAgentRequest(
|
|
60
62
|
c.req.raw,
|
|
61
|
-
env(c)
|
|
63
|
+
env(c) as AgentEnv<E>,
|
|
62
64
|
options
|
|
63
65
|
);
|
|
64
66
|
|
|
65
|
-
if (
|
|
67
|
+
if (response === null) {
|
|
66
68
|
return null;
|
|
67
69
|
}
|
|
68
70
|
|
|
71
|
+
if (!response.webSocket) {
|
|
72
|
+
return response;
|
|
73
|
+
}
|
|
74
|
+
|
|
69
75
|
return new Response(null, {
|
|
70
76
|
status: 101,
|
|
71
77
|
webSocket: response.webSocket
|
|
@@ -78,7 +84,7 @@ async function handleWebSocketUpgrade<E extends Env>(
|
|
|
78
84
|
*/
|
|
79
85
|
async function handleHttpRequest<E extends Env>(
|
|
80
86
|
c: Context<E>,
|
|
81
|
-
options?: AgentOptions<E
|
|
87
|
+
options?: AgentOptions<AgentEnv<E>>
|
|
82
88
|
) {
|
|
83
|
-
return routeAgentRequest(c.req.raw, env(c)
|
|
89
|
+
return routeAgentRequest(c.req.raw, env(c) as AgentEnv<E>, options);
|
|
84
90
|
}
|