Skip to content

Commit

Permalink
hono-agents
Browse files Browse the repository at this point in the history
  • Loading branch information
threepointone committed Feb 24, 2025
1 parent 7a3a1a0 commit 2610509
Show file tree
Hide file tree
Showing 12 changed files with 488 additions and 9 deletions.
6 changes: 6 additions & 0 deletions .changeset/cyan-cameras-pull.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@cloudflare/agents": patch
"hono-agents": patch
---

Hono Agents
2 changes: 1 addition & 1 deletion .github/version-script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ async function main() {
console.log("Git hash:", stdout.trim());

for (const path of [
// just the one package for now
"./packages/agents/package.json",
"./packages/hono-agents/package.json",
]) {
const packageJson = JSON.parse(fs.readFileSync(path, "utf-8"));
packageJson.version = `0.0.0-${stdout.trim()}`;
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/prerelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@ jobs:
env:
NPM_PUBLISH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
working-directory: packages/agents

# - run: npm publish --tag beta
# env:
# NPM_PUBLISH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
# working-directory: packages/hono-agents
188 changes: 188 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,191 @@ We welcome contributions! Whether it's:
MIT License - Build something meaningful.

---

# hono-agents

🔥 Hono ⨉ 🧠 Cloudflare Agents

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.

## Installation

```bash
npm install hono-agents hono @cloudflare/agents
```

## Usage

```ts
import { Hono } from "hono";
import { agentsMiddleware } from "hono-agents";
import { Agent } from "@cloudflare/agents";

// Define your agent classes
export class ChatAgent extends Agent {
async onRequest(request) {
return new Response("Ready to assist with chat.");
}
}

export class AssistantAgent extends Agent {
async onRequest(request) {
return new Response("I'm your AI assistant.");
}
}

// Basic setup
const app = new Hono();
app.use("*", agentsMiddleware());

// or with authentication
app.use(
"*",
agentsMiddleware({
options: {
onBeforeConnect: async (req) => {
const token = req.headers.get("authorization");
// validate token
if (!token) return new Response("Unauthorized", { status: 401 });
},
},
})
);

// With error handling
app.use("*", agentsMiddleware({ onError: (error) => console.error(error) }));

// With custom routing
app.use(
"*",
agentsMiddleware({
options: {
prefix: "/agents", // Handles /agents/* routes only
},
})
);

export default app;
```

## React Usage

```tsx
import { useAgent } from "@cloudflare/agents/react";

// Basic connection
const agent = useAgent({ agent: "chat-agent", name: "support" });

// Assistant connection
const agent = useAgent({ agent: "assistant-agent", name: "helper" });

// With auth
const agent = useAgent({
agent: "chat-agent",
name: "support",
headers: { authorization: `Bearer ${token}` },
});

// Using the agent state
function StateInterface() {
const [state, setState] = useState({ counter: 0 });

const agent = useAgent({
agent: "thinking-agent",
onStateUpdate: (newState) => setState(newState),
});

const increment = () => {
agent.setState({ counter: state.counter + 1 });
};

return (
<div>
<div>Count: {state.counter}</div>
<button onClick={increment}>Increment</button>
</div>
);
}

// AI Chat Interface
function ChatInterface() {
const agent = useAgent({
agent: "dialogue-agent",
});

const { messages, input, handleInputChange, handleSubmit, clearHistory } =
useAgentChat({
agent,
maxSteps: 5,
});

return (
<div className="chat-interface">
<div className="message-flow">
{messages.map((message) => (
<div key={message.id} className="message">
<div className="role">{message.role}</div>
<div className="content">{message.content}</div>
</div>
))}
</div>

<form onSubmit={handleSubmit} className="input-area">
<input
value={input}
onChange={handleInputChange}
placeholder="Type your message..."
className="message-input"
/>
</form>

<button onClick={clearHistory} className="clear-button">
Clear Chat
</button>
</div>
);
}
```

## Configuration

To properly configure your Cloudflare Workers project to use agents, update your `wrangler.toml` file:

```toml
[durable_objects]
bindings = [
{ name = "ChatAgent", class_name = "ChatAgent" },
{ name = "AssistantAgent", class_name = "AssistantAgent" }
]

[[migrations]]
tag = "v1"
new_sqlite_classes = ["ChatAgent", "AssistantAgent"]
```

## How It Works

The `agentsMiddleware` function:

1. Detects whether the incoming request is a WebSocket connection or standard HTTP request
2. Routes the request to the appropriate agent
3. Handles WebSocket upgrades for persistent connections
4. Provides error handling and custom routing options

Agents can:

- Maintain state across requests
- Handle both HTTP and WebSocket connections
- Schedule tasks for future execution
- Communicate with AI services
- Integrate seamlessly with React applications

## License

ISC

## Credits

Thanks to Cloudflare for developing the Agents framework and for the inspiration from projects like PartyKit that pioneered these patterns.

---
26 changes: 26 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"author": "Sunil Pai <spai@cloudflare.com>",
"private": true,
"scripts": {
"build": "npm run build -w @cloudflare/agents",
"build": "npm run build -w @cloudflare/agents -w hono-agents",
"check": "sherif && tsc"
},
"license": "MIT",
Expand Down
5 changes: 0 additions & 5 deletions packages/agents/TODO.md

This file was deleted.

6 changes: 4 additions & 2 deletions packages/agents/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,12 @@ export type AgentNamespace<Agentic extends Agent<unknown>> =

export type AgentContext = DurableObjectState;

export type AgentOptions<Env> = PartyServerOptions<Env>;

export function routeAgentRequest<Env>(
request: Request,
env: Env,
options?: PartyServerOptions<Env>
options?: AgentOptions<Env>
) {
return routePartykitRequest(request, env as Record<string, unknown>, {
prefix: "agents",
Expand All @@ -404,7 +406,7 @@ export function routeAgentRequest<Env>(
export async function routeAgentEmail<Env>(
email: ForwardableEmailMessage,
env: Env,
options?: PartyServerOptions<Env>
options?: AgentOptions<Env>
): Promise<void> {}

export function getAgentByName<Env, T extends Agent<Env>>(
Expand Down
Loading

0 comments on commit 2610509

Please sign in to comment.