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 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(request) {
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(request) {
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
- // or with authentication
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: async (req) => {
43
- const token = req.headers.get("authorization");
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
- // With error handling
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
- // With custom routing
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<E> /** Optional error handler for caught errors */;
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
- ): _$hono.MiddlewareHandler<E, string, {}, Response>;
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 a WebSocket upgrade response if successful, null otherwise
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 (!response?.webSocket) return null;
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>;\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 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 response = await routeAgentRequest(\n c.req.raw,\n env(c) satisfies Env,\n options\n );\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 return routeAgentRequest(c.req.raw, env(c) satisfies Env, options);\n}\n"],"mappings":";;;;;;;;AAoBA,SAAgB,iBACd,KACA;AACA,QAAO,iBAAoB,OAAO,GAAG,SAAS;AAC5C,MAAI;GAKF,MAAM,WAAW,OAJD,mBAAmB,EAAE,GACjC,yBACA,mBAE2B,GAAG,KAAK,QAAQ;AAE/C,UAAO,aAAa,OAAO,MAAM,MAAM,GAAG;WACnC,OAAO;AACd,OAAI,KAAK,SAAS;AAChB,QAAI,QAAQ,MAAe;AAC3B,WAAO,MAAM;;AAEf,SAAM;;GAER;;;;;;AAOJ,SAAS,mBAAmB,GAAqB;AAC/C,QAAO,EAAE,IAAI,OAAO,UAAU,EAAE,aAAa,KAAK;;;;;;AAOpD,eAAe,uBACb,GACA,SACA;CACA,MAAM,WAAW,MAAM,kBACrB,EAAE,IAAI,KACN,IAAI,EAAE,EACN,QACD;AAED,KAAI,CAAC,UAAU,UACb,QAAO;AAGT,QAAO,IAAI,SAAS,MAAM;EACxB,QAAQ;EACR,WAAW,SAAS;EACrB,CAAC;;;;;;AAOJ,eAAe,kBACb,GACA,SACA;AACA,QAAO,kBAAkB,EAAE,IAAI,KAAK,IAAI,EAAE,EAAgB,QAAQ"}
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.11.0",
9
- "hono": "^4.12.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.9.0 <1.0.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.10"
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 a WebSocket upgrade response if successful, null otherwise
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) satisfies Env,
63
+ env(c) as AgentEnv<E>,
62
64
  options
63
65
  );
64
66
 
65
- if (!response?.webSocket) {
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) satisfies Env, options);
89
+ return routeAgentRequest(c.req.raw, env(c) as AgentEnv<E>, options);
84
90
  }