package tool import "fmt" // CheckGate returns an error if the invocation context's SkillName does // not match the tool's gate. Tools should call this at the top of their // handler when their Permission has a non-empty SkillNameGate. // // Why: the gate is enforced per-call (not per-build) because the same // Tool may be referenced by multiple skills, only one of which is // gate-eligible. Build cannot know in advance which skill will call it // — that's per-Invocation. // // What: returns nil if no gate, or the names match. Returns an error // suitable for surfacing to the LLM as the tool's failure result. func CheckGate(inv Invocation) error { if inv.gate == "" { return nil } if inv.currentSkill == inv.gate { return nil } return fmt.Errorf("tool %q is restricted to the %q skill", inv.toolName, inv.gate) } // EmitAudit forwards a tool's call+result to the audit hook, if one is // wired. Tools should call this once per Execute, after the underlying // work has completed (regardless of error). Pass the original args // JSON, the result string, and any error. // // Why: keeping the audit emission inside the tool ensures the captured // args are exactly what the tool ran with (after coercion / defaults), // not the raw LLM JSON which can drift. func EmitAudit(inv Invocation, args, result string, err error) { if inv.audit == nil { return } inv.audit(AuditCall{ Tool: inv.toolName, Args: args, Result: result, Err: err, }) }