Files
openclaw/src/plugin-sdk/approval-renderers.ts
Val Alexander 43a941b51c fix(pair): render /pair qr as media (#70047)
* fix(pair): render pair qr as media

* fix(gateway): preserve media reply threading

* fix(gateway): harden webchat media replies

* fix(plugin-sdk): keep trustedLocalMedia internal

* docs(changelog): note pair qr media fix

* Update CHANGELOG with recent fixes and enhancements

Updated changelog to include recent fixes and enhancements.
2026-04-22 03:31:09 -05:00

98 lines
3.0 KiB
TypeScript

import {
buildApprovalInteractiveReply,
type ExecApprovalReplyDecision,
} from "../infra/exec-approval-reply.js";
import {
buildPluginApprovalRequestMessage,
buildPluginApprovalResolvedMessage,
type PluginApprovalRequest,
type PluginApprovalResolved,
} from "../infra/plugin-approvals.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import type { ReplyPayload } from "./reply-payload.js";
const DEFAULT_ALLOWED_DECISIONS = ["allow-once", "allow-always", "deny"] as const;
export function buildApprovalPendingReplyPayload(params: {
approvalKind?: "exec" | "plugin";
approvalId: string;
approvalSlug: string;
text: string;
agentId?: string | null;
allowedDecisions?: readonly ExecApprovalReplyDecision[];
sessionKey?: string | null;
channelData?: Record<string, unknown>;
}): ReplyPayload {
const allowedDecisions = params.allowedDecisions ?? DEFAULT_ALLOWED_DECISIONS;
return {
text: params.text,
interactive: buildApprovalInteractiveReply({
approvalId: params.approvalId,
allowedDecisions,
}),
channelData: {
execApproval: {
approvalId: params.approvalId,
approvalSlug: params.approvalSlug,
approvalKind: params.approvalKind ?? "exec",
agentId: normalizeOptionalString(params.agentId),
allowedDecisions,
sessionKey: normalizeOptionalString(params.sessionKey),
state: "pending",
},
...params.channelData,
},
};
}
export function buildApprovalResolvedReplyPayload(params: {
approvalId: string;
approvalSlug: string;
text: string;
channelData?: Record<string, unknown>;
}): ReplyPayload {
return {
text: params.text,
channelData: {
execApproval: {
approvalId: params.approvalId,
approvalSlug: params.approvalSlug,
state: "resolved",
},
...params.channelData,
},
};
}
export function buildPluginApprovalPendingReplyPayload(params: {
request: PluginApprovalRequest;
nowMs: number;
text?: string;
approvalSlug?: string;
allowedDecisions?: readonly ExecApprovalReplyDecision[];
channelData?: Record<string, unknown>;
}): ReplyPayload {
return buildApprovalPendingReplyPayload({
approvalKind: "plugin",
approvalId: params.request.id,
approvalSlug: params.approvalSlug ?? params.request.id.slice(0, 8),
text: params.text ?? buildPluginApprovalRequestMessage(params.request, params.nowMs),
allowedDecisions: params.allowedDecisions,
channelData: params.channelData,
});
}
export function buildPluginApprovalResolvedReplyPayload(params: {
resolved: PluginApprovalResolved;
text?: string;
approvalSlug?: string;
channelData?: Record<string, unknown>;
}): ReplyPayload {
return buildApprovalResolvedReplyPayload({
approvalId: params.resolved.id,
approvalSlug: params.approvalSlug ?? params.resolved.id.slice(0, 8),
text: params.text ?? buildPluginApprovalResolvedMessage(params.resolved),
channelData: params.channelData,
});
}