mirror of
https://github.com/codeany-ai/open-agent-sdk-typescript.git
synced 2026-04-25 07:00:49 +09:00
85dff47d74
- Add skill system with types, registry, SkillTool, and 5 bundled skills
(simplify, commit, review, debug, test)
- Integrate hooks into QueryEngine at 9 lifecycle points (SessionStart,
UserPromptSubmit, PreToolUse, PostToolUse, PostToolUseFailure,
PreCompact, PostCompact, Stop, SessionEnd)
- Add LLM provider abstraction supporting both Anthropic Messages API
and OpenAI Chat Completions API (works with GPT, DeepSeek, Qwen, etc.)
- Add CODEANY_API_TYPE env var ('anthropic-messages' | 'openai-completions')
with auto-detection from model name
- Remove all ANTHROPIC_* env var references, only support CODEANY_* prefix
- Add model pricing and context windows for OpenAI/DeepSeek models
- Remove direct @anthropic-ai/sdk dependency from all files except the
Anthropic provider (types.ts, engine.ts, etc. are now provider-agnostic)
- Add PermissionBehavior type export
- Bump version to 0.2.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
89 lines
2.6 KiB
TypeScript
89 lines
2.6 KiB
TypeScript
/**
|
|
* Example 13: Hooks
|
|
*
|
|
* Shows how to use lifecycle hooks to intercept agent behavior.
|
|
* Hooks fire at key points: session start/end, before/after tool use,
|
|
* compaction, etc.
|
|
*
|
|
* Run: npx tsx examples/13-hooks.ts
|
|
*/
|
|
import { createAgent, createHookRegistry } from '../src/index.js'
|
|
import type { HookInput } from '../src/index.js'
|
|
|
|
async function main() {
|
|
console.log('--- Example 13: Hooks ---\n')
|
|
|
|
// Create a hook registry with custom handlers
|
|
const registry = createHookRegistry({
|
|
SessionStart: [{
|
|
handler: async (input: HookInput) => {
|
|
console.log(`[Hook] Session started: ${input.sessionId}`)
|
|
},
|
|
}],
|
|
PreToolUse: [{
|
|
handler: async (input: HookInput) => {
|
|
console.log(`[Hook] About to use tool: ${input.toolName}`)
|
|
// You can block a tool by returning { block: true }
|
|
// return { block: true, message: 'Tool blocked by hook' }
|
|
},
|
|
}],
|
|
PostToolUse: [{
|
|
handler: async (input: HookInput) => {
|
|
const output = typeof input.toolOutput === 'string'
|
|
? input.toolOutput.slice(0, 100)
|
|
: JSON.stringify(input.toolOutput).slice(0, 100)
|
|
console.log(`[Hook] Tool ${input.toolName} completed: ${output}...`)
|
|
},
|
|
}],
|
|
PostToolUseFailure: [{
|
|
handler: async (input: HookInput) => {
|
|
console.log(`[Hook] Tool ${input.toolName} FAILED: ${input.error}`)
|
|
},
|
|
}],
|
|
Stop: [{
|
|
handler: async () => {
|
|
console.log('[Hook] Agent loop completed')
|
|
},
|
|
}],
|
|
SessionEnd: [{
|
|
handler: async () => {
|
|
console.log('[Hook] Session ended')
|
|
},
|
|
}],
|
|
})
|
|
|
|
// Create agent with hook registry
|
|
// Note: For direct HookRegistry usage, we pass hooks via the engine config.
|
|
// The AgentOptions.hooks format also works (see below).
|
|
const agent = createAgent({
|
|
model: process.env.CODEANY_MODEL || 'claude-sonnet-4-6',
|
|
maxTurns: 5,
|
|
// Alternative: use AgentOptions.hooks format
|
|
hooks: {
|
|
PreToolUse: [{
|
|
hooks: [async (input: any, toolUseId: string) => {
|
|
console.log(`[AgentHook] PreToolUse: ${input.toolName} (${toolUseId})`)
|
|
}],
|
|
}],
|
|
},
|
|
})
|
|
|
|
for await (const event of agent.query('What files are in the current directory? Be brief.')) {
|
|
const msg = event as any
|
|
if (msg.type === 'assistant') {
|
|
for (const block of msg.message?.content || []) {
|
|
if (block.type === 'text' && block.text.trim()) {
|
|
console.log(`\nAssistant: ${block.text.slice(0, 200)}`)
|
|
}
|
|
}
|
|
}
|
|
if (msg.type === 'result') {
|
|
console.log(`\n--- ${msg.subtype} ---`)
|
|
}
|
|
}
|
|
|
|
await agent.close()
|
|
}
|
|
|
|
main().catch(console.error)
|