Skip to content

Commit d27dfd2

Browse files
committed
Cache hook policy in handler to avoid per-turn workspace reloads
1 parent 34e1b0e commit d27dfd2

File tree

2 files changed

+27
-12
lines changed

2 files changed

+27
-12
lines changed

pkg/agent/loop.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers
231231
hookDispatcher = hooks.NewDispatcher(auditSink)
232232
if hookPolicy.Enabled || hookPolicyErr != nil {
233233
provenanceHandler := &builtin.ProvenanceHandler{}
234-
policyHandler := builtin.NewPolicyHandler(workspace)
234+
policyHandler := builtin.NewPolicyHandler(hookPolicy, hookDiag, hookPolicyErr)
235235
if hookPolicyErr != nil {
236236
for _, ev := range hooks.KnownEvents() {
237237
hookDispatcher.Register(ev, provenanceHandler)

pkg/hooks/builtin/policy.go

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,62 @@ package builtin
22

33
import (
44
"context"
5+
"errors"
56

67
"github.com/sipeed/picoclaw/pkg/hookpolicy"
78
"github.com/sipeed/picoclaw/pkg/hooks"
89
)
910

1011
// PolicyHandler applies workspace hook policy (HOOKS.md + hooks.yaml).
1112
type PolicyHandler struct {
12-
workspace string
13+
policy hookpolicy.Policy
14+
warnings []string
15+
loadErr error
1316
}
1417

15-
func NewPolicyHandler(workspace string) *PolicyHandler {
16-
return &PolicyHandler{workspace: workspace}
18+
func NewPolicyHandler(policy hookpolicy.Policy, diag hookpolicy.Diagnostics, loadErr error) *PolicyHandler {
19+
warnings := make([]string, 0, len(diag.Warnings))
20+
warnings = append(warnings, diag.Warnings...)
21+
return &PolicyHandler{
22+
policy: policy,
23+
warnings: warnings,
24+
loadErr: loadErr,
25+
}
1726
}
1827

1928
func (h *PolicyHandler) Name() string {
2029
return "policy"
2130
}
2231

2332
func (h *PolicyHandler) Handle(_ context.Context, ev hooks.Event, data hooks.Context) hooks.Result {
24-
policy, diag, err := hookpolicy.LoadPolicy(h.workspace)
25-
if err != nil {
33+
if h.loadErr != nil {
2634
return hooks.Result{
2735
Status: hooks.StatusError,
2836
Message: "failed to load hook policy",
29-
Err: err,
37+
Err: h.loadErr,
38+
}
39+
}
40+
if h.policy.Events == nil {
41+
return hooks.Result{
42+
Status: hooks.StatusError,
43+
Message: "hook policy missing event configuration",
44+
Err: errors.New("hook policy events are not initialized"),
3045
}
3146
}
3247

3348
meta := map[string]any{
34-
"policy_enabled": policy.Enabled,
49+
"policy_enabled": h.policy.Enabled,
3550
"turn_id": data.TurnID,
3651
}
37-
if len(diag.Warnings) > 0 {
38-
meta["warnings"] = diag.Warnings
52+
if len(h.warnings) > 0 {
53+
meta["warnings"] = h.warnings
3954
}
4055

41-
if !policy.Enabled {
56+
if !h.policy.Enabled {
4257
return hooks.Result{Status: hooks.StatusOK, Message: "hooks disabled by policy", Metadata: meta}
4358
}
4459

45-
eventPolicy, ok := policy.Events[ev]
60+
eventPolicy, ok := h.policy.Events[ev]
4661
if !ok {
4762
return hooks.Result{Status: hooks.StatusOK, Message: "event not configured", Metadata: meta}
4863
}

0 commit comments

Comments
 (0)