From abbb43d5cc71ff9f045cd4ed966aa943e29d5871 Mon Sep 17 00:00:00 2001 From: Dallin Romney Date: Fri, 21 Aug 2026 01:26:58 -0700 Subject: [PATCH] fix(approvals): bind portable actions to lifecycle --- extensions/discord/src/approval-custom-id.ts | 11 ++++- .../discord/src/approval-handler.runtime.ts | 5 ++ .../discord/src/monitor/exec-approvals.ts | 24 +++++++--- .../discord/src/shared-interactive.test.ts | 11 ++++- extensions/imessage/src/approval-native.ts | 1 + extensions/imessage/src/approval-reactions.ts | 12 ++++- extensions/slack/src/approval-actions.test.ts | 22 +++++++++ extensions/slack/src/approval-actions.ts | 19 +++++++- .../events/interactions.block-actions.ts | 1 + .../src/approval-callback-data.test.ts | 28 +++++++++++ .../telegram/src/approval-callback-data.ts | 46 +++++++++++++++---- .../telegram/src/approval-handler.runtime.ts | 1 + .../bot-handlers.callback-router-controls.ts | 1 + .../telegram/src/exec-approval-forwarding.ts | 1 + ...-agent-subscribe.handlers.tools.results.ts | 3 ++ src/gateway/exec-approval-manager.ts | 6 +++ src/gateway/operator-approval-store.ts | 7 ++- src/infra/approval-gateway-resolver.test.ts | 2 + src/infra/approval-gateway-resolver.ts | 4 ++ src/infra/approval-resolution-ref.test.ts | 18 ++++++++ src/infra/approval-resolution-ref.ts | 10 ++-- src/infra/approval-view-model.ts | 4 ++ src/infra/approval-view-model.types.ts | 1 + src/infra/exec-approval-reply.ts | 11 +++++ src/infra/plugin-approvals.ts | 1 + src/interactive/payload.ts | 11 ++++- src/plugin-sdk/approval-reaction-binding.ts | 9 +++- src/plugin-sdk/approval-reaction-runtime.ts | 1 + src/plugin-sdk/approval-renderers.ts | 5 ++ 29 files changed, 245 insertions(+), 31 deletions(-) diff --git a/extensions/discord/src/approval-custom-id.ts b/extensions/discord/src/approval-custom-id.ts index 05763cd89882..31b9c53e1f5f 100644 --- a/extensions/discord/src/approval-custom-id.ts +++ b/extensions/discord/src/approval-custom-id.ts @@ -11,6 +11,7 @@ function encodeDiscordApprovalCustomId(action: DiscordApprovalAction): string { return [ `execapproval:kind=${action.approvalKind}`, `id=${encodeURIComponent(action.approvalId)}`, + ...(action.instanceId ? [`instance=${encodeURIComponent(action.instanceId)}`] : []), `action=${action.decision}`, ].join(";"); } @@ -27,7 +28,9 @@ function encodeBoundedDiscordApprovalCustomId(action: DiscordApprovalAction): st approvalId: buildApprovalResolutionRef({ approvalId: action.approvalId, approvalKind: action.approvalKind, + instanceId: action.instanceId, }), + instanceId: undefined, }); } @@ -48,10 +51,12 @@ export function buildExecApprovalCustomId( approvalId: string, approvalKind: DiscordApprovalAction["approvalKind"], decision: DiscordApprovalAction["decision"], + instanceId?: string, ): string { return encodeBoundedDiscordApprovalCustomId({ type: "approval", approvalId, + ...(instanceId ? { instanceId } : {}), approvalKind, decision, }); @@ -67,6 +72,7 @@ function decodeCustomIdValue(value: string): string | null { export function parseExecApprovalData(data: ComponentData): { approvalId: string; + instanceId?: string; approvalKind: DiscordApprovalAction["approvalKind"]; action: DiscordApprovalAction["decision"]; } | null { @@ -78,6 +84,7 @@ export function parseExecApprovalData(data: ComponentData): { const rawId = coerce(data.id); const rawKind = coerce(data.kind); const rawAction = coerce(data.action); + const rawInstanceId = coerce(data.instance); if (!rawId || (rawKind !== "exec" && rawKind !== "plugin") || !rawAction) { return null; } @@ -85,11 +92,13 @@ export function parseExecApprovalData(data: ComponentData): { return null; } const approvalId = decodeCustomIdValue(rawId); - if (!approvalId) { + const instanceId = rawInstanceId ? decodeCustomIdValue(rawInstanceId) : undefined; + if (!approvalId || (rawInstanceId && !instanceId)) { return null; } return { approvalId, + ...(instanceId ? { instanceId } : {}), approvalKind: rawKind, action: rawAction, }; diff --git a/extensions/discord/src/approval-handler.runtime.ts b/extensions/discord/src/approval-handler.runtime.ts index a7443135b425..ceafee6f7829 100644 --- a/extensions/discord/src/approval-handler.runtime.ts +++ b/extensions/discord/src/approval-handler.runtime.ts @@ -128,6 +128,7 @@ class ExecApprovalActionButton extends Button { constructor(params: { approvalId: string; + instanceId?: string; approvalKind: PendingApprovalView["approvalKind"]; descriptor: ExecApprovalActionDescriptor; }) { @@ -136,6 +137,7 @@ class ExecApprovalActionButton extends Button { params.approvalId, params.approvalKind, params.descriptor.decision, + params.instanceId, ); this.label = params.descriptor.label; this.style = @@ -152,6 +154,7 @@ class ExecApprovalActionButton extends Button { class ExecApprovalActionRow extends Row