Back to skills
SKILL.md
1228 Patterns 075cf49e
ASecurity**Server (AIChatAgent):**
- 9 stars
- 0 votes
- 0 copies
- 0 views
- Added October 11, 2026
Works with
Security analysis
100/100npx -y skills add tools-only/X-Skills --skill 1228-patterns_075cf49e --agent claude-codeAre you the author of 1228 Patterns 075cf49e?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/tools-only-1228-patterns-075cf49e)# Patterns & Use Cases
## AI Chat w/Tools
**Server (AIChatAgent):**
```ts
import { AIChatAgent } from 'agents'
import { openai } from '@ai-sdk/openai'
import { tool } from 'ai'
import { z } from 'zod'
export class ChatAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
return this.streamText({
model: openai('gpt-4'),
messages: this.messages, // Auto-managed
tools: {
getWeather: tool({
description: 'Get current weather',
parameters: z.object({ city: z.string() }),
execute: async ({ city }) => `Weather in ${city}: Sunny, 72°F`,
}),
searchDocs: tool({
description: 'Search documentation',
parameters: z.object({ query: z.string() }),
execute: async ({ query }) =>
JSON.stringify(
this.sql<{ title; content }>`SELECT title, content FROM docs WHERE content LIKE ${'%' + query + '%'}`,
),
}),
},
onFinish,
})
}
}
```
**Client (React):**
```tsx
import { useAgent } from 'agents/react'
import { useAgentChat } from 'agents/ai-react'
function ChatUI() {
const agent = useAgent({ agent: 'ChatAgent' })
const { messages, input, handleInputChange, handleSubmit, isLoading } = useAgentChat({ agent })
return (
<div>
{messages.map((m) => (
<div key={m.id}>
{m.role}: {m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} disabled={isLoading} />
<button disabled={isLoading}>Send</button>
</form>
</div>
)
}
```
## Human-in-the-Loop (Client Tools)
Server defines tool, client executes:
```ts
// Server
export class ChatAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
return this.streamText({
model: openai('gpt-4'),
messages: this.messages,
tools: {
confirmAction: tool({
description: 'Ask user to confirm',
parameters: z.object({ action: z.string() }),
execute: 'client', // Client-side execution
}),
},
onFinish,
})
}
}
// Client
const { messages } = useAgentChat({
agent,
onToolCall: async (toolCall) => {
if (toolCall.toolName === 'confirmAction') {
return { confirmed: window.confirm(`Confirm: ${toolCall.args.action}?`) }
}
},
})
```
## Task Queue & Scheduled Processing
```ts
export class TaskAgent extends Agent<Env> {
onStart() {
this.schedule('*/5 * * * *', 'processQueue', {}) // Every 5 min
this.schedule('0 0 * * *', 'dailyCleanup', {}) // Daily
}
async onRequest(req: Request) {
await this.queue('processVideo', { videoId: (await req.json()).videoId })
return Response.json({ queued: true })
}
async processQueue() {
const tasks = await this.dequeue(10)
for (const task of tasks) {
if (task.name === 'processVideo') await this.processVideo(task.data.videoId)
}
}
async dailyCleanup() {
this.sql`DELETE FROM logs WHERE created_at < ${Date.now() - 86400000}`
}
}
```
## Manual WebSocket Chat
Custom protocols (non-AI):
```ts
export class ChatAgent extends Agent<Env> {
async onConnect(conn: Connection, ctx: ConnectionContext) {
conn.accept()
conn.setState({ userId: ctx.request.headers.get('X-User-ID') || 'anon' })
conn.send(JSON.stringify({ type: 'history', messages: this.state.messages }))
}
async onMessage(conn: Connection, msg: WSMessage) {
const newMsg = { userId: conn.state.userId, text: JSON.parse(msg as string).text, timestamp: Date.now() }
this.setState({ messages: [...this.state.messages, newMsg] })
this.connections.forEach((c) => c.send(JSON.stringify(newMsg)))
}
}
```
## Email Processing w/AI
```ts
export class EmailAgent extends Agent<Env> {
async onEmail(email: AgentEmail) {
const [text, from, subject] = [await email.text(), email.from, email.headers.get('subject') || '']
this.sql`INSERT INTO emails (from_addr, subject, body) VALUES (${from}, ${subject}, ${text})`
const { text: summary } = await generateText({
model: openai('gpt-4o-mini'),
prompt: `Summarize: ${subject}\n\n${text}`,
})
this.connections.forEach((c) => c.send(JSON.stringify({ type: 'new_email', from, summary })))
if (summary.includes('urgent')) await this.schedule(0, 'sendAutoReply', { to: from })
}
}
```
## Real-time Collaboration
```ts
export class GameAgent extends Agent<Env> {
initialState = { players: [], gameStarted: false }
async onConnect(conn: Connection, ctx: ConnectionContext) {
conn.accept()
const playerId = ctx.request.headers.get('X-Player-ID') || crypto.randomUUID()
conn.setState({ playerId })
const newPlayer = { id: playerId, score: 0 }
this.setState({ ...this.state, players: [...this.state.players, newPlayer] })
this.connections.forEach((c) => c.send(JSON.stringify({ type: 'player_joined', player: newPlayer })))
}
async onMessage(conn: Connection, msg: WSMessage) {
const m = JSON.parse(msg as string)
if (m.type === 'move') {
this.setState({
...this.state,
players: this.state.players.map((p) =>
p.id === conn.state.playerId ? { ...p, score: p.score + m.points } : p,
),
})
this.connections.forEach((c) => c.send(JSON.stringify({ type: 'player_moved', playerId: conn.state.playerId })))
}
if (m.type === 'start' && this.state.players.length >= 2) {
this.setState({ ...this.state, gameStarted: true })
this.connections.forEach((c) => c.send(JSON.stringify({ type: 'game_started' })))
}
}
}
```
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.