diff --git a/extensions/discord/src/approval-native.ts b/extensions/discord/src/approval-native.ts index 3841617d280..a1b522283c5 100644 --- a/extensions/discord/src/approval-native.ts +++ b/extensions/discord/src/approval-native.ts @@ -1,4 +1,4 @@ -import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime"; +import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; import { resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime"; import type { DiscordExecApprovalConfig, OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import type { ExecApprovalRequest, PluginApprovalRequest } from "openclaw/plugin-sdk/infra-runtime"; diff --git a/extensions/discord/src/monitor/exec-approvals.ts b/extensions/discord/src/monitor/exec-approvals.ts index 0043fffb610..f907a744f80 100644 --- a/extensions/discord/src/monitor/exec-approvals.ts +++ b/extensions/discord/src/monitor/exec-approvals.ts @@ -1,6 +1,6 @@ import { Button, type ButtonInteraction, type ComponentData } from "@buape/carbon"; import { ButtonStyle } from "discord-api-types/v10"; -import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-handler-runtime"; +import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-gateway-runtime"; import type { DiscordExecApprovalConfig, OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import type { ExecApprovalDecision, diff --git a/extensions/discord/src/monitor/provider.ts b/extensions/discord/src/monitor/provider.ts index d04b75a8a36..8128442c69f 100644 --- a/extensions/discord/src/monitor/provider.ts +++ b/extensions/discord/src/monitor/provider.ts @@ -8,7 +8,7 @@ import { } from "@buape/carbon"; import { GatewayCloseCodes, type GatewayPlugin } from "@buape/carbon/gateway"; import { Routes } from "discord-api-types/v10"; -import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-runtime"; +import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context"; import { listNativeCommandSpecsForConfig, diff --git a/extensions/matrix/src/approval-native.ts b/extensions/matrix/src/approval-native.ts index 914068667a4..dc1c2439e1e 100644 --- a/extensions/matrix/src/approval-native.ts +++ b/extensions/matrix/src/approval-native.ts @@ -3,7 +3,7 @@ import { createApproverRestrictedNativeApprovalCapability, splitChannelApprovalCapability, } from "openclaw/plugin-sdk/approval-delivery-runtime"; -import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime"; +import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; import { createChannelNativeOriginTargetResolver, resolveApprovalRequestSessionConversation, diff --git a/extensions/matrix/src/exec-approval-resolver.ts b/extensions/matrix/src/exec-approval-resolver.ts index c5e9002eac1..fd004ae9a85 100644 --- a/extensions/matrix/src/exec-approval-resolver.ts +++ b/extensions/matrix/src/exec-approval-resolver.ts @@ -1,4 +1,4 @@ -import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-handler-runtime"; +import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-gateway-runtime"; import type { ExecApprovalReplyDecision } from "openclaw/plugin-sdk/approval-runtime"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { isApprovalNotFoundError } from "openclaw/plugin-sdk/error-runtime"; diff --git a/extensions/matrix/src/matrix/monitor/index.ts b/extensions/matrix/src/matrix/monitor/index.ts index 78d87e3e03c..13b3918ed11 100644 --- a/extensions/matrix/src/matrix/monitor/index.ts +++ b/extensions/matrix/src/matrix/monitor/index.ts @@ -1,5 +1,5 @@ import { format } from "node:util"; -import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-runtime"; +import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context"; import { GROUP_POLICY_BLOCKED_LABEL, diff --git a/extensions/slack/src/approval-native.ts b/extensions/slack/src/approval-native.ts index 646b70b6183..dca5d896ef6 100644 --- a/extensions/slack/src/approval-native.ts +++ b/extensions/slack/src/approval-native.ts @@ -2,7 +2,7 @@ import { createApproverRestrictedNativeApprovalCapability, splitChannelApprovalCapability, } from "openclaw/plugin-sdk/approval-delivery-runtime"; -import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime"; +import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; import { createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, diff --git a/extensions/slack/src/monitor/provider.ts b/extensions/slack/src/monitor/provider.ts index a9f5838d613..bf4f481d557 100644 --- a/extensions/slack/src/monitor/provider.ts +++ b/extensions/slack/src/monitor/provider.ts @@ -7,7 +7,7 @@ import { patchAllowlistUsersInConfigEntries, summarizeMapping, } from "openclaw/plugin-sdk/allow-from"; -import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-runtime"; +import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context"; import type { SessionScope } from "openclaw/plugin-sdk/config-runtime"; import { createConnectedChannelStatusPatch } from "openclaw/plugin-sdk/gateway-runtime"; diff --git a/extensions/telegram/src/approval-native.ts b/extensions/telegram/src/approval-native.ts index 82b45132610..e6ddc42d231 100644 --- a/extensions/telegram/src/approval-native.ts +++ b/extensions/telegram/src/approval-native.ts @@ -2,7 +2,7 @@ import { createApproverRestrictedNativeApprovalCapability, splitChannelApprovalCapability, } from "openclaw/plugin-sdk/approval-delivery-runtime"; -import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime"; +import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; import { createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, diff --git a/extensions/telegram/src/exec-approval-resolver.ts b/extensions/telegram/src/exec-approval-resolver.ts index bf6ee63e52c..b4e45a1f609 100644 --- a/extensions/telegram/src/exec-approval-resolver.ts +++ b/extensions/telegram/src/exec-approval-resolver.ts @@ -1,4 +1,4 @@ -import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-handler-runtime"; +import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-gateway-runtime"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import type { ExecApprovalReplyDecision } from "openclaw/plugin-sdk/infra-runtime"; diff --git a/extensions/telegram/src/monitor.ts b/extensions/telegram/src/monitor.ts index 37e37327e62..59b5db11fca 100644 --- a/extensions/telegram/src/monitor.ts +++ b/extensions/telegram/src/monitor.ts @@ -1,5 +1,5 @@ import type { RunOptions } from "@grammyjs/runner"; -import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-runtime"; +import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; import type { PluginRuntime } from "openclaw/plugin-sdk/channel-core"; import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context"; import { resolveAgentMaxConcurrent } from "openclaw/plugin-sdk/config-runtime"; diff --git a/package.json b/package.json index 3714a2ec7a4..f1b9061c5d0 100644 --- a/package.json +++ b/package.json @@ -116,6 +116,14 @@ "types": "./dist/plugin-sdk/approval-delivery-runtime.d.ts", "default": "./dist/plugin-sdk/approval-delivery-runtime.js" }, + "./plugin-sdk/approval-gateway-runtime": { + "types": "./dist/plugin-sdk/approval-gateway-runtime.d.ts", + "default": "./dist/plugin-sdk/approval-gateway-runtime.js" + }, + "./plugin-sdk/approval-handler-adapter-runtime": { + "types": "./dist/plugin-sdk/approval-handler-adapter-runtime.d.ts", + "default": "./dist/plugin-sdk/approval-handler-adapter-runtime.js" + }, "./plugin-sdk/approval-handler-runtime": { "types": "./dist/plugin-sdk/approval-handler-runtime.d.ts", "default": "./dist/plugin-sdk/approval-handler-runtime.js" diff --git a/src/infra/approval-handler-adapter-runtime.ts b/src/infra/approval-handler-adapter-runtime.ts new file mode 100644 index 00000000000..90a513de07b --- /dev/null +++ b/src/infra/approval-handler-adapter-runtime.ts @@ -0,0 +1,85 @@ +import { createLazyRuntimeModule } from "../shared/lazy-runtime.js"; +import type { + ChannelApprovalNativeAvailabilityAdapter, + ChannelApprovalNativeRuntimeAdapter, +} from "./approval-handler-runtime.js"; +import type { ExecApprovalChannelRuntimeEventKind } from "./exec-approval-channel-runtime.js"; + +export const CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY = "approval.native"; + +type LazyChannelApprovalNativeRuntimeParams = { + load: () => Promise; + isConfigured: ChannelApprovalNativeAvailabilityAdapter["isConfigured"]; + shouldHandle: ChannelApprovalNativeAvailabilityAdapter["shouldHandle"]; + eventKinds?: readonly ExecApprovalChannelRuntimeEventKind[]; + resolveApprovalKind?: ChannelApprovalNativeRuntimeAdapter["resolveApprovalKind"]; +}; + +export function createLazyChannelApprovalNativeRuntimeAdapter( + params: LazyChannelApprovalNativeRuntimeParams, +): ChannelApprovalNativeRuntimeAdapter { + const loadRuntime = createLazyRuntimeModule(params.load); + let loadedRuntime: ChannelApprovalNativeRuntimeAdapter | null = null; + const loadResolvedRuntime = async (): Promise => { + const runtime = await loadRuntime(); + loadedRuntime = runtime; + return runtime; + }; + const loadRequired = async ( + select: (runtime: ChannelApprovalNativeRuntimeAdapter) => TResult, + ): Promise => select(await loadResolvedRuntime()); + const loadOptional = async ( + select: (runtime: ChannelApprovalNativeRuntimeAdapter) => TResult | undefined, + ): Promise => select(await loadResolvedRuntime()); + + return { + ...(params.eventKinds ? { eventKinds: params.eventKinds } : {}), + ...(params.resolveApprovalKind ? { resolveApprovalKind: params.resolveApprovalKind } : {}), + availability: { + isConfigured: params.isConfigured, + shouldHandle: params.shouldHandle, + }, + presentation: { + buildPendingPayload: async (runtimeParams) => + (await loadRequired((runtime) => runtime.presentation.buildPendingPayload))(runtimeParams), + buildResolvedResult: async (runtimeParams) => + (await loadRequired((runtime) => runtime.presentation.buildResolvedResult))(runtimeParams), + buildExpiredResult: async (runtimeParams) => + (await loadRequired((runtime) => runtime.presentation.buildExpiredResult))(runtimeParams), + }, + transport: { + prepareTarget: async (runtimeParams) => + (await loadRequired((runtime) => runtime.transport.prepareTarget))(runtimeParams), + deliverPending: async (runtimeParams) => + (await loadRequired((runtime) => runtime.transport.deliverPending))(runtimeParams), + updateEntry: async (runtimeParams) => + await ( + await loadOptional((runtime) => runtime.transport.updateEntry) + )?.(runtimeParams), + deleteEntry: async (runtimeParams) => + await ( + await loadOptional((runtime) => runtime.transport.deleteEntry) + )?.(runtimeParams), + }, + interactions: { + bindPending: async (runtimeParams) => + (await loadOptional((runtime) => runtime.interactions?.bindPending))?.(runtimeParams), + unbindPending: async (runtimeParams) => + await ( + await loadOptional((runtime) => runtime.interactions?.unbindPending) + )?.(runtimeParams), + clearPendingActions: async (runtimeParams) => + await ( + await loadOptional((runtime) => runtime.interactions?.clearPendingActions) + )?.(runtimeParams), + }, + observe: { + // Observe hooks are fire-and-forget at call sites. Reuse the already + // loaded runtime instead of introducing unawaited lazy-load promises. + onDeliveryError: (runtimeParams) => loadedRuntime?.observe?.onDeliveryError?.(runtimeParams), + onDuplicateSkipped: (runtimeParams) => + loadedRuntime?.observe?.onDuplicateSkipped?.(runtimeParams), + onDelivered: (runtimeParams) => loadedRuntime?.observe?.onDelivered?.(runtimeParams), + }, + }; +} diff --git a/src/infra/approval-handler-runtime.ts b/src/infra/approval-handler-runtime.ts index 067814d012d..39282d67205 100644 --- a/src/infra/approval-handler-runtime.ts +++ b/src/infra/approval-handler-runtime.ts @@ -5,8 +5,11 @@ import type { } from "../channels/plugins/types.adapters.js"; import type { OpenClawConfig } from "../config/config.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; -import { createLazyRuntimeModule } from "../shared/lazy-runtime.js"; import { resolveApprovalOverGateway } from "./approval-gateway-resolver.js"; +import { + CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY, + createLazyChannelApprovalNativeRuntimeAdapter, +} from "./approval-handler-adapter-runtime.js"; import type { ChannelApprovalNativePlannedTarget } from "./approval-native-delivery.js"; import { createChannelNativeApprovalRuntime, @@ -46,10 +49,13 @@ export type { ResolvedApprovalView, } from "./approval-view-model.js"; export { resolveApprovalOverGateway }; +export { + CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY, + createLazyChannelApprovalNativeRuntimeAdapter, +}; type ApprovalRequest = ExecApprovalRequest | PluginApprovalRequest; type ApprovalResolved = ExecApprovalResolved | PluginApprovalResolved; -export const CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY = "approval.native"; export type ChannelApprovalHandler< TRequest extends ApprovalRequest = ApprovalRequest, @@ -584,83 +590,6 @@ export function createChannelApprovalNativeRuntimeAdapter< }; } -type LazyChannelApprovalNativeRuntimeParams = { - load: () => Promise; - isConfigured: ChannelApprovalNativeAvailabilityAdapter["isConfigured"]; - shouldHandle: ChannelApprovalNativeAvailabilityAdapter["shouldHandle"]; - eventKinds?: readonly ExecApprovalChannelRuntimeEventKind[]; - resolveApprovalKind?: ChannelApprovalNativeRuntimeAdapter["resolveApprovalKind"]; -}; - -export function createLazyChannelApprovalNativeRuntimeAdapter( - params: LazyChannelApprovalNativeRuntimeParams, -): ChannelApprovalNativeRuntimeAdapter { - const loadRuntime = createLazyRuntimeModule(params.load); - let loadedRuntime: ChannelApprovalNativeRuntimeAdapter | null = null; - const loadResolvedRuntime = async (): Promise => { - const runtime = await loadRuntime(); - loadedRuntime = runtime; - return runtime; - }; - const loadRequired = async ( - select: (runtime: ChannelApprovalNativeRuntimeAdapter) => TResult, - ): Promise => select(await loadResolvedRuntime()); - const loadOptional = async ( - select: (runtime: ChannelApprovalNativeRuntimeAdapter) => TResult | undefined, - ): Promise => select(await loadResolvedRuntime()); - - return { - ...(params.eventKinds ? { eventKinds: params.eventKinds } : {}), - ...(params.resolveApprovalKind ? { resolveApprovalKind: params.resolveApprovalKind } : {}), - availability: { - isConfigured: params.isConfigured, - shouldHandle: params.shouldHandle, - }, - presentation: { - buildPendingPayload: async (runtimeParams) => - (await loadRequired((runtime) => runtime.presentation.buildPendingPayload))(runtimeParams), - buildResolvedResult: async (runtimeParams) => - (await loadRequired((runtime) => runtime.presentation.buildResolvedResult))(runtimeParams), - buildExpiredResult: async (runtimeParams) => - (await loadRequired((runtime) => runtime.presentation.buildExpiredResult))(runtimeParams), - }, - transport: { - prepareTarget: async (runtimeParams) => - (await loadRequired((runtime) => runtime.transport.prepareTarget))(runtimeParams), - deliverPending: async (runtimeParams) => - (await loadRequired((runtime) => runtime.transport.deliverPending))(runtimeParams), - updateEntry: async (runtimeParams) => - await ( - await loadOptional((runtime) => runtime.transport.updateEntry) - )?.(runtimeParams), - deleteEntry: async (runtimeParams) => - await ( - await loadOptional((runtime) => runtime.transport.deleteEntry) - )?.(runtimeParams), - }, - interactions: { - bindPending: async (runtimeParams) => - (await loadOptional((runtime) => runtime.interactions?.bindPending))?.(runtimeParams), - unbindPending: async (runtimeParams) => - await ( - await loadOptional((runtime) => runtime.interactions?.unbindPending) - )?.(runtimeParams), - clearPendingActions: async (runtimeParams) => - await ( - await loadOptional((runtime) => runtime.interactions?.clearPendingActions) - )?.(runtimeParams), - }, - observe: { - // Observe hooks are fire-and-forget at call sites. Reuse the already - // loaded runtime instead of introducing unawaited lazy-load promises. - onDeliveryError: (runtimeParams) => loadedRuntime?.observe?.onDeliveryError?.(runtimeParams), - onDuplicateSkipped: (runtimeParams) => - loadedRuntime?.observe?.onDuplicateSkipped?.(runtimeParams), - onDelivered: (runtimeParams) => loadedRuntime?.observe?.onDelivered?.(runtimeParams), - }, - }; -} - export type ChannelApprovalHandlerRuntimeSpec = { label: string; clientDisplayName: string; diff --git a/src/plugin-sdk/approval-gateway-runtime.ts b/src/plugin-sdk/approval-gateway-runtime.ts new file mode 100644 index 00000000000..6422655c267 --- /dev/null +++ b/src/plugin-sdk/approval-gateway-runtime.ts @@ -0,0 +1 @@ +export { resolveApprovalOverGateway } from "../infra/approval-gateway-resolver.js"; diff --git a/src/plugin-sdk/approval-handler-adapter-runtime.ts b/src/plugin-sdk/approval-handler-adapter-runtime.ts new file mode 100644 index 00000000000..a3a45436d55 --- /dev/null +++ b/src/plugin-sdk/approval-handler-adapter-runtime.ts @@ -0,0 +1,4 @@ +export { + CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY, + createLazyChannelApprovalNativeRuntimeAdapter, +} from "../infra/approval-handler-adapter-runtime.js"; diff --git a/src/plugin-sdk/approval-handler-runtime.ts b/src/plugin-sdk/approval-handler-runtime.ts index 9a835f8dc74..8c3f8d08324 100644 --- a/src/plugin-sdk/approval-handler-runtime.ts +++ b/src/plugin-sdk/approval-handler-runtime.ts @@ -3,7 +3,6 @@ export { createChannelApprovalNativeRuntimeAdapter, createChannelApprovalHandlerFromCapability, createLazyChannelApprovalNativeRuntimeAdapter, - resolveApprovalOverGateway, CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY, type ApprovalActionView, type ApprovalMetadataView, @@ -29,3 +28,4 @@ export { type PluginApprovalResolvedView, type ResolvedApprovalView, } from "../infra/approval-handler-runtime.js"; +export { resolveApprovalOverGateway } from "./approval-gateway-runtime.js";