openclaw/scripts/control-ui-mock-preview.ts
Peter Steinberger ad7534cc7f
feat(custodian): recommend a chief of staff and specialist roles when creating an agent (#141453)
* feat(agents): add role templates and team onboarding

Add bundled coordinator, researcher, writer, and reviewer workspace programs
with complete identities through agents add --role. Add agents team create
and guided/non-interactive onboard --team using the existing creation owner.

Keep fleet ownership explicit, preserve existing agents and ambient owners,
and target the coordinator explicitly after onboarding. Preflight normalized
ID conflicts and distinguish fresh main placeholders from established agents.
Keep normalized agent-creation JSON machine-readable.

Reuse scalar option validation and test setup helpers without adding config
keys, dependencies, global delegation policy, or store schemas.

* fix(cli): align setup team flags and command JSON classification

* refactor(agents): express role templates as Claw sources

* fix(agents): reject role adoption before publishing workspace files

* feat(custodian): recommend agent roles and teams

Offer catalog-backed Chief of staff, specialist, team, and custom choices
from New agent, and seed approved creations through the CLI lifecycle owners.
Keep coordinator as the role id without adding CLI flags or config keys.

Carry host requester provenance through team creation and report committed
members when later creation or bookkeeping fails. Record those partial
outcomes for operator visibility and post-write verification.

Update role documentation and the mock custodian welcome.
2026-09-12 01:02:39 -07:00

118 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type {
SystemAgentChatQuestion,
SystemAgentChatResult,
} from "../packages/gateway-protocol/src/index.js";
import type { ControlUiMockGateway } from "../ui/src/test-helpers/control-ui-e2e.ts";
// Serialized into the preview page; runtime dependencies must stay inside this function.
function installControlUiPreview(newAgentWelcome: string): void {
const previewWindow = window as Window & {
__OPENCLAW_NATIVE_CONTROL_AUTH__?: { gatewayUrl: string };
openclawControlUiE2eGateway?: ControlUiMockGateway;
};
// The WebSocket mock does not intercept HTTP. Select this origin before
// application startup can send synthetic resources to the operator Gateway.
const gatewayUrl = new URL(window.location.origin);
gatewayUrl.protocol = gatewayUrl.protocol === "https:" ? "wss:" : "ws:";
gatewayUrl.pathname = "/__openclaw_mock_gateway__";
previewWindow["__OPENCLAW_NATIVE_CONTROL_AUTH__"] = { gatewayUrl: gatewayUrl.toString() };
const gateway = previewWindow.openclawControlUiE2eGateway;
if (!gateway) {
throw new Error("Preview Gateway must be installed before its request handlers");
}
gateway.setRequestHandler("chat.send", ({ params, respond, emit }) => {
const input = params && typeof params === "object" ? (params as Record<string, unknown>) : {};
const runId =
typeof input.idempotencyKey === "string" && input.idempotencyKey.trim()
? input.idempotencyKey
: "control-ui-mock-run";
const sessionKey =
typeof input.sessionKey === "string" && input.sessionKey.trim()
? input.sessionKey
: "agent:main:main";
const message = typeof input.message === "string" ? input.message.trim() : "";
window.setTimeout(() => {
respond({ runId, status: "started" });
// The client must observe admission before the final event for this run.
window.setTimeout(
() =>
emit("chat", {
message: {
content: [{ text: `Mock reply: ${message || "message received"}`, type: "text" }],
role: "assistant",
timestamp: Date.now(),
},
runId,
seq: 1,
sessionKey,
state: "final",
}),
0,
);
}, 200);
});
const sessionTurns = new Map<string, number>();
const channelQuestion = {
id: "mock-channel-choice",
header: "Channel setup",
question: "Which channel would you like to work on?",
options: [
{
label: "WhatsApp",
reply: "help me connect WhatsApp",
description: "Review linking and account status.",
recommended: true,
},
{
label: "Telegram",
reply: "help me connect Telegram",
description: "Review the bot token and delivery status.",
},
{
label: "Discord",
reply: "help me connect Discord",
description: "Review the bot and server connection.",
},
],
isOther: true,
} satisfies SystemAgentChatQuestion;
gateway.setRequestHandler("openclaw.chat", ({ params, respond }) => {
const input = params && typeof params === "object" ? (params as Record<string, unknown>) : {};
const sessionId =
typeof input.sessionId === "string" && input.sessionId.trim()
? input.sessionId
: "control-ui-custodian-mock";
const message = typeof input.message === "string" ? input.message : undefined;
const turn = sessionTurns.get(sessionId) ?? 0;
sessionTurns.set(sessionId, turn + 1);
const response: SystemAgentChatResult = message
? message.toLowerCase().includes("channel")
? {
sessionId,
reply: "I can help with that.\n\nChoose a channel to continue.",
action: "none",
question: channelQuestion,
}
: {
sessionId,
reply: `I checked the mock system. Everything looks healthy.\n\nThat was demo turn ${turn}.`,
action: "none",
}
: {
sessionId,
reply:
input.welcomeVariant === "new-agent"
? newAgentWelcome
: "Hi — I’m OpenClaw, your system caretaker.\n\nAsk me about setup, channels, or recent changes.",
action: "none",
};
window.setTimeout(() => respond(response), message === undefined ? 0 : 600);
});
}
export function createControlUiPreviewInitScript(newAgentWelcome: string): string {
return `(() => { const __name = (target) => target; (${installControlUiPreview.toString()})(${JSON.stringify(newAgentWelcome)}); })();`;
}