mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-03 10:21:40 +00:00
New openclaw delegation tool relays to openclaw.chat in-process; persistent writes surface through the existing durable operator-approval registry as a third system-agent kind (no parallel store), armed only by a human operator in the Control UI — a delegated agent can never self-approve. Setup wizards (channel/model/open-setup/open-tui) are refused in delegated mode so a machine agent cannot complete setup or persist credentials unattended. Vendor-neutral inference fallback ladder (requester route first, then other authed providers by provider id). update.run removed from the gateway tool. Caveman system-prompt fragment steers config/channels/plugins/agents/updates to the openclaw tool. Doctor-owned state migration widens the approval-kind constraint; runtime stays canonical-only. Refs #107237
44 lines
1.5 KiB
TypeScript
44 lines
1.5 KiB
TypeScript
// Human-only arming for delegated OpenClaw changes.
|
|
import { hashSystemAgentOperation } from "../agents/tools/system-agent-tool.js";
|
|
import { isPersistentSystemAgentOperation, type SystemAgentOperation } from "./operations.js";
|
|
|
|
type ProposalRef = { current?: string; operation?: SystemAgentOperation };
|
|
|
|
export function resolvePendingOperatorProposal(
|
|
pending: SystemAgentOperation | null,
|
|
proposalRef: ProposalRef,
|
|
): { operation: SystemAgentOperation; hash: string } | null {
|
|
const operation = pending ?? proposalRef.operation;
|
|
if (!operation || !isPersistentSystemAgentOperation(operation)) {
|
|
return null;
|
|
}
|
|
const hash = hashSystemAgentOperation(operation);
|
|
if (proposalRef.current && proposalRef.current !== hash) {
|
|
return null;
|
|
}
|
|
proposalRef.current = hash;
|
|
proposalRef.operation = operation;
|
|
return { operation, hash };
|
|
}
|
|
|
|
export async function resolveOperatorApprovalDecision<T>(params: {
|
|
decision: "allow-once" | "allow-always" | "deny" | null;
|
|
proposalHash: string;
|
|
getProposal: () => { hash: string } | null;
|
|
clear: () => void;
|
|
apply: (message: string) => Promise<T>;
|
|
denied: () => T;
|
|
}): Promise<T | null> {
|
|
const proposal = params.getProposal();
|
|
if (!proposal || proposal.hash !== params.proposalHash) {
|
|
return null;
|
|
}
|
|
if (params.decision !== "allow-once") {
|
|
params.clear();
|
|
return params.denied();
|
|
}
|
|
return await params.apply(
|
|
`[operator-approved] Human approved ${params.proposalHash}. Apply exact proposal; approved=true.`,
|
|
);
|
|
}
|