Custom Handler Example
Use a custom handler to test agents without an HTTP endpoint.
In-Process Agent
ts
import { defineConfig, type ChatMessage } from 'agentest'
import { myAgent } from './src/agent.js'
export default defineConfig({
agent: {
type: 'custom',
name: 'my-agent',
handler: async (messages: ChatMessage[]) => {
const result = await myAgent.chat(messages)
return {
role: 'assistant',
content: result.text,
}
},
},
})With Tool Calls
ts
handler: async (messages: ChatMessage[]) => {
const result = await myAgent.chat(messages)
// Map tool calls to OpenAI format
const toolCalls = result.toolCalls?.map((tc, i) => ({
id: `call_${i}`,
type: 'function' as const,
function: {
name: tc.name,
arguments: JSON.stringify(tc.args),
},
}))
return {
role: 'assistant',
content: result.text || '',
tool_calls: toolCalls,
}
}Anthropic SDK
ts
import Anthropic from '@anthropic-ai/sdk'
const client = new Anthropic()
export default defineConfig({
agent: {
type: 'custom',
name: 'claude-agent',
handler: async (messages) => {
const response = await client.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: messages
.filter((m) => m.role !== 'system')
.map((m) => ({
role: m.role as 'user' | 'assistant',
content: m.content,
})),
system: messages.find((m) => m.role === 'system')?.content,
})
const text = response.content[0].type === 'text'
? response.content[0].text
: ''
return { role: 'assistant', content: text }
},
},
})Benefits of Custom Handlers
- No HTTP server needed - Test agents in-process
- Direct SDK access - Use any LLM SDK
- Custom protocols - Not limited to OpenAI format
- Framework integration - Works with LangChain, Vercel AI, etc.
- Local development - Faster iteration during development
Testing Different Versions
ts
import { agentV1, agentV2 } from './src/agents.js'
export default defineConfig({
agent: {
type: 'custom',
name: 'v1',
handler: async (msgs) => agentV1.chat(msgs),
},
compare: [
{
type: 'custom',
name: 'v2',
handler: async (msgs) => agentV2.chat(msgs),
},
],
})