docs(hooks): add plugin-style lifecycle hook examples
This commit is contained in:
parent
ebb28f5201
commit
ac905d478b
2 changed files with 98 additions and 0 deletions
10
README.md
10
README.md
|
|
@ -1003,6 +1003,16 @@ PicoClaw routes providers by protocol family:
|
|||
|
||||
This keeps the runtime lightweight while making new OpenAI-compatible backends mostly a config operation (`api_base` + `api_key`).
|
||||
|
||||
### Lifecycle Hooks (Plugin-style Extensions)
|
||||
|
||||
PicoClaw provides typed lifecycle hooks for observability, outbound filtering, and tool guardrails.
|
||||
|
||||
- Register hooks in Go at startup with `hooks.NewHookRegistry()`.
|
||||
- Attach once via `agentLoop.SetHooks(registry)` before `Run()`.
|
||||
- If hooks are not set, default behavior is unchanged.
|
||||
|
||||
See runnable examples: [docs/hooks-plugin-examples.md](docs/hooks-plugin-examples.md)
|
||||
|
||||
<details>
|
||||
<summary><b>Zhipu</b></summary>
|
||||
|
||||
|
|
|
|||
88
docs/hooks-plugin-examples.md
Normal file
88
docs/hooks-plugin-examples.md
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# Lifecycle Hooks: Plugin-Style Examples
|
||||
|
||||
This guide shows how to extend PicoClaw behavior with `pkg/hooks` without modifying core agent logic.
|
||||
|
||||
Current model:
|
||||
- "Plugin-style" means registering Go handlers at startup.
|
||||
- Hooks are in-process (no dynamic `.so` loading).
|
||||
- If no hooks are registered, the runtime follows the normal zero-cost path.
|
||||
|
||||
## Available Hooks
|
||||
|
||||
| Hook | Type | Typical use |
|
||||
|---|---|---|
|
||||
| `message_received` | observe-only | inbound telemetry |
|
||||
| `message_sending` | modifying + cancel | content filtering, safety policy |
|
||||
| `before_tool_call` | modifying + cancel | tool allow/deny, arg rewriting |
|
||||
| `after_tool_call` | observe-only | latency/error metrics |
|
||||
| `llm_input` | observe-only | prompt size monitoring |
|
||||
| `llm_output` | observe-only | response/tool-call telemetry |
|
||||
| `session_start` | observe-only | session audit |
|
||||
| `session_end` | observe-only | session cleanup metrics |
|
||||
|
||||
## Quick Start
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/hooks"
|
||||
)
|
||||
|
||||
func buildHooks() *hooks.HookRegistry {
|
||||
reg := hooks.NewHookRegistry()
|
||||
|
||||
// 1) Guardrail: block shell tool globally.
|
||||
reg.OnBeforeToolCall("block-shell", 100, func(_ context.Context, e *hooks.BeforeToolCallEvent) error {
|
||||
if e.ToolName == "shell" {
|
||||
e.Cancel = true
|
||||
e.CancelReason = "shell tool is disabled by local policy"
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// 2) Outbound filter: redact obvious API key patterns.
|
||||
reg.OnMessageSending("redact-secrets", 50, func(_ context.Context, e *hooks.MessageSendingEvent) error {
|
||||
e.Content = strings.ReplaceAll(e.Content, "sk-", "[redacted]-")
|
||||
return nil
|
||||
})
|
||||
|
||||
// 3) Telemetry: record tool latency or errors.
|
||||
reg.OnAfterToolCall("tool-telemetry", 0, func(_ context.Context, e *hooks.AfterToolCallEvent) error {
|
||||
// Send to metrics backend / logs as needed.
|
||||
_ = e.ToolName
|
||||
_ = e.Duration
|
||||
_ = e.Result
|
||||
return nil
|
||||
})
|
||||
|
||||
return reg
|
||||
}
|
||||
```
|
||||
|
||||
Attach once during startup:
|
||||
|
||||
```go
|
||||
agentLoop := agent.NewAgentLoop(cfg, msgBus, provider)
|
||||
agentLoop.SetHooks(buildHooks()) // Must be called before Run()
|
||||
```
|
||||
|
||||
## Priority and Cancellation
|
||||
|
||||
- Lower `priority` runs first.
|
||||
- `message_sending` and `before_tool_call` are sequential and can cancel.
|
||||
- Other hooks are observe-only and run concurrently.
|
||||
|
||||
Recommended ordering:
|
||||
- `0-49`: telemetry and logging
|
||||
- `50-89`: transforms (redaction, normalization)
|
||||
- `90+`: hard guardrails (block/cancel)
|
||||
|
||||
## Safety Notes
|
||||
|
||||
- Hook panics are recovered internally; one bad hook does not crash the loop.
|
||||
- Hook errors are logged and execution continues unless `Cancel` is set.
|
||||
- Keep hook handlers fast and non-blocking to avoid latency impact.
|
||||
Loading…
Add table
Reference in a new issue