use serde_json::Value;
use super::Verb;
pub const ANSWER: Verb = Verb {
word: "answer",
params: &["workspace", "agent", "verdict"],
flags: &[],
summary: "release, decline or keep parked the tool call held at this conversation",
detail: "Answers the invocation the capability boundary parked before it \
ran. `pass` lets that one call through, `refuse` declines it in \
band — the model is told the decision stands and told not to \
retry it, rephrase it or reach the same outcome another way — and \
`hold` keeps it parked even if the policy later would have passed \
it. Which call is answered is read from the conversation's own \
hold mark, so nothing is typed and nothing can be spent by a \
different call. A fourth word says how far the answer stands. \
Left off it settles that one call, which is the safe reading and \
the one you get without asking for anything; `conversation` \
settles the whole class of the held call — the same tool at the \
same reach — for this conversation and everything below it, and \
`workspace` settles that class for every conversation there. A \
wider answer is how you stop being asked eleven times about one \
narrow tool; `revoke` suspends every standing answer, which is \
how you take one back. A destructive or credential-reaching call \
takes the bare form only. Passing or refusing then drives the \
conversation on, which is what actually lifts the hold. Nothing \
here stops the agent. Refused when nothing is held there.",
};
pub const REVOKE: Verb = Verb {
word: "revoke",
params: &["workspace", "agent"],
flags: &[],
summary: "take away this conversation's tool auto-approval, and its descendants'",
detail: "Stops letting the conversation act on its own: from its next tool \
call, everything but a read waits for you. It keeps running, \
keeps its branch and keeps reading, so nothing is lost and \
nothing is killed. It covers the conversation and everything \
below it, including children it has not spawned yet. Anything the \
policy already refuses stays refused, and a call passed with \
`answer` still goes through.",
};
pub const RESTORE: Verb = Verb {
word: "restore",
params: &["workspace", "agent"],
flags: &[],
summary: "give this conversation's tool auto-approval back",
detail: "Lifts a floor `revoke` put on the conversation: its calls are \
adjudicated by the ordinary policy again, from its next one. It \
drives nothing — a conversation parked at a held call is released \
by answering that call. If an ancestor is still revoked the \
conversation stays floored under it, and the reply says so rather \
than claiming a restore it did not make.",
};
pub const VERDICTS: [&str; 3] = ["pass", "refuse", "hold"];
pub const SCOPE: &str = "scope";
pub const SCOPES: [&str; 3] = ["call", "conversation", "workspace"];
pub const CALL: &str = "call";
pub fn answer(workspace: String, agent: String, verdict: String, scope: Option<String>) -> Value {
ANSWER.stating(
vec![workspace, agent, verdict],
SCOPE,
Some(scope.unwrap_or_else(|| CALL.to_owned())),
)
}
pub fn revoke(workspace: String, agent: String) -> Value {
REVOKE.built(vec![workspace, agent], &[])
}
pub fn restore(workspace: String, agent: String) -> Value {
RESTORE.built(vec![workspace, agent], &[])
}
#[cfg(test)]
mod tests;