Policy
Policy: which tools may run, which need a person's approval.
noclick.Policy.set(deny=["*.delete_*"], require_approval=["gmail.send_email_message"])
noclick.Policy.set(allow=["search", "gmail.*"], user="user_42") # narrows the account policyPatterns match dotted tool names (gmail.*, *.delete_*, search).
Deny wins; an empty allow allows everything the other rules don't stop.
Like every call, get, set and evaluate follow as_user: inside it they
address that user's policy, and user=None addresses the account's. A rule can
also be a noclick.Rule with a condition on the call's arguments and a person
who approves it.
class PolicyThe account's policy, or one user's (user_id). Each list holds patterns,
and Rules where a rule has a condition or an approver.
| allow | (string | Rule)[] | Patterns, and |
| deny | (string | Rule)[] | |
| requireApproval | (string | Rule)[] | |
| userId | string | null | Whose policy this is (your id for the user; null for the account's). |
| raw | JsonObject | The response JSON exactly as the API sent it. |
liststatic
static list(options?: { client?: NoClick }): Promise<Policy[]>The account's policy and every user policy.
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
The account's policy first (its user_id is None), then each user that has a policy of
its own, with your id for that user as its user_id.
evaluatestatic
static evaluate(
tools: string | readonly string[],
options?: PolicyOptions & { draft?: PolicyDraft; arguments?: JsonObject },
): Promise<PolicyVerdict[]>How the policy judges each of tools (dotted or wire names, at most 500) for the account,
or { user }. A draft is judged in place of its layer's saved rules. Nothing runs and
no approval is requested. arguments judges one tool's call with those
arguments, so rules with a when apply; without them a rule with a when never matches.
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
One verdict per tool, in order: allow, deny or approval, with the matched_pattern
and layer that decided it, and the whole rule. matched_pattern is None when no rule
matched, or when an allow list left the tool out.
getstatic
static get(options?: PolicyOptions): Promise<Policy>The account's policy, or with { user } that user's own rules.
The allow, deny and require_approval lists, empty where nothing is set. A user's
policy holds only its own rules, not the account's.
setstatic
static set(rules: PolicyRules, options?: PolicyOptions): Promise<Policy>Replace the policy: lists left out are sent empty.
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
The saved policy, its patterns lowercased and deduplicated. A list you left out is now empty.
addstatic
static add(
rules: readonly RuleInput[],
options?: PolicyOptions & { to?: "requireApproval" | "deny" | "allow" },
): Promise<Policy>Add rules to one list (to: requireApproval by default, deny or allow) of the account's
policy (or { user }'s), leaving every other rule as it is, in one change on the server. A rule
for a tool that list already has replaces it, so code that owns a rule can add it on every run.
await Policy.add(["quickbooks.create_bill"]);
await Policy.add(["slack.*"], { to: "deny", user: "user_42" });The client to send with; defaults to the module client built from NOCLICK_API_KEY.
The saved policy, with the rest of its rules.
removestatic
static remove(
tools: readonly string[],
options?: PolicyOptions,
): Promise<Policy>Remove the rules for these tools, as written, from every list of the account's policy (or
{ user }'s), leaving the rest. A tool with no rule changes nothing.
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
The saved policy, with the rules that are left.
PolicyVerdict
interface PolicyVerdictWhat a policy decides for one tool, and which rule decided it.
| tool | string | The tool's dotted name. |
| verdict | "allow" | "deny" | "approval" | |
| matchedPattern | string | null | |
| layer | string | null |
|
| raw | JsonObject | The response JSON exactly as the API sent it. |
| rule | string | Rule | null | The rule that decided, whole: a pattern or a |
Rule
class RuleA policy rule that says more than a pattern: tool is the pattern, when a CEL expression the
call must satisfy for the rule to apply, over args (the call's final arguments, bound ones
included) and user (id, email, name, metadata), and approver who approves it in
requireApproval: a Human (new Human() for the user the call is made for) or an email; it's
emailed the approval, and only it may answer. Without an approver the owner of what the call
acts in approves, as for a pattern. A call when can't judge (an argument it lacks, values that
don't compare) meets a deny or requireApproval rule and misses an allow one; numbers
compare within their own type (double(args.amount) > 99.5 for an amount with a fraction).
message, on a deny rule, is what the call's refusal says in your words, so the agent can tell
the user what to do ("Web search comes with Pro: https://..."); {{user.*}} in it is filled in for
whom the call is for.
await Policy.add([new Rule("stripe.create_refund", { when: "args.amount > 10000", approver: "finance@acme.com" })]);| tool | string | |
| when | string | null | |
| approver | Human | string | null | |
| message | string | null | What a |