mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-07-12 11:07:03 +00:00
aa1b2f026a
Exposes agent hooks over WebSocket (hooks.list/create/update/delete/ toggle/test/history) behind existing auth layer. Additions: - Gateway wiring: buildHookHandlers() factory reused by dispatcher and hooks.test runner, so UI test panel exercises production code paths - GetByID tenant-scope guard: non-master callers only see own tenant + global rows (matches List() behavior on both PG and SQLite) - i18n keys + catalogs (en/vi/zh) for hooks error messages - Protocol method constants for hooks.* and config.defaults
62 lines
1.8 KiB
Go
62 lines
1.8 KiB
Go
package methods
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/hooks"
|
|
)
|
|
|
|
// DispatcherTestRunner is a HookTestRunner that invokes a registered handler
|
|
// one-shot without writing to hook_executions. Used by `hooks.test` WS method
|
|
// to power the Web UI test panel. dryRun-by-construction: no store writes.
|
|
//
|
|
// Handlers is expected to be the same map passed to the production dispatcher
|
|
// (command + http + prompt). Missing handler → DecisionError result.
|
|
type DispatcherTestRunner struct {
|
|
Handlers map[hooks.HandlerType]hooks.Handler
|
|
}
|
|
|
|
// NewDispatcherTestRunner returns a test runner sharing handlers with the
|
|
// production dispatcher. Panics if handlers is nil.
|
|
func NewDispatcherTestRunner(handlers map[hooks.HandlerType]hooks.Handler) *DispatcherTestRunner {
|
|
if handlers == nil {
|
|
handlers = map[hooks.HandlerType]hooks.Handler{}
|
|
}
|
|
return &DispatcherTestRunner{Handlers: handlers}
|
|
}
|
|
|
|
// RunTest implements HookTestRunner. Enforces the per-hook timeout, captures
|
|
// duration, and maps handler return values into HookTestResult. Does NOT
|
|
// call the audit writer.
|
|
func (r *DispatcherTestRunner) RunTest(ctx context.Context, cfg hooks.HookConfig, ev hooks.Event) HookTestResult {
|
|
h, ok := r.Handlers[cfg.HandlerType]
|
|
if !ok {
|
|
return HookTestResult{
|
|
Decision: hooks.DecisionError,
|
|
Error: fmt.Sprintf("no handler registered for %q", cfg.HandlerType),
|
|
}
|
|
}
|
|
|
|
timeout := 5 * time.Second
|
|
if cfg.TimeoutMS > 0 {
|
|
timeout = time.Duration(cfg.TimeoutMS) * time.Millisecond
|
|
}
|
|
hctx, cancel := context.WithTimeout(ctx, timeout)
|
|
defer cancel()
|
|
|
|
start := time.Now()
|
|
dec, err := h.Execute(hctx, cfg, ev)
|
|
durationMS := int(time.Since(start) / time.Millisecond)
|
|
|
|
res := HookTestResult{
|
|
Decision: dec,
|
|
DurationMS: durationMS,
|
|
}
|
|
if err != nil {
|
|
res.Error = err.Error()
|
|
}
|
|
return res
|
|
}
|