fix: repair release delivery and live channel QA (#122529)

Backport the exact-delivery claim promotion repair and its prerequisite evidence preservation from main. Restore Buzz canary eligibility and let the Matrix QA scenario request raw progress command text without changing the privacy-safe product default.

The Telegram workflow-only repair remains on main and is intentionally not backported.

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
This commit is contained in:
Peter Steinberger
2026-08-12 00:50:53 -07:00
committed by GitHub
parent e0a5820c1e
commit 514fa32f3d
13 changed files with 393 additions and 64 deletions
+17 -17
View File
@@ -53,7 +53,7 @@
{"closureHash":"ff3c4616cd6212a6d698831a8b287ad87e3968c8663f4090d095bb30ec40fc1c","declaration":"export function abortAndDrainAgentHarnessRun(params: { sessionId: string; sessionKey?: string; settleMs?: number; forceClear?: boolean; reason?: string; }): Promise<AbortAndDrainEmbeddedAgentRunResult>;","entrypoint":"agent-harness","exportName":"abortAndDrainAgentHarnessRun","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"}
{"closureHash":"58989e3fa91eecf2e05202e36548e6e64a3b9219e83154bd99866c851604e34e","declaration":"export function createAgentToolResultMiddlewareRunner(ctx: AgentToolResultMiddlewareContext, handlers?: AgentToolResultMiddleware[]): { applyToolResultMiddleware(event: AgentToolResultMiddlewareEvent): Promise<OpenClawAgentToolResult>; };","entrypoint":"agent-harness","exportName":"createAgentToolResultMiddlewareRunner","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"}
{"closureHash":"b8f6355d7ad1700aceecddaa6e9ccf43091a792d5b481a1ee3f55294a881a67d","declaration":"export function createCodexAppServerToolResultExtensionRunner(ctx: CodexAppServerExtensionContext, factories?: CodexAppServerExtensionFactory[]): { applyToolResultExtensions(event: CodexAppServerToolResultEvent): Promise<AgentToolResult<unknown>>; };","entrypoint":"agent-harness","exportName":"createCodexAppServerToolResultExtensionRunner","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"}
{"closureHash":"82a967232dd50d7c7a42d6a576722af500feba6c6170c808a3297ea36f6a9bec","declaration":"export function createOpenClawCodingTools(options?: OpenClawCodingToolsOptions): AnyAgentTool[];","entrypoint":"agent-harness","exportName":"createOpenClawCodingTools","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"}
{"closureHash":"2de11782a252f85f6f89fcd833c30c073e57644a1c583c50823a7f12255003cd","declaration":"export function createOpenClawCodingTools(options?: OpenClawCodingToolsOptions): AnyAgentTool[];","entrypoint":"agent-harness","exportName":"createOpenClawCodingTools","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"}
{"closureHash":"13649ee853485319e7449fda25c106b3f3f53d3090e53cdbb28e220a8529eb80","declaration":"export function disposeRegisteredAgentHarnesses(): Promise<void>;","entrypoint":"agent-harness","exportName":"disposeRegisteredAgentHarnesses","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"}
{"closureHash":"f255a91162ece4c239bb8fa745efa14a1054bc024a291e9954f75f239b2b87c3","declaration":"export function resolveActiveEmbeddedRunSessionId(sessionKey: string): string | undefined;","entrypoint":"agent-harness","exportName":"resolveActiveEmbeddedRunSessionId","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"}
{"closureHash":"27d9f61df9ccf68615cb2002a6da891e36ab0c07623bc37c4d07aa980b446881","declaration":"export function resolveWebSearchToolPolicy(params: WebSearchToolPolicyParams): WebSearchToolPolicyResolution;","entrypoint":"agent-harness","exportName":"resolveWebSearchToolPolicy","importSpecifier":"openclaw/plugin-sdk/agent-harness","kind":"function","recordType":"export"}
@@ -1097,7 +1097,7 @@
{"closureHash":"9555a73ba2717bba0bf94888017be4cecef2c51cc3887ed34f8d8ef3c79d6abf","declaration":"export const DEFAULT_INGRESS_RETRY_DEAD_LETTER_MIN_AGE_MS: number;","entrypoint":"channel-message","exportName":"DEFAULT_INGRESS_RETRY_DEAD_LETTER_MIN_AGE_MS","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"const","recordType":"export"}
{"closureHash":"3a2df3ab656149630c004d2d9f71b8ceda99aa81eb6b72b0cc7b3982ed0ce044","declaration":"export const DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS: 8;","entrypoint":"channel-message","exportName":"DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"const","recordType":"export"}
{"closureHash":"38c735a14c65067aa7825390d1c5c8876c651d0603e84980dfaf947f5235747a","declaration":"export const INGRESS_CLAIM_PROCESS_ID: string;","entrypoint":"channel-message","exportName":"INGRESS_CLAIM_PROCESS_ID","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"const","recordType":"export"}
{"closureHash":"f5d6c974980d1792af370a89adca4417174efdc8bf3b70e140fdfe21d1692cca","declaration":"export const deliverInboundReplyWithMessageSendContext: (params: DurableInboundReplyDeliveryParams) => Promise<{ status: \"not_applicable\"; reason: \"non_final\";} | { status: \"unsupported\"; reason: \"missing_channel\" | \"missing_target\" | \"missing_outbound_handler\" | \"capability_mismatch\"; capability?: DurableFinalDeliveryRequirement;} | { status: \"handled_visible\"; delivery: ChannelDeliveryResult;} | { status: \"handled_no_send\"; reason: \"no_visible_result\"; delivery: ChannelDeliveryResult;} | { status: \"failed\"; error: unknown; sentBeforeError?: true;}>;","entrypoint":"channel-message","exportName":"deliverInboundReplyWithMessageSendContext","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"const","recordType":"export"}
{"closureHash":"7d90d0f9c14318d2f1a6a6c4e525eee5913d6fafdee648144d8f656297934d9c","declaration":"export const deliverInboundReplyWithMessageSendContext: (params: DurableInboundReplyDeliveryParams) => Promise<{ status: \"not_applicable\"; reason: \"non_final\";} | { status: \"unsupported\"; reason: \"missing_channel\" | \"missing_target\" | \"missing_outbound_handler\" | \"capability_mismatch\"; capability?: DurableFinalDeliveryRequirement;} | { status: \"handled_visible\"; delivery: ChannelDeliveryResult;} | { status: \"handled_no_send\"; reason: \"no_visible_result\"; delivery: ChannelDeliveryResult;} | { status: \"failed\"; error: unknown; sentBeforeError?: true;}>;","entrypoint":"channel-message","exportName":"deliverInboundReplyWithMessageSendContext","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"const","recordType":"export"}
{"closureHash":"2c52eff200a5b9bd2d93ee72209c2626bbe165f59b538591db661b94773023b0","declaration":"export type AgentPlanStep = AgentPlanStep;","entrypoint":"channel-message","exportName":"AgentPlanStep","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"type","recordType":"export"}
{"closureHash":"1e8bcb2c8d8f5327f5b81b8c217f722f090dccba21ba3943324010f4f80a5a50","declaration":"export type AgentPlanStepStatus = AgentPlanStepStatus;","entrypoint":"channel-message","exportName":"AgentPlanStepStatus","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"type","recordType":"export"}
{"closureHash":"b036fc26e5330dfd7da1af8839bb3c23e85283b9e16e252a659dd4bb0c35cd5e","declaration":"export type ChannelDeliveryStreamingConfig = ChannelDeliveryStreamingConfig;","entrypoint":"channel-message","exportName":"ChannelDeliveryStreamingConfig","importSpecifier":"openclaw/plugin-sdk/channel-message","kind":"type","recordType":"export"}
@@ -1226,7 +1226,7 @@
{"closureHash":"9555a73ba2717bba0bf94888017be4cecef2c51cc3887ed34f8d8ef3c79d6abf","declaration":"export const DEFAULT_INGRESS_RETRY_DEAD_LETTER_MIN_AGE_MS: number;","entrypoint":"channel-outbound","exportName":"DEFAULT_INGRESS_RETRY_DEAD_LETTER_MIN_AGE_MS","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"const","recordType":"export"}
{"closureHash":"3a2df3ab656149630c004d2d9f71b8ceda99aa81eb6b72b0cc7b3982ed0ce044","declaration":"export const DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS: 8;","entrypoint":"channel-outbound","exportName":"DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"const","recordType":"export"}
{"closureHash":"38c735a14c65067aa7825390d1c5c8876c651d0603e84980dfaf947f5235747a","declaration":"export const INGRESS_CLAIM_PROCESS_ID: string;","entrypoint":"channel-outbound","exportName":"INGRESS_CLAIM_PROCESS_ID","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"const","recordType":"export"}
{"closureHash":"f5d6c974980d1792af370a89adca4417174efdc8bf3b70e140fdfe21d1692cca","declaration":"export const deliverInboundReplyWithMessageSendContext: (params: DurableInboundReplyDeliveryParams) => Promise<{ status: \"not_applicable\"; reason: \"non_final\";} | { status: \"unsupported\"; reason: \"missing_channel\" | \"missing_target\" | \"missing_outbound_handler\" | \"capability_mismatch\"; capability?: DurableFinalDeliveryRequirement;} | { status: \"handled_visible\"; delivery: ChannelDeliveryResult;} | { status: \"handled_no_send\"; reason: \"no_visible_result\"; delivery: ChannelDeliveryResult;} | { status: \"failed\"; error: unknown; sentBeforeError?: true;}>;","entrypoint":"channel-outbound","exportName":"deliverInboundReplyWithMessageSendContext","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"const","recordType":"export"}
{"closureHash":"7d90d0f9c14318d2f1a6a6c4e525eee5913d6fafdee648144d8f656297934d9c","declaration":"export const deliverInboundReplyWithMessageSendContext: (params: DurableInboundReplyDeliveryParams) => Promise<{ status: \"not_applicable\"; reason: \"non_final\";} | { status: \"unsupported\"; reason: \"missing_channel\" | \"missing_target\" | \"missing_outbound_handler\" | \"capability_mismatch\"; capability?: DurableFinalDeliveryRequirement;} | { status: \"handled_visible\"; delivery: ChannelDeliveryResult;} | { status: \"handled_no_send\"; reason: \"no_visible_result\"; delivery: ChannelDeliveryResult;} | { status: \"failed\"; error: unknown; sentBeforeError?: true;}>;","entrypoint":"channel-outbound","exportName":"deliverInboundReplyWithMessageSendContext","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"const","recordType":"export"}
{"closureHash":"2c52eff200a5b9bd2d93ee72209c2626bbe165f59b538591db661b94773023b0","declaration":"export type AgentPlanStep = AgentPlanStep;","entrypoint":"channel-outbound","exportName":"AgentPlanStep","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"type","recordType":"export"}
{"closureHash":"1e8bcb2c8d8f5327f5b81b8c217f722f090dccba21ba3943324010f4f80a5a50","declaration":"export type AgentPlanStepStatus = AgentPlanStepStatus;","entrypoint":"channel-outbound","exportName":"AgentPlanStepStatus","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"type","recordType":"export"}
{"closureHash":"b036fc26e5330dfd7da1af8839bb3c23e85283b9e16e252a659dd4bb0c35cd5e","declaration":"export type ChannelDeliveryStreamingConfig = ChannelDeliveryStreamingConfig;","entrypoint":"channel-outbound","exportName":"ChannelDeliveryStreamingConfig","importSpecifier":"openclaw/plugin-sdk/channel-outbound","kind":"type","recordType":"export"}
@@ -2354,7 +2354,7 @@
{"closureHash":"98e0cc16352b7dfcceb4957f8cd2acfe3c2b3acb223c42a5cfb885e088fcb04c","declaration":"export function resolveInboundReplyDispatchCounts(result: ChannelTurnDispatchResultLike): Record<ReplyDispatchKind, number>;","entrypoint":"inbound-reply-dispatch","exportName":"resolveInboundReplyDispatchCounts","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"function","recordType":"export"}
{"closureHash":"9d503d05e408ddd1a1c373e3c4485b1f9acff4c240fdc241840a2cfa8b55c3a7","declaration":"export function runChannelInboundEvent<TRaw, TDispatchResult = DispatchFromConfigResult>(params: RunChannelTurnParams<TRaw, TDispatchResult, ChannelProviderOwnedMessageSendingDeliveryAdapter>): Promise<ChannelTurnResult<TDispatchResult>>;\nexport function runChannelInboundEvent<TRaw, TDispatchResult = DispatchFromConfigResult>(params: ChannelInboundEventRunnerParams<TRaw, TDispatchResult>): Promise<ChannelTurnResult<TDispatchResult>>;","entrypoint":"inbound-reply-dispatch","exportName":"runChannelInboundEvent","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"function","recordType":"export"}
{"closureHash":"2c68496a174872b31aaf1ac8fad2789deb79d490c5ffbcb157325f1c95d1b51f","declaration":"export function runPreparedInboundReply<TDispatchResult>(params: PreparedChannelTurn<TDispatchResult>): Promise<ChannelTurnResult<TDispatchResult>>;","entrypoint":"inbound-reply-dispatch","exportName":"runPreparedInboundReply","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"function","recordType":"export"}
{"closureHash":"f5d6c974980d1792af370a89adca4417174efdc8bf3b70e140fdfe21d1692cca","declaration":"export const deliverInboundReplyWithMessageSendContext: (params: DurableInboundReplyDeliveryParams) => Promise<{ status: \"not_applicable\"; reason: \"non_final\";} | { status: \"unsupported\"; reason: \"missing_channel\" | \"missing_target\" | \"missing_outbound_handler\" | \"capability_mismatch\"; capability?: DurableFinalDeliveryRequirement;} | { status: \"handled_visible\"; delivery: ChannelDeliveryResult;} | { status: \"handled_no_send\"; reason: \"no_visible_result\"; delivery: ChannelDeliveryResult;} | { status: \"failed\"; error: unknown; sentBeforeError?: true;}>;","entrypoint":"inbound-reply-dispatch","exportName":"deliverInboundReplyWithMessageSendContext","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"const","recordType":"export"}
{"closureHash":"7d90d0f9c14318d2f1a6a6c4e525eee5913d6fafdee648144d8f656297934d9c","declaration":"export const deliverInboundReplyWithMessageSendContext: (params: DurableInboundReplyDeliveryParams) => Promise<{ status: \"not_applicable\"; reason: \"non_final\";} | { status: \"unsupported\"; reason: \"missing_channel\" | \"missing_target\" | \"missing_outbound_handler\" | \"capability_mismatch\"; capability?: DurableFinalDeliveryRequirement;} | { status: \"handled_visible\"; delivery: ChannelDeliveryResult;} | { status: \"handled_no_send\"; reason: \"no_visible_result\"; delivery: ChannelDeliveryResult;} | { status: \"failed\"; error: unknown; sentBeforeError?: true;}>;","entrypoint":"inbound-reply-dispatch","exportName":"deliverInboundReplyWithMessageSendContext","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"const","recordType":"export"}
{"closureHash":"278dc8a410230012ddbc3552ec621a224e6f7c5dd4cd3904c943ac98dd4259e4","declaration":"export type AssembledInboundReply = AssembledChannelTurn;","entrypoint":"inbound-reply-dispatch","exportName":"AssembledInboundReply","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"type","recordType":"export"}
{"closureHash":"3de0d6d1bb8f9a83bd1c6e57aa8618e3fea71054236cd530c555e348bd0b7702","declaration":"export type ChannelBotLoopProtectionFacts = ChannelBotLoopProtectionFacts;","entrypoint":"inbound-reply-dispatch","exportName":"ChannelBotLoopProtectionFacts","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"type","recordType":"export"}
{"closureHash":"f0da845bbdf49b30f6718a4b7ff012a0536deb98f65418583555dc90825797ca","declaration":"export type ChannelInboundDroppedHistoryOptions = ChannelTurnDroppedHistoryOptions;","entrypoint":"inbound-reply-dispatch","exportName":"ChannelInboundDroppedHistoryOptions","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch","kind":"type","recordType":"export"}
@@ -3189,19 +3189,19 @@
{"closureHash":"50394942e0a454c742e80a4f3c8739c80258b387ade498eb5aed66df887108be","declaration":"export function callMeetingBrowserProxyOnNode(params: { runtime: PluginRuntime; adapter: NodeAdapter; nodeId: string; } & MeetingBrowserRequestParams): Promise<unknown>;","entrypoint":"meeting-runtime","exportName":"callMeetingBrowserProxyOnNode","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"c5fcd1d157edcb4773235adfaf8051e3ec7ca428cb7916b6d55f2511affab56c","declaration":"export function convertMeetingBridgeAudioForStt(audio: Buffer, audioFormat: MeetingRealtimeAudioFormat): Buffer;","entrypoint":"meeting-runtime","exportName":"convertMeetingBridgeAudioForStt","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"aa9063c27c5ff714d3653571c4a2a71e9d2eea5609b161f03e4738e15411358b","declaration":"export function convertMeetingTtsAudioForBridge(audio: Buffer, sampleRate: number, audioFormat: MeetingRealtimeAudioFormat, outputFormat?: string, platformName?: string): Buffer;","entrypoint":"meeting-runtime","exportName":"convertMeetingTtsAudioForBridge","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"c8f1a9163a69ca61d4f88f8129e5f23719f921e5245e060c7a6c77bfaae8c34a","declaration":"export function createLocalMeetingRealtimeAudioTransport(params: { inputCommand: string[]; outputCommand: string[]; bargeInInputCommand?: string[]; bargeInRmsThreshold: number; bargeInPeakThreshold: number; bargeInCooldownMs: number; logger: RuntimeLogger; logScope: string; audioFormat?: MeetingRealtimeAudioFormat; spawn?: MeetingRealtimeAudioSpawn; }): MeetingRealtimeAudioTransport;","entrypoint":"meeting-runtime","exportName":"createLocalMeetingRealtimeAudioTransport","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"da67f89aa5cab403a21826f782ae63af7cd135aea65d76e03c10e701ff20f0cb","declaration":"export function createLocalMeetingRealtimeAudioTransport(params: { inputCommand: string[]; outputCommand: string[]; bargeInInputCommand?: string[]; bargeInRmsThreshold: number; bargeInPeakThreshold: number; bargeInCooldownMs: number; logger: RuntimeLogger; logScope: string; audioFormat?: MeetingRealtimeAudioFormat; spawn?: MeetingRealtimeAudioSpawn; }): MeetingRealtimeAudioTransport;","entrypoint":"meeting-runtime","exportName":"createLocalMeetingRealtimeAudioTransport","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"9cb63eefd2e5a70aea960bf17fcf570ef02a2d7b5afd5ad9451802964c653fcf","declaration":"export function createMeetingBrowserNodeCaller(params: { runtime: PluginRuntime; adapter: NodeAdapter; nodeId: string; }): MeetingBrowserRequestCaller;","entrypoint":"meeting-runtime","exportName":"createMeetingBrowserNodeCaller","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"f244ca8c47f556c9f388953cf9a7581c7d4d413af93e0dfa1462779e6a687a7c","declaration":"export function createMeetingBrowserNodeInvokePolicy(options: MeetingBrowserNodePolicyOptions): OpenClawPluginNodeInvokePolicy;","entrypoint":"meeting-runtime","exportName":"createMeetingBrowserNodeInvokePolicy","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"1aa4e3ff39a2cbe162421c62b1fa4a362973381d4d9ff15c671249b1ebd566bc","declaration":"export function createMeetingNodeHost(options: MeetingNodeHostOptions): { handleCommand(paramsJSON?: string | null): Promise<string>; };","entrypoint":"meeting-runtime","exportName":"createMeetingNodeHost","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"2493d5d6a3b2128c167ae4c42129ff96b2dddaac7c12c87fc442ff304b01ca3a","declaration":"export function createMeetingRealtimeEngineBindings(params: { platform: MeetingPlatformRuntimeMetadata; config: { realtime: { agentId?: string; toolPolicy: RealtimeVoiceAgentConsultToolPolicy; }; }; fullConfig: OpenClawConfig; runtime: PluginRuntime; logger: RuntimeLogger; }): { platform: MeetingRuntimePlatform; consultAgent: (consult: MeetingAgentConsultParams) => Promise<{ text: string; }>; tools: RealtimeVoiceTool[]; handleToolCall: (call: MeetingRealtimeToolCallParams) => Promise<void>; };","entrypoint":"meeting-runtime","exportName":"createMeetingRealtimeEngineBindings","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"14ac7c607f540bb79a096af8a60844201a0544d4f506311d65f298c32c5d42a8","declaration":"export function createMeetingRealtimeEngineBindings(params: { platform: MeetingPlatformRuntimeMetadata; config: { realtime: { agentId?: string; toolPolicy: RealtimeVoiceAgentConsultToolPolicy; }; }; fullConfig: OpenClawConfig; runtime: PluginRuntime; logger: RuntimeLogger; }): { platform: MeetingRuntimePlatform; consultAgent: (consult: MeetingAgentConsultParams) => Promise<{ text: string; }>; tools: RealtimeVoiceTool[]; handleToolCall: (call: MeetingRealtimeToolCallParams) => Promise<void>; };","entrypoint":"meeting-runtime","exportName":"createMeetingRealtimeEngineBindings","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"9124db05923060c467edb149bd8abdc8be1d00d00f867cf84600972923a58489","declaration":"export function createMeetingSession<TTransport extends string, TMode extends string, TToolPolicy extends string>(params: { platform: MeetingPlatformRuntimeMetadata; config: { realtime: { provider?: string; voiceProvider?: string; transcriptionProvider?: string; model?: string; toolPolicy: TToolPolicy; }; }; resolved: MeetingResolvedJoin<TTransport, TMode>; createdAt: string; }): MeetingSessionRecord<TTransport, TMode, { enabled: boolean; strategy: string; provider: string | undefined; model: string | undefined; transcriptionProvider: string | undefined; toolPolicy: TToolPolicy; }>;","entrypoint":"meeting-runtime","exportName":"createMeetingSession","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"fb276e07e395ab19177b3d7967fd0a8fcda79130883f15092a4a306b826481b9","declaration":"export function createMeetingSetupStatus(checks: MeetingSetupCheck[]): MeetingSetupStatus;","entrypoint":"meeting-runtime","exportName":"createMeetingSetupStatus","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"93c4bb70429a2739151e6f900e67bed81f3cd8f597811220e790341edb0d6008","declaration":"export function createMeetingVoiceCallGateway(params: { config: MeetingVoiceCallConfig; runtime: PluginRuntime; surface: MeetingVoiceCallSurface; connectClient: (params: { config: MeetingVoiceCallConfig; surface: MeetingVoiceCallSurface; }) => Promise<MeetingVoiceCallGatewayClient>; }): MeetingVoiceCallGateway;","entrypoint":"meeting-runtime","exportName":"createMeetingVoiceCallGateway","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"cdf4e39ad1cf11a2826425997ccaea4ffedb057b543b355c375885891476bf23","declaration":"export function createNodeMeetingRealtimeAudioTransport(params: { runtime: PluginRuntime; nodeId: string; bridgeId: string; logger: RuntimeLogger; commandName: string; logScope: string; logPrefix: string; audioFormat?: MeetingRealtimeAudioFormat; }): MeetingRealtimeAudioTransport;","entrypoint":"meeting-runtime","exportName":"createNodeMeetingRealtimeAudioTransport","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"8f5dbf400a577fb8041e8e4f1035b0a08b1c651dfc391f71f674626414a4463d","declaration":"export function createNodeMeetingRealtimeAudioTransport(params: { runtime: PluginRuntime; nodeId: string; bridgeId: string; logger: RuntimeLogger; commandName: string; logScope: string; logPrefix: string; audioFormat?: MeetingRealtimeAudioFormat; }): MeetingRealtimeAudioTransport;","entrypoint":"meeting-runtime","exportName":"createNodeMeetingRealtimeAudioTransport","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"c0987b15a391a92d53d3e4e12b61eb122f9547fcf4f45478cdd3c5a8973a3e52","declaration":"export function endMeetingVoiceCallGatewayCall(params: { gateway: MeetingVoiceCallGateway; callId: string; }): Promise<void>;","entrypoint":"meeting-runtime","exportName":"endMeetingVoiceCallGatewayCall","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"b3ebc10fe7ab372e1317eaa8f78621cf277bba1e33fda57acf2254f6759d1e9d","declaration":"export function getMeetingVoiceCallGatewayCall(params: { gateway: MeetingVoiceCallGateway; callId: string; }): Promise<MeetingVoiceCallStatusResult>;","entrypoint":"meeting-runtime","exportName":"getMeetingVoiceCallGatewayCall","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"aac088df8e80d9ce89c45feccdb04ace3ae4417b3fcdd0f058410ddf25c96b46","declaration":"export function isMeetingVoiceCallMissingError(error: unknown): boolean;","entrypoint":"meeting-runtime","exportName":"isMeetingVoiceCallMissingError","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"337f14177df4f0a622be4d97495e99706782e43917ff560c5fbb439263f89457","declaration":"export function joinMeetingViaVoiceCallGateway(params: { config: MeetingVoiceCallConfig; gateway: MeetingVoiceCallGateway; surface: MeetingVoiceCallSurface; dialInNumber: string; dtmfSequence?: string; logger?: RuntimeLogger; message?: string; requesterSessionKey?: string; agentId?: string; sessionKey?: string; }): Promise<MeetingVoiceCallJoinResult>;","entrypoint":"meeting-runtime","exportName":"joinMeetingViaVoiceCallGateway","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"32150fd1c5ab0734ab02215d8a0acdb048d598fd69947d4f1d0ed2ea209cf0a6","declaration":"export function joinMeetingViaVoiceCallGateway(params: { config: MeetingVoiceCallConfig; gateway: MeetingVoiceCallGateway; surface: MeetingVoiceCallSurface; dialInNumber: string; dtmfSequence?: string; logger?: RuntimeLogger; message?: string; requesterSessionKey?: string; agentId?: string; sessionKey?: string; }): Promise<MeetingVoiceCallJoinResult>;","entrypoint":"meeting-runtime","exportName":"joinMeetingViaVoiceCallGateway","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"bac9621cd025754fbcd4c21409b06eb0503405db81f35cac993aaf0b881ab3e1","declaration":"export function leaveMeetingWithBrowser<Session, Mode extends string, Health extends MeetingBrowserHealth, Transcript extends MeetingTranscriptSnapshot>(params: { adapter: BrowserAdapter<Session, Mode, Health, Transcript>; callBrowser: MeetingBrowserRequestCaller; launch: boolean; meetingSessionId?: string; meetingUrl: string; tab: MeetingBrowserTab; timeoutMs: number; }): Promise<{ left: boolean; note: string; }>;","entrypoint":"meeting-runtime","exportName":"leaveMeetingWithBrowser","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"c7b1aeac134b2070d053adf33026d876998b852ccd65cd2c9667119b1a1abee2","declaration":"export function openMeetingWithBrowser<Session extends MeetingBrowserJoinSession<Mode>, Mode extends string, Health extends MeetingBrowserHealth & { browserTitle?: string; browserUrl?: string; notes?: string[]; }, Transcript extends MeetingTranscriptSnapshot>(params: { adapter: BrowserAdapter<Session, Mode, Health, Transcript>; callBrowser: MeetingBrowserRequestCaller; config: MeetingBrowserControllerConfig; session: Session; }): Promise<{ launched: boolean; browser?: Health; tab?: MeetingBrowserTab; }>;","entrypoint":"meeting-runtime","exportName":"openMeetingWithBrowser","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"34858979bd248799c2215d9c7bdd5d4a6b27660c9173bfca2e50dd4373ac27db","declaration":"export function readMeetingBrowserTab(result: unknown): MeetingBrowserCandidateTab | undefined;","entrypoint":"meeting-runtime","exportName":"readMeetingBrowserTab","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
@@ -3212,8 +3212,8 @@
{"closureHash":"56874c5b2ced5af647b1dff296c931f0d8b85b1318e98c741aa88b58a9c5c606","declaration":"export function resolveMeetingBrowserNodeInfo(params: { runtime: PluginRuntime; adapter: NodeAdapter; requestedNode?: string; }): Promise<MeetingBrowserNodeInfo>;","entrypoint":"meeting-runtime","exportName":"resolveMeetingBrowserNodeInfo","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"f21196c9ea8ab90248ffdcdef3e942f1247ee2b9064ddb9757fffe352362c779","declaration":"export function resolveMeetingRealtimeAudioFormat(audioFormat: MeetingRealtimeAudioFormat): RealtimeVoiceAudioFormat;","entrypoint":"meeting-runtime","exportName":"resolveMeetingRealtimeAudioFormat","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"521dc5c262524a709cdd27cdc88e95004073da8223537bcbc73d5d423172dc2b","declaration":"export function speakMeetingViaVoiceCallGateway(params: { gateway: MeetingVoiceCallGateway; callId: string; message: string; }): Promise<void>;","entrypoint":"meeting-runtime","exportName":"speakMeetingViaVoiceCallGateway","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"318770156465bcaef766d607ed73d3d3ceea9a3d148c80980bed8da4d33ae94e","declaration":"export function startMeetingAgentRealtimeEngine(params: { config: MeetingRealtimeEngineConfig; fullConfig: OpenClawConfig; runtime: PluginRuntime; platform: MeetingRuntimePlatform; meetingSessionId: string; requesterSessionKey?: string; logPrefix?: \"node\"; transport: MeetingRealtimeAudioTransport; logger: RuntimeLogger; providers?: RealtimeTranscriptionProviderPlugin[]; consultAgent: (params: MeetingAgentConsultParams) => Promise<{ text: string; }>; }): Promise<MeetingRealtimeAudioEngineHandle>;","entrypoint":"meeting-runtime","exportName":"startMeetingAgentRealtimeEngine","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"90ca9e0ecea498d28aad6e0d5b1a098779002ff2229035ad43e7c6eae9411f23","declaration":"export function startMeetingRealtimeEngine(params: { config: MeetingRealtimeEngineConfig; fullConfig: OpenClawConfig; runtime: PluginRuntime; platform: MeetingRuntimePlatform; meetingSessionId: string; requesterSessionKey?: string; logPrefix?: \"node\"; talkSessionId?: string; talkContext?: { nodeId: string; bridgeId: string; }; transport: MeetingRealtimeAudioTransport; logger: RuntimeLogger; providers?: RealtimeVoiceProviderPlugin[]; consultAgent: (params: MeetingAgentConsultParams) => Promise<{ text: string; }>; tools: RealtimeVoiceTool[]; handleToolCall: (params: MeetingRealtimeToolCallParams) => Promise<void>; }): Promise<MeetingRealtimeAudioEngineHandle>;","entrypoint":"meeting-runtime","exportName":"startMeetingRealtimeEngine","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"7174800aae9004a2c5f75a161b27890725b4602f43f335fbf43483c5b86e9aa0","declaration":"export function startMeetingAgentRealtimeEngine(params: { config: MeetingRealtimeEngineConfig; fullConfig: OpenClawConfig; runtime: PluginRuntime; platform: MeetingRuntimePlatform; meetingSessionId: string; requesterSessionKey?: string; logPrefix?: \"node\"; transport: MeetingRealtimeAudioTransport; logger: RuntimeLogger; providers?: RealtimeTranscriptionProviderPlugin[]; consultAgent: (params: MeetingAgentConsultParams) => Promise<{ text: string; }>; }): Promise<MeetingRealtimeAudioEngineHandle>;","entrypoint":"meeting-runtime","exportName":"startMeetingAgentRealtimeEngine","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"9cbdf1184013c4f809bc45c204510dff243d070e7cdad69f30861e6f051957bc","declaration":"export function startMeetingRealtimeEngine(params: { config: MeetingRealtimeEngineConfig; fullConfig: OpenClawConfig; runtime: PluginRuntime; platform: MeetingRuntimePlatform; meetingSessionId: string; requesterSessionKey?: string; logPrefix?: \"node\"; talkSessionId?: string; talkContext?: { nodeId: string; bridgeId: string; }; transport: MeetingRealtimeAudioTransport; logger: RuntimeLogger; providers?: RealtimeVoiceProviderPlugin[]; consultAgent: (params: MeetingAgentConsultParams) => Promise<{ text: string; }>; tools: RealtimeVoiceTool[]; handleToolCall: (params: MeetingRealtimeToolCallParams) => Promise<void>; }): Promise<MeetingRealtimeAudioEngineHandle>;","entrypoint":"meeting-runtime","exportName":"startMeetingRealtimeEngine","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"function","recordType":"export"}
{"closureHash":"663b9c77231b21af697efd5042e22d1c33e9ee972adeb312ad86d81a2b2e36f7","declaration":"export type MeetingAgentConsultParams = MeetingAgentConsultParams;","entrypoint":"meeting-runtime","exportName":"MeetingAgentConsultParams","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
{"closureHash":"adf0745c611bf737fc28978d766fc2a25b7104e71b6b2fed4e9b95e519c7b115","declaration":"export type MeetingBrowserCandidateTab = MeetingBrowserCandidateTab;","entrypoint":"meeting-runtime","exportName":"MeetingBrowserCandidateTab","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
{"closureHash":"59b1526172b7491b85f14f13c1ee26d8d6726f33093770748580c767b1689a17","declaration":"export type MeetingBrowserControllerConfig = MeetingBrowserControllerConfig;","entrypoint":"meeting-runtime","exportName":"MeetingBrowserControllerConfig","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
@@ -3245,7 +3245,7 @@
{"closureHash":"8244b408803f57cf2004157e96f2ce11bb036cdf864123b15ba2fac7f03b5d43","declaration":"export type MeetingSessionRuntimeHandles<THealth extends MeetingBrowserHealth> = MeetingSessionRuntimeHandles<THealth>;","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntimeHandles","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
{"closureHash":"aa8054fc2c442891197e89bdad61e79999ea15d813c4b127fb6150607b9e67e7","declaration":"export type MeetingSessionRuntimeJoinContext<TSession extends MeetingSessionRecord<TTransport, TMode>, TTransport extends string, TMode extends string, THealth extends MeetingBrowserHealth, TTab extends MeetingBrowserTab> = MeetingSessionRuntimeJoinContext<TSession, TTransport, TMode, THealth, TTab>;","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntimeJoinContext","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
{"closureHash":"325241724edd38da439c5df03d225e2a7cb8e56d817e98ed7c37850656d3744b","declaration":"export type MeetingSessionRuntimeMessages<TSpeechBlockedReason extends string> = MeetingSessionRuntimeMessages<TSpeechBlockedReason>;","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntimeMessages","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
{"closureHash":"bc3ec8d61eeca24b6d2d5d56b91479aed7c4e8bf0b7e86945a1eedc562a9e42e","declaration":"export type MeetingSessionRuntimeOptions<TSession extends MeetingSessionRecord<TTransport, TMode>, TRequest, TTransport extends string, TMode extends string, THealth extends MeetingBrowserHealth<TManualReason, TSpeechBlockedReason>, TTab extends MeetingBrowserTab, TManualReason extends string, TSpeechBlockedReason extends string> = MeetingSessionRuntimeOptions<TSession, TRequest, TTransport, TMode, THealth, TTab, TManualReason, TSpeechBlockedReason>;","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntimeOptions","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
{"closureHash":"fa85bc062083dfd786c365009d368a32b57084e16e6fab1bde67a55099a6fb09","declaration":"export type MeetingSessionRuntimeOptions<TSession extends MeetingSessionRecord<TTransport, TMode>, TRequest, TTransport extends string, TMode extends string, THealth extends MeetingBrowserHealth<TManualReason, TSpeechBlockedReason>, TTab extends MeetingBrowserTab, TManualReason extends string, TSpeechBlockedReason extends string> = MeetingSessionRuntimeOptions<TSession, TRequest, TTransport, TMode, THealth, TTab, TManualReason, TSpeechBlockedReason>;","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntimeOptions","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
{"closureHash":"d3c730cba02d30512c4cdae6e2367c662982e2c25671833ecd8701283924c642","declaration":"export type MeetingSessionState = MeetingSessionState;","entrypoint":"meeting-runtime","exportName":"MeetingSessionState","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
{"closureHash":"2496931157bf64fdb16013172ab9c023e60c5f85b98f46a3ee9532ce58d636d6","declaration":"export type MeetingSetupCheck = MeetingSetupCheck;","entrypoint":"meeting-runtime","exportName":"MeetingSetupCheck","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
{"closureHash":"f0aed6f7955a43fc387d8bbc072cb6276b0f2d18e7f829441a2ad45974bb3831","declaration":"export type MeetingSetupStatus = MeetingSetupStatus;","entrypoint":"meeting-runtime","exportName":"MeetingSetupStatus","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
@@ -3259,9 +3259,9 @@
{"closureHash":"20c70a94483aeddda4d1500cfcc5e71fab844b474ba4061c55d6c8693d40821b","declaration":"export type MeetingVoiceCallJoinResult = MeetingVoiceCallJoinResult;","entrypoint":"meeting-runtime","exportName":"MeetingVoiceCallJoinResult","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
{"closureHash":"4fb2c5928aa6f809dd4c604d71c5c99cdfe3e98b6e9c1662601c9b4ad9738162","declaration":"export type MeetingVoiceCallStatusResult = MeetingVoiceCallStatusResult;","entrypoint":"meeting-runtime","exportName":"MeetingVoiceCallStatusResult","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
{"closureHash":"5ef812397b6409a4ca228943dd1080661365959477b42e705a9aaa219757d14f","declaration":"export type MeetingVoiceCallSurface = MeetingVoiceCallSurface;","entrypoint":"meeting-runtime","exportName":"MeetingVoiceCallSurface","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"type","recordType":"export"}
{"closureHash":"647fd7d11823c5e1228d0cb75a7dfed96c63e16087f74f7dc6c48afaebaf417d","declaration":"export interface MeetingPlatformAdapter<Session, Mode extends string, Health extends MeetingBrowserHealth, Transcript extends MeetingTranscriptSnapshot, CreateParams = never, CreateResult = never, DialInParams = never, DialInPlan = never> extends MeetingPlatformAdapterContract<Session, Mode, Health, Transcript, CreateParams, CreateResult, DialInParams, DialInPlan> {\n}","entrypoint":"meeting-runtime","exportName":"MeetingPlatformAdapter","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"interface","recordType":"export"}
{"closureHash":"af46549b627c17d5f706fe108a92a0d0472055e353059299dfc8204212ee7eb4","declaration":"export interface MeetingPlatformAdapter<Session, Mode extends string, Health extends MeetingBrowserHealth, Transcript extends MeetingTranscriptSnapshot, CreateParams = never, CreateResult = never, DialInParams = never, DialInPlan = never> extends MeetingPlatformAdapterContract<Session, Mode, Health, Transcript, CreateParams, CreateResult, DialInParams, DialInPlan> {\n}","entrypoint":"meeting-runtime","exportName":"MeetingPlatformAdapter","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"interface","recordType":"export"}
{"closureHash":"79884bd1df1ea0d07d5ceb4c62d93c1ee744b75d31c94c988845869c0f3cbd2d","declaration":"export interface MeetingRealtimeAudioTransport {\n onFatal(handler: () => void): void;\n startInput(onAudio: (audio: Buffer) => void): void;\n beginOutput?(): void;\n stop(): Promise<void>;\n writeOutput(audio: Buffer): Promise<void>;\n clearOutput(): Promise<void>;\n dispose(): Promise<void>;\n getHealth?(): MeetingRealtimeAudioTransportHealth;\n startBargeInMonitor?(onBargeIn: (audio: Buffer) => boolean): void;\n}","entrypoint":"meeting-runtime","exportName":"MeetingRealtimeAudioTransport","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"interface","recordType":"export"}
{"closureHash":"d3d839a5d9a3361c282ff6d2713defc867be38fef32cb3e2731fcd4fbf6645a7","declaration":"export class MeetingSessionRuntime<TSession extends MeetingSessionRecord<TTransport, TMode>, TRequest, TTransport extends string, TMode extends string, THealth extends MeetingBrowserHealth<TManualReason, TSpeechBlockedReason>, TTab extends MeetingBrowserTab, TManualReason extends string, TSpeechBlockedReason extends string> {\n readonly #sessions: Map<string, TSession>;\n readonly #sessionLeaves: Map<string, Promise<MeetingSessionLeaveResult<TSession>>>;\n readonly #sessionCleanup: MeetingSessionCleanupTracker;\n readonly #meetingLock: MeetingSessionJoinLock;\n readonly #sessionStops: Map<string, () => Promise<void>>;\n readonly #sessionSpeakers: Map<string, (instructions?: string) => void>;\n readonly #sessionHealth: Map<string, () => Partial<THealth>>;\n readonly #durableTranscripts: MeetingSessionDurableTranscripts<TSession>;\n readonly #transcriptStore: MeetingSessionTranscriptStore<TSession>;\n constructor(private readonly options: MeetingSessionRuntimeOptions<TSession, TRequest, TTransport, TMode, THealth, TTab, TManualReason, TSpeechBlockedReason>);\n list(): TSession[];\n getSession(sessionId: string): TSession | undefined;\n async status(sessionId?: string): Promise<{\n found: boolean;\n session?: TSession;\n sessions?: TSession[];\n }>;\n async transcript(sessionId: string, options: {\n sinceIndex?: number;\n }): Promise<{ found: boolean; sessionId?: string; startIndex?: number; nextIndex?: number; droppedLines?: number; evicted?: boolean; lines?: MeetingTranscriptLine[]; }>;\n async startTranscriptSource(request: TranscriptStartRequest): Promise<TranscriptsStartResult>;\n async stopTranscriptSource(request: TranscriptStopRequest): Promise<TranscriptsStopResult>;\n isReusableSession(session: TSession, resolved: MeetingResolvedJoin<TTransport, TMode>): boolean;\n async join(request: TRequest): Promise<{\n session: TSession;\n spoken?: boolean;\n }>;\n async leave(sessionId: string, options?: {\n keepBrowserTab?: boolean;\n }): Promise<MeetingSessionLeaveResult<TSession>>;\n async speak(sessionId: string, instructions?: string): Promise<{\n found: boolean;\n spoken: boolean;\n session?: TSession;\n }>;\n async speakWhenReady(session: TSession, instructions: string): Promise<boolean>;\n hasHealthHandle(sessionId: string): boolean;\n refreshHealth(sessionId?: string): void;\n async refreshBrowserHealth(session: TSession, options: {\n force?: boolean;\n readOnly?: boolean;\n }): Promise<void>;\n async refreshCaptionHealth(session: TSession): Promise<void>;\n refreshSpeechReadiness(session: TSession): {\n ready: boolean;\n reason?: TSpeechBlockedReason;\n message?: string;\n };\n markSessionEnded(session: TSession, reason: string): void;\n async #joinUnlocked(request: TRequest, resolved: MeetingResolvedJoin<TTransport, TMode>): Promise<{\n session: TSession;\n spoken?: boolean;\n }>;\n async #leaveUnlocked(sessionId: string, options?: {\n keepBrowserTab?: boolean;\n }): Promise<MeetingSessionLeaveResult<TSession>>;\n async #leaveSession(session: TSession, options?: {\n keepBrowserTab?: boolean;\n }): Promise<MeetingSessionLeaveResult<TSession>>;\n #meetingKey(transport: TTransport, url: string): string;\n #inheritBrowserTabOwnership(params: {\n session: TSession;\n transport: TTransport;\n nodeId?: string;\n meetingUrl: string;\n tab?: TTab;\n }): TTab | undefined;\n async #settleRetainedBrowserTabs(retained: Array<{\n session: TSession;\n tab: TTab;\n }>, adopted?: {\n transport: TTransport;\n nodeId?: string;\n tab: TTab;\n }): Promise<boolean>;\n async #rollbackFailedJoinSession(session: TSession): Promise<void>;\n async #settleRetainedBrowserTabsAfterFailure(retained: Array<{\n session: TSession;\n tab: TTab;\n }>): Promise<void>;\n #attachRuntimeHandles(session: TSession, handles: MeetingSessionRuntimeHandles<THealth>): void;\n #dropRuntimeHandles(sessionId: string): void;\n #isManagedBrowserSession(session: TSession): boolean;\n #evaluateSpeechReadiness(session: TSession): {\n ready: boolean;\n reason?: TSpeechBlockedReason;\n message?: string;\n };\n #noteSession(session: TSession, note: string): void;\n}","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntime","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"class","recordType":"export"}
{"closureHash":"c9cedf68602823e1eb0c6dce9206150967a843dd4bb49cfb1cd9f4156e39cd52","declaration":"export class MeetingSessionRuntime<TSession extends MeetingSessionRecord<TTransport, TMode>, TRequest, TTransport extends string, TMode extends string, THealth extends MeetingBrowserHealth<TManualReason, TSpeechBlockedReason>, TTab extends MeetingBrowserTab, TManualReason extends string, TSpeechBlockedReason extends string> {\n readonly #sessions: Map<string, TSession>;\n readonly #sessionLeaves: Map<string, Promise<MeetingSessionLeaveResult<TSession>>>;\n readonly #sessionCleanup: MeetingSessionCleanupTracker;\n readonly #meetingLock: MeetingSessionJoinLock;\n readonly #sessionStops: Map<string, () => Promise<void>>;\n readonly #sessionSpeakers: Map<string, (instructions?: string) => void>;\n readonly #sessionHealth: Map<string, () => Partial<THealth>>;\n readonly #durableTranscripts: MeetingSessionDurableTranscripts<TSession>;\n readonly #transcriptStore: MeetingSessionTranscriptStore<TSession>;\n constructor(private readonly options: MeetingSessionRuntimeOptions<TSession, TRequest, TTransport, TMode, THealth, TTab, TManualReason, TSpeechBlockedReason>);\n list(): TSession[];\n getSession(sessionId: string): TSession | undefined;\n async status(sessionId?: string): Promise<{\n found: boolean;\n session?: TSession;\n sessions?: TSession[];\n }>;\n async transcript(sessionId: string, options: {\n sinceIndex?: number;\n }): Promise<{ found: boolean; sessionId?: string; startIndex?: number; nextIndex?: number; droppedLines?: number; evicted?: boolean; lines?: MeetingTranscriptLine[]; }>;\n async startTranscriptSource(request: TranscriptStartRequest): Promise<TranscriptsStartResult>;\n async stopTranscriptSource(request: TranscriptStopRequest): Promise<TranscriptsStopResult>;\n isReusableSession(session: TSession, resolved: MeetingResolvedJoin<TTransport, TMode>): boolean;\n async join(request: TRequest): Promise<{\n session: TSession;\n spoken?: boolean;\n }>;\n async leave(sessionId: string, options?: {\n keepBrowserTab?: boolean;\n }): Promise<MeetingSessionLeaveResult<TSession>>;\n async speak(sessionId: string, instructions?: string): Promise<{\n found: boolean;\n spoken: boolean;\n session?: TSession;\n }>;\n async speakWhenReady(session: TSession, instructions: string): Promise<boolean>;\n hasHealthHandle(sessionId: string): boolean;\n refreshHealth(sessionId?: string): void;\n async refreshBrowserHealth(session: TSession, options: {\n force?: boolean;\n readOnly?: boolean;\n }): Promise<void>;\n async refreshCaptionHealth(session: TSession): Promise<void>;\n refreshSpeechReadiness(session: TSession): {\n ready: boolean;\n reason?: TSpeechBlockedReason;\n message?: string;\n };\n markSessionEnded(session: TSession, reason: string): void;\n async #joinUnlocked(request: TRequest, resolved: MeetingResolvedJoin<TTransport, TMode>): Promise<{\n session: TSession;\n spoken?: boolean;\n }>;\n async #leaveUnlocked(sessionId: string, options?: {\n keepBrowserTab?: boolean;\n }): Promise<MeetingSessionLeaveResult<TSession>>;\n async #leaveSession(session: TSession, options?: {\n keepBrowserTab?: boolean;\n }): Promise<MeetingSessionLeaveResult<TSession>>;\n #meetingKey(transport: TTransport, url: string): string;\n #inheritBrowserTabOwnership(params: {\n session: TSession;\n transport: TTransport;\n nodeId?: string;\n meetingUrl: string;\n tab?: TTab;\n }): TTab | undefined;\n async #settleRetainedBrowserTabs(retained: Array<{\n session: TSession;\n tab: TTab;\n }>, adopted?: {\n transport: TTransport;\n nodeId?: string;\n tab: TTab;\n }): Promise<boolean>;\n async #rollbackFailedJoinSession(session: TSession): Promise<void>;\n async #settleRetainedBrowserTabsAfterFailure(retained: Array<{\n session: TSession;\n tab: TTab;\n }>): Promise<void>;\n #attachRuntimeHandles(session: TSession, handles: MeetingSessionRuntimeHandles<THealth>): void;\n #dropRuntimeHandles(sessionId: string): void;\n #isManagedBrowserSession(session: TSession): boolean;\n #evaluateSpeechReadiness(session: TSession): {\n ready: boolean;\n reason?: TSpeechBlockedReason;\n message?: string;\n };\n #noteSession(session: TSession, note: string): void;\n}","entrypoint":"meeting-runtime","exportName":"MeetingSessionRuntime","importSpecifier":"openclaw/plugin-sdk/meeting-runtime","kind":"class","recordType":"export"}
{"category":null,"entrypoint":"memory-core-host-engine-foundation","importSpecifier":"openclaw/plugin-sdk/memory-core-host-engine-foundation","recordType":"module"}
{"closureHash":"e2df8d235401aebf58eb71652fbeaedb42ca00aaa5042a76909ff2c48ba6fd54","declaration":"export function createSubsystemLogger(subsystem: string): SubsystemLogger;","entrypoint":"memory-core-host-engine-foundation","exportName":"createSubsystemLogger","importSpecifier":"openclaw/plugin-sdk/memory-core-host-engine-foundation","kind":"function","recordType":"export"}
{"closureHash":null,"declaration":"export function isPathInside(root: string, target: string): boolean;","entrypoint":"memory-core-host-engine-foundation","exportName":"isPathInside","importSpecifier":"openclaw/plugin-sdk/memory-core-host-engine-foundation","kind":"function","recordType":"export"}
@@ -3655,10 +3655,10 @@
{"closureHash":"e66adcb55dec79be73a52bc76594b7e9210fd93c69a85b56098fbb58cecbb354","declaration":"export type WriteOAuthCredentialsOptions = WriteOAuthCredentialsOptions;","entrypoint":"provider-auth","exportName":"WriteOAuthCredentialsOptions","importSpecifier":"openclaw/plugin-sdk/provider-auth","kind":"type","recordType":"export"}
{"category":null,"entrypoint":"provider-catalog-runtime","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","recordType":"module"}
{"closureHash":"b5665596a3f011454a5614681513516acd50b6c749536c43842d811980cf7ad3","declaration":"export function augmentModelCatalogWithProviderPlugins(params: { config?: OpenClawConfig; workspaceDir?: string; env?: NodeJS.ProcessEnv; metadataSnapshot?: PluginMetadataSnapshot; context: ProviderAugmentModelCatalogContext; }): Promise<ModelCatalogEntry[]>;","entrypoint":"provider-catalog-runtime","exportName":"augmentModelCatalogWithProviderPlugins","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"}
{"closureHash":"94876118e27fd3a011c350765bc51c045da727a430bf560b76b13c36815e2a21","declaration":"export function isPluginProvidersLoadInFlight(params: Parameters<typeof resolvePluginProviders>[0]): boolean;","entrypoint":"provider-catalog-runtime","exportName":"isPluginProvidersLoadInFlight","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"}
{"closureHash":"baabd4ac04b433e27916ad3bfeee5a95952afce9e0685ae5acf3b7dceea69507","declaration":"export function resolveCatalogHookProviderPluginIds(params: { config?: PluginLoadOptions[\"config\"]; workspaceDir?: string; env?: PluginLoadOptions[\"env\"]; metadataSnapshot?: ProviderManifestLoadParams[\"metadataSnapshot\"]; }): string[];","entrypoint":"provider-catalog-runtime","exportName":"resolveCatalogHookProviderPluginIds","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"}
{"closureHash":"c21aedf5df214eee9f68930c1aaeef0b9ef5ec66df0a09dc9db095aa1764bd58","declaration":"export function resolveOwningPluginIdsForProvider(params: { provider: string; config?: PluginLoadOptions[\"config\"]; workspaceDir?: string; env?: PluginLoadOptions[\"env\"]; manifestRegistry?: PluginManifestRegistry; metadataSnapshot?: Pick<PluginMetadataSnapshot, \"owners\" | \"manifestRegistry\" | \"byPluginId\">; }): string[] | undefined;","entrypoint":"provider-catalog-runtime","exportName":"resolveOwningPluginIdsForProvider","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"}
{"closureHash":"37b37fd3da65fed3572a4e2d9784e79a338a26b85cacd87039c4741cfb41b07b","declaration":"export function resolvePluginProviders(params: { config?: PluginLoadOptions[\"config\"]; workspaceDir?: string; env?: PluginLoadOptions[\"env\"]; bundledProviderVitestCompat?: boolean; onlyPluginIds?: string[]; providerRefs?: readonly string[]; modelRefs?: readonly string[]; activate?: boolean; cache?: boolean; applyAutoEnable?: boolean; pluginSdkResolution?: PluginLoadOptions[\"pluginSdkResolution\"]; mode?: \"runtime\" | \"setup\"; includeUntrustedWorkspacePlugins?: boolean; pluginMetadataSnapshot?: PluginMetadataRegistryView; skipIfLoadInFlight?: boolean; }): ProviderPlugin[];","entrypoint":"provider-catalog-runtime","exportName":"resolvePluginProviders","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"}
{"closureHash":"335c16c1aebef57af0854df3f9c54ae8fe824a5734a14ee0d3701557299560d0","declaration":"export function isPluginProvidersLoadInFlight(params: Parameters<typeof resolvePluginProviders>[0]): boolean;","entrypoint":"provider-catalog-runtime","exportName":"isPluginProvidersLoadInFlight","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"}
{"closureHash":"10890ed322bbcee137a08de3fe0e4321c35126a6f1ee8ad763f1217e6ae32826","declaration":"export function resolveCatalogHookProviderPluginIds(params: { config?: PluginLoadOptions[\"config\"]; workspaceDir?: string; env?: PluginLoadOptions[\"env\"]; metadataSnapshot?: ProviderManifestLoadParams[\"metadataSnapshot\"]; }): string[];","entrypoint":"provider-catalog-runtime","exportName":"resolveCatalogHookProviderPluginIds","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"}
{"closureHash":"698f1fcc79c157e9de99df73ecec432cee824af1ec0dca1436a84f31e68b278a","declaration":"export function resolveOwningPluginIdsForProvider(params: { provider: string; config?: PluginLoadOptions[\"config\"]; workspaceDir?: string; env?: PluginLoadOptions[\"env\"]; manifestRegistry?: PluginManifestRegistry; metadataSnapshot?: Pick<PluginMetadataSnapshot, \"owners\" | \"manifestRegistry\" | \"byPluginId\">; }): string[] | undefined;","entrypoint":"provider-catalog-runtime","exportName":"resolveOwningPluginIdsForProvider","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"}
{"closureHash":"fc0e915b8a97d2b5fe2a9e6bc49a8ea09b7be903ff7204157de22eba2465a853","declaration":"export function resolvePluginProviders(params: { config?: PluginLoadOptions[\"config\"]; workspaceDir?: string; env?: PluginLoadOptions[\"env\"]; bundledProviderVitestCompat?: boolean; onlyPluginIds?: string[]; providerRefs?: readonly string[]; modelRefs?: readonly string[]; activate?: boolean; cache?: boolean; applyAutoEnable?: boolean; pluginSdkResolution?: PluginLoadOptions[\"pluginSdkResolution\"]; mode?: \"runtime\" | \"setup\"; includeUntrustedWorkspacePlugins?: boolean; pluginMetadataSnapshot?: PluginMetadataRegistryView; skipIfLoadInFlight?: boolean; }): ProviderPlugin[];","entrypoint":"provider-catalog-runtime","exportName":"resolvePluginProviders","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime","kind":"function","recordType":"export"}
{"category":null,"entrypoint":"proxy-capture","importSpecifier":"openclaw/plugin-sdk/proxy-capture","recordType":"module"}
{"closureHash":"d0e4e026d736bc00b1758d1089c44c3c5f3a09c7254291584de8cb297365804c","declaration":"export function acquireDebugProxyCaptureStore(dbPath: string, blobDir: string): { store: LegacyDebugProxyCaptureStore; release: () => void; };\nexport function acquireDebugProxyCaptureStore(options?: DebugProxyCaptureStoreOptions): { store: SharedDebugProxyCaptureStore; release: () => void; };","entrypoint":"proxy-capture","exportName":"acquireDebugProxyCaptureStore","importSpecifier":"openclaw/plugin-sdk/proxy-capture","kind":"function","recordType":"export"}
{"closureHash":"d41cbb9de51b7aee1c6cf8c713b0bc44f27ac926fbb6422c05726f196d11964e","declaration":"export function captureHttpExchange(params: { url: string; method: string; requestHeaders?: Headers | Record<string, string> | undefined; requestBody?: BodyInit | Buffer | string | null; response: Response; transport?: \"http\" | \"sse\"; flowId?: string; meta?: Record<string, unknown>; }, resolved?: DebugProxySettings, deps?: DebugProxyCaptureRuntimeDeps): void;","entrypoint":"proxy-capture","exportName":"captureHttpExchange","importSpecifier":"openclaw/plugin-sdk/proxy-capture","kind":"function","recordType":"export"}
@@ -374,6 +374,7 @@ describe("matrix qa config", () => {
chunkMode: "newline",
mode: "quiet",
preview: { toolProgress: false },
progress: { commandText: "status", maxLines: 2 },
},
threadBindings: {
enabled: false,
@@ -463,6 +464,7 @@ describe("matrix qa config", () => {
chunkMode: "newline",
mode: "quiet",
preview: { adjacentPreview: "current", toolProgress: false },
progress: { commandText: "raw", currentOnly: "current", maxLines: 3 },
},
threadBindings: {
adjacentBinding: "current",
@@ -541,6 +543,7 @@ describe("matrix qa config", () => {
chunkMode: "length",
mode: "off",
preview: { adjacentPreview: "current", toolProgress: true },
progress: { commandText: "status", currentOnly: "current", maxLines: 3 },
},
threadBindings: {
adjacentBinding: "current",
@@ -596,7 +599,10 @@ describe("matrix qa config", () => {
},
groupMentionPatterns: ["\\S"],
groupPolicy: "open",
streaming: true,
streaming: {
mode: "partial",
progress: { commandText: "raw" },
},
},
sutAccessToken: "sut-token",
sutAccountId: "sut",
@@ -613,11 +619,12 @@ describe("matrix qa config", () => {
chunkMode: "length",
mode: "partial",
preview: { toolProgress: true },
progress: { commandText: "raw" },
});
expect(config.messages?.groupChat?.mentionPatterns).toEqual(["\\S"]);
});
it("resets tool progress when a scalar streaming override follows an opt-out", () => {
it("resets QA streaming detail overrides when a scalar override follows", () => {
const optedOut = buildMatrixQaConfig({} as OpenClawConfig, {
driverUserId: "@driver:matrix-qa.test",
homeserver: "http://127.0.0.1:28008/",
@@ -626,6 +633,7 @@ describe("matrix qa config", () => {
streaming: {
mode: "quiet",
preview: { toolProgress: false },
progress: { commandText: "raw" },
},
},
sutAccessToken: "sut-token",
@@ -650,6 +658,7 @@ describe("matrix qa config", () => {
chunkMode: "length",
mode: "quiet",
preview: { toolProgress: false },
progress: { commandText: "raw" },
});
expect(reset.channels?.matrix?.accounts?.sut?.streaming).toEqual({
block: { enabled: false },
@@ -20,9 +20,8 @@ type MatrixQaExecApprovalsEnabled = boolean | "auto";
type MatrixQaAllowBotsMode = boolean | "mentions";
type MatrixQaStreamingConfig = {
mode?: MatrixQaStreamingMode;
preview?: {
toolProgress?: boolean;
};
preview?: { toolProgress?: boolean };
progress?: { commandText?: "raw" | "status" };
};
type MatrixQaAgentDefaultsOverrides = {
blockStreamingChunk?: {
@@ -132,6 +131,7 @@ type MatrixQaConfigSnapshot = {
startupVerification?: "if-unverified" | "off";
streaming: MatrixQaStreamingMode;
streamingPreviewToolProgress: boolean;
streamingProgressCommandText?: "raw" | "status";
textChunkLimit?: number;
threadBindings: MatrixQaThreadBindingsConfigOverrides;
threadReplies: MatrixQaThreadRepliesMode;
@@ -293,10 +293,7 @@ function isMatrixQaStreamingConfig(
function resolveMatrixQaStreamingPreviewToolProgress(
value: MatrixQaConfigOverrides["streaming"],
): boolean {
if (!isMatrixQaStreamingConfig(value)) {
return true;
}
return value.preview?.toolProgress ?? true;
return isMatrixQaStreamingConfig(value) ? (value.preview?.toolProgress ?? true) : true;
}
function resolveMatrixQaAutoJoinAllowlist(params: { overrides?: MatrixQaConfigOverrides }) {
@@ -450,12 +447,22 @@ function buildMatrixQaChannelAccountConfig(params: {
const preview = restoreOwnedFields(current?.streaming?.preview, baseline?.streaming?.preview, [
"toolProgress",
]);
const progress = restoreOwnedFields(current?.streaming?.progress, baseline?.streaming?.progress, [
"commandText",
]);
if (params.snapshot.streamingProgressCommandText !== undefined) {
progress.commandText = params.snapshot.streamingProgressCommandText;
}
Object.assign(streaming, {
block: { ...block, enabled: params.snapshot.blockStreaming },
chunkMode: params.snapshot.chunkMode ?? "length",
mode: params.snapshot.streaming,
preview: { ...preview, toolProgress: params.snapshot.streamingPreviewToolProgress },
});
delete streaming.progress;
if (Object.keys(progress).length > 0) {
streaming.progress = progress;
}
const threadBindings = restoreOwnedFields(
current?.threadBindings,
baseline?.threadBindings,
@@ -513,6 +520,7 @@ function buildMatrixQaConfigSnapshot(params: {
sutUserId: string;
topology: MatrixQaProvisionedTopology;
}): MatrixQaConfigSnapshot {
const streaming = params.overrides?.streaming;
return {
allowBots: params.overrides?.allowBots,
autoJoin: params.overrides?.autoJoin ?? "off",
@@ -532,10 +540,11 @@ function buildMatrixQaConfigSnapshot(params: {
}),
replyToMode: params.overrides?.replyToMode ?? "off",
startupVerification: params.overrides?.startupVerification,
streaming: resolveMatrixQaStreamingMode(params.overrides?.streaming),
streamingPreviewToolProgress: resolveMatrixQaStreamingPreviewToolProgress(
params.overrides?.streaming,
),
streaming: resolveMatrixQaStreamingMode(streaming),
streamingPreviewToolProgress: resolveMatrixQaStreamingPreviewToolProgress(streaming),
streamingProgressCommandText: isMatrixQaStreamingConfig(streaming)
? streaming.progress?.commandText
: undefined,
threadBindings: { ...params.overrides?.threadBindings },
textChunkLimit: params.overrides?.textChunkLimit,
threadReplies: params.overrides?.threadReplies ?? "inbound",
@@ -138,6 +138,7 @@ describe("live transport QA scenario selection", () => {
it.each([
{ channelId: "matrix", scenarioId: "thread-follow-up" },
{ channelId: "buzz", scenarioId: "channel-canary" },
{ channelId: "telegram", scenarioId: "channel-canary" },
{ channelId: "telegram", scenarioId: "channel-message-flows" },
] as const)(
@@ -165,7 +166,7 @@ describe("live transport QA scenario selection", () => {
scenarioIds: ["channel-canary"],
}),
).toThrow(
"selected QA scenario(s) do not match the current QA lane: channel-canary (channel=qa-channel|telegram)",
"selected QA scenario(s) do not match the current QA lane: channel-canary (channel=qa-channel|telegram|buzz)",
);
});
});
@@ -213,10 +213,33 @@ describe("qa scenario catalog channel contracts", () => {
expect(scenario.gatewayConfigPatch).not.toHaveProperty("channels.telegram.groups");
});
it("keeps the shared channel canary eligible for QA Channel and Telegram", () => {
it("keeps the shared channel canary eligible for QA Channel, Telegram, and Buzz", () => {
const scenario = requireFlowScenario(readQaScenarioById("channel-canary"));
expect(scenario.execution.channels).toEqual(["qa-channel", "telegram"]);
expect(scenario.execution.channels).toEqual(["qa-channel", "telegram", "buzz"]);
});
it("keeps raw Matrix command text scoped to the mention-safety scenario", () => {
const scenario = requireFlowScenario(
readQaScenarioById("matrix-room-tool-progress-mention-safety"),
);
const ordinaryProgressScenario = requireFlowScenario(
readQaScenarioById("matrix-room-tool-progress-preview"),
);
expect(scenario.execution.channel).toBe("matrix");
expect(scenario.execution.config).toMatchObject({
matrixConfigOverrides: {
streaming: {
mode: "partial",
progress: { commandText: "raw" },
},
toolProfile: "coding",
},
});
expect(ordinaryProgressScenario.execution.config).not.toHaveProperty(
"matrixConfigOverrides.streaming.progress.commandText",
);
});
it("keeps transcript-role delivery on the Crabline driver", () => {
@@ -24,6 +24,7 @@ scenario:
channels:
- qa-channel
- telegram
- buzz
summary: Run the shared channel canary through QA Channel, Crabline, or a live adapter.
transportPolicy:
requireGroupMention: true
@@ -12,7 +12,10 @@ scenario:
retryCount: 0
config:
matrixConfigOverrides:
streaming: partial
streaming:
mode: partial
progress:
commandText: raw
toolProfile: coding
flow:
@@ -0,0 +1,87 @@
import { describe, expect, it, vi } from "vitest";
import {
claimDeliveryQueueEntryPlatformSend,
dispatchDeliveryQueueEntryPlatformSend,
} from "./delivery-queue-sqlite-claim.js";
import { loadDeliveryQueueEntry, upsertDeliveryQueueEntry } from "./delivery-queue-sqlite.js";
import { installDeliveryQueueTmpDirHooks } from "./outbound/delivery-queue.test-helpers.js";
describe("delivery queue SQLite dispatch ownership", () => {
const { tmpDir } = installDeliveryQueueTmpDirHooks();
const queueName = "test-dispatch-owner";
it("atomically promotes dispatch ownership and rejects expired or replaced claims", () => {
vi.useFakeTimers();
try {
vi.setSystemTime(new Date("2026-08-10T10:00:00.000Z"));
const stateDir = tmpDir();
const id = "cron-direct-delivery:v1:dispatch-owner";
upsertDeliveryQueueEntry({
queueName,
entry: {
id,
enqueuedAt: Date.now(),
retryCount: 0,
completionRetention: {
idPrefix: "cron-direct-delivery:v1:",
maxAgeMs: 24 * 60 * 60_000,
maxEntries: 2,
},
requiresProducerClaim: true,
},
stateDir,
});
const expiredClaimId = claimDeliveryQueueEntryPlatformSend({ queueName, id, stateDir });
if (!expiredClaimId) {
throw new Error("test invariant: the first producer claim must be available");
}
vi.advanceTimersByTime(30_001);
expect(
dispatchDeliveryQueueEntryPlatformSend({
queueName,
id,
claimId: expiredClaimId,
stateDir,
}),
).toBe(false);
const claimId = claimDeliveryQueueEntryPlatformSend({ queueName, id, stateDir });
if (!claimId) {
throw new Error("test invariant: the replacement producer claim must be available");
}
expect(
dispatchDeliveryQueueEntryPlatformSend({
queueName,
id,
claimId: expiredClaimId,
stateDir,
}),
).toBe(false);
expect(
dispatchDeliveryQueueEntryPlatformSend({
queueName,
id,
claimId,
stateDir,
route: { replyToId: "thread-1" },
}),
).toBe(true);
expect(loadDeliveryQueueEntry(queueName, id, stateDir)).toMatchObject({
recoveryState: "send_attempt_started",
platformSendAttemptId: claimId,
platformSendStartedAt: Date.now(),
effectiveReplyToId: "thread-1",
availableAt: Date.now() + 30_000,
});
expect(loadDeliveryQueueEntry(queueName, id, stateDir)?.producerClaimId).toBeUndefined();
vi.advanceTimersByTime(30_001);
expect(dispatchDeliveryQueueEntryPlatformSend({ queueName, id, claimId, stateDir })).toBe(
false,
);
} finally {
vi.useRealTimers();
}
});
});
+59 -10
View File
@@ -68,9 +68,9 @@ export function transitionOwnedDeliveryQueueEntry(
);
}
function transitionUnsentDeliveryQueueEntry(
function transitionDeliveryQueueEntryPlatformSend(
params: PlatformClaimParams,
operation: "claim" | "promote",
operation: "claim" | "promote" | "dispatch",
transition: (entry: DeliveryQueueEntryState, now: number) => DeliveryQueueEntryState | undefined,
): boolean {
// State-database opens reuse the canonical path-owned connection, so both
@@ -82,13 +82,16 @@ function transitionUnsentDeliveryQueueEntry(
database.db,
() => {
const current = loadDeliveryQueueEntry(params.queueName, params.id, params.stateDir);
if (!current) {
return false;
}
if (
!current ||
(current.platformSendStartedAt !== undefined &&
(operation !== "claim" ||
current.platformSendStartedAt !== params.reconciledPlatformSendStartedAt ||
current.platformSendAttemptId !== params.reconciledPlatformSendAttemptId ||
typeof current.platformSendAttemptId !== "string"))
current.platformSendStartedAt !== undefined &&
(operation === "promote" ||
(operation === "claim" &&
(current.platformSendStartedAt !== params.reconciledPlatformSendStartedAt ||
current.platformSendAttemptId !== params.reconciledPlatformSendAttemptId ||
typeof current.platformSendAttemptId !== "string")))
) {
return false;
}
@@ -114,7 +117,7 @@ export function claimDeliveryQueueEntryPlatformSend(
params: PlatformClaimParams,
): string | undefined {
const claimId = generateSecureUuid();
return transitionUnsentDeliveryQueueEntry(params, "claim", (entry, now) => {
return transitionDeliveryQueueEntryPlatformSend(params, "claim", (entry, now) => {
const reconciledNotSent =
entry.recoveryState === "send_attempt_started" &&
typeof params.reconciledPlatformSendStartedAt === "number" &&
@@ -197,7 +200,7 @@ export function promoteDeliveryQueueEntryPlatformSend(
route?: { replyToId?: string | null };
},
): boolean {
return transitionUnsentDeliveryQueueEntry(params, "promote", (entry, now) =>
return transitionDeliveryQueueEntryPlatformSend(params, "promote", (entry, now) =>
entry.recoveryState === "producer_claimed" &&
entry.producerClaimId === params.claimId &&
typeof entry.availableAt === "number" &&
@@ -219,3 +222,49 @@ export function promoteDeliveryQueueEntryPlatformSend(
: undefined,
);
}
/** Atomically authorize dispatch, promoting a producer claim into the active attempt. */
export function dispatchDeliveryQueueEntryPlatformSend(
params: PlatformClaimParams & {
claimId: string;
route?: { replyToId?: string | null };
},
): boolean {
return transitionDeliveryQueueEntryPlatformSend(params, "dispatch", (entry, now) => {
const producerOwned =
entry.recoveryState === "producer_claimed" &&
entry.producerClaimId === params.claimId &&
typeof entry.availableAt === "number" &&
entry.availableAt > now;
const attemptOwned =
(entry.recoveryState === "send_attempt_started" ||
entry.recoveryState === "unknown_after_send") &&
entry.platformSendAttemptId === params.claimId &&
(entry.requiresProducerClaim !== true ||
(typeof entry.availableAt === "number" && entry.availableAt > now));
if (!producerOwned && !attemptOwned) {
return undefined;
}
return {
...entry,
// Exact reconciliation can skip pre-send promotion, so publish attempt identity
// atomically; later batch dispatches retain stronger unknown-after-send evidence.
availableAt:
entry.requiresProducerClaim === true
? producerOwned
? now + PLATFORM_SEND_OWNER_LEASE_MS
: entry.availableAt
: undefined,
producerClaimId: undefined,
platformSendAttemptId: params.claimId,
platformSendStartedAt: now,
...(params.route && "replyToId" in params.route
? { effectiveReplyToId: params.route.replyToId ?? null }
: {}),
recoveryState:
entry.recoveryState === "unknown_after_send"
? "unknown_after_send"
: "send_attempt_started",
};
});
}
@@ -0,0 +1,101 @@
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { createMessageReceiptFromOutboundResults } from "../../channels/message/receipt.js";
import type { ChannelMessageSendTextContext } from "../../channels/message/types.js";
import type { OpenClawConfig } from "../../config/config.js";
import { createEmptyPluginRegistry } from "../../plugins/registry.js";
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../../plugins/runtime.js";
import { createOutboundTestPlugin, createTestRegistry } from "../../test-utils/channel-plugins.js";
import { getDeliveryQueueEntryStatus } from "../delivery-queue-sqlite.js";
import {
boundedCronCompletionRetention,
drainMatrixReconnect,
matrixOutboundForQueueTest,
} from "./deliver.queue-integration.test-support.js";
import { OUTBOUND_DELIVERY_QUEUE_NAME } from "./delivery-queue-media-staging.js";
import type { DeliverFn } from "./delivery-queue.js";
import { installDeliveryQueueTmpDirHooks } from "./delivery-queue.test-helpers.js";
let deliverOutboundPayloads: typeof import("./deliver.js").deliverOutboundPayloads;
describe("exact Matrix delivery queue reconciliation", () => {
const fixtures = installDeliveryQueueTmpDirHooks();
let tmpDir: string;
beforeAll(async () => {
({ deliverOutboundPayloads } = await import("./deliver.js"));
});
beforeEach(() => {
tmpDir = fixtures.tmpDir();
});
afterEach(() => {
resetPluginRuntimeStateForTest();
setActivePluginRegistry(createEmptyPluginRegistry());
});
it.each(["required", "best_effort"] as const)(
"settles one exact Matrix %s send without restart replay",
async (queuePolicy) => {
process.env.OPENCLAW_STATE_DIR = tmpDir;
const deliveryIntentId = `cron-direct-delivery:v1:exact-${queuePolicy}-completion`;
const messageId = `exact-${queuePolicy}-message`;
const reconcileUnknownSend = vi.fn();
const sendText = vi.fn(async (ctx: ChannelMessageSendTextContext) => {
expect(ctx.deliveryQueueId).toBe(deliveryIntentId);
await ctx.onPlatformSendDispatch?.();
return {
messageId,
receipt: createMessageReceiptFromOutboundResults({
results: [{ channel: "matrix", messageId }],
kind: "text",
}),
};
});
setActivePluginRegistry(
createTestRegistry([
{
pluginId: "matrix",
source: "test",
plugin: {
...createOutboundTestPlugin({ id: "matrix", outbound: matrixOutboundForQueueTest }),
message: {
id: "matrix",
durableFinal: {
capabilities: { text: true, reconcileUnknownSend: true },
reconcileUnknownSendKinds: { text: true },
reconcileUnknownSend,
},
send: { text: sendText },
},
},
},
]),
);
const params = {
cfg: {} as OpenClawConfig,
channel: "matrix" as const,
to: "!room:example",
payloads: [{ text: "send exactly once with durable platform identity" }],
queuePolicy,
...(queuePolicy === "best_effort" ? { bestEffort: true } : {}),
deliveryIntentId,
completionRetention: boundedCronCompletionRetention,
reusePendingDeliveryIntent: true,
requireUnknownSendReconciliation: true,
};
await expect(deliverOutboundPayloads(params)).resolves.toMatchObject([{ messageId }]);
expect(sendText).toHaveBeenCalledOnce();
expect(reconcileUnknownSend).not.toHaveBeenCalled();
expect(
getDeliveryQueueEntryStatus(OUTBOUND_DELIVERY_QUEUE_NAME, deliveryIntentId, tmpDir),
).toBe("completed");
const recoveryDeliver = vi.fn<DeliverFn>(async () => []);
await drainMatrixReconnect({ deliver: recoveryDeliver, stateDir: tmpDir });
expect(recoveryDeliver).not.toHaveBeenCalled();
expect(sendText).toHaveBeenCalledOnce();
},
);
});
@@ -1,9 +1,26 @@
import {
claimDeliveryQueueEntryPlatformSend,
dispatchDeliveryQueueEntryPlatformSend,
renewDeliveryQueueEntryPlatformSendLease,
} from "../delivery-queue-sqlite-claim.js";
import { OUTBOUND_DELIVERY_QUEUE_NAME } from "./delivery-queue-media-staging.js";
/** Atomically transfer a stable pending producer intent to one platform sender. */
export async function claimDeliveryPlatformSendAttempt(
id: string,
stateDir?: string,
reconciledPlatformSendStartedAt?: number,
reconciledPlatformSendAttemptId?: string,
): Promise<string | undefined> {
return claimDeliveryQueueEntryPlatformSend({
queueName: OUTBOUND_DELIVERY_QUEUE_NAME,
id,
stateDir,
...(reconciledPlatformSendStartedAt !== undefined ? { reconciledPlatformSendStartedAt } : {}),
...(reconciledPlatformSendAttemptId !== undefined ? { reconciledPlatformSendAttemptId } : {}),
});
}
/** Claim and atomically upgrade a live reusable producer to renewable ownership. */
export async function claimReusableDeliveryPlatformSendAttempt(
id: string,
@@ -30,3 +47,22 @@ export async function renewDeliveryPlatformSendLease(
claimId,
});
}
/** Promote or refresh the exact live owner at recipient-visible dispatch. */
export function markOwnedDeliveryPlatformSendDispatched(
id: string,
stateDir: string | undefined,
route: { replyToId?: string | null } | undefined,
claimId: string,
): void {
const dispatched = dispatchDeliveryQueueEntryPlatformSend({
queueName: OUTBOUND_DELIVERY_QUEUE_NAME,
id,
stateDir,
route,
claimId,
});
if (!dispatched) {
throw new Error(`Delivery platform claim was lost: ${id}`);
}
}
+11 -20
View File
@@ -9,7 +9,6 @@ import type {
import type { ReplyToMode } from "../../config/types.js";
import type { PluginHookReplyPayloadSendingContext } from "../../plugins/hook-types.js";
import {
claimDeliveryQueueEntryPlatformSend,
promoteDeliveryQueueEntryPlatformSend,
transitionOwnedDeliveryQueueEntry,
type InitialDeliveryProducerClaim,
@@ -44,6 +43,7 @@ import {
OUTBOUND_DELIVERY_QUEUE_NAME,
OUTBOUND_LEGACY_PREPARATION_QUEUE_NAME,
} from "./delivery-queue-media-staging.js";
import { markOwnedDeliveryPlatformSendDispatched } from "./delivery-queue-platform-lease.js";
import {
StableDeliveryPreparationLostError,
type StableDeliveryPreparation,
@@ -481,21 +481,7 @@ export async function failDeliveryAfterPlatformSend(
);
}
/** Atomically transfer a stable pending producer intent to one platform sender. */
export async function claimDeliveryPlatformSendAttempt(
id: string,
stateDir?: string,
reconciledPlatformSendStartedAt?: number,
reconciledPlatformSendAttemptId?: string,
): Promise<string | undefined> {
return claimDeliveryQueueEntryPlatformSend({
queueName: OUTBOUND_DELIVERY_QUEUE_NAME,
id,
stateDir,
...(reconciledPlatformSendStartedAt !== undefined ? { reconciledPlatformSendStartedAt } : {}),
...(reconciledPlatformSendAttemptId !== undefined ? { reconciledPlatformSendAttemptId } : {}),
});
}
export { claimDeliveryPlatformSendAttempt } from "./delivery-queue-platform-lease.js";
/** Reserve one durable delivery call before invoking the provider path. */
export async function reserveDeliveryAttempt(
@@ -579,18 +565,23 @@ export async function markDeliveryPlatformSendDispatched(
route?: { replyToId?: string | null },
expectedPlatformSendAttemptId?: string | null,
): Promise<void> {
if (typeof expectedPlatformSendAttemptId === "string") {
markOwnedDeliveryPlatformSendDispatched(id, stateDir, route, expectedPlatformSendAttemptId);
return;
}
updateQueuedDelivery(
id,
stateDir,
(entry) => ({
...entry,
// Dispatch still belongs to the promoted producer until provider I/O
// settles; clearing its lease lets another process replay an active send.
availableAt: expectedPlatformSendAttemptId ? entry.availableAt : undefined,
availableAt: undefined,
producerClaimId: undefined,
platformSendStartedAt: Date.now(),
...(route && "replyToId" in route ? { effectiveReplyToId: route.replyToId ?? null } : {}),
recoveryState: "send_attempt_started",
// A later batch send must not erase concrete evidence from an earlier result;
// recovery could otherwise replay the whole batch and duplicate that delivery.
recoveryState:
entry.recoveryState === "unknown_after_send" ? entry.recoveryState : "send_attempt_started",
}),
expectedPlatformSendAttemptId,
);
@@ -547,6 +547,25 @@ describe("delivery-queue storage", () => {
expect(entry.recoveryState).toBe("send_attempt_started");
});
it("keeps ambiguous post-send evidence across a later unclaimed batch dispatch", async () => {
const id = await enqueueTextDelivery(
{
channel: "forum",
to: "123",
payloads: [{ text: "test" }],
},
tmpDir(),
);
await markDeliveryPlatformSendAttemptStarted(id, tmpDir());
await markDeliveryPlatformOutcomeUnknown(id, tmpDir());
await markDeliveryPlatformSendDispatched(id, tmpDir());
// Downgrading to send_attempt_started would let recovery replay the whole
// batch as not_sent and duplicate the payload that already reached the platform.
expect(readQueuedEntry(tmpDir(), id).recoveryState).toBe("unknown_after_send");
});
it("increments retryCount, records attempt time, and sets lastError", async () => {
const id = await enqueueTextDelivery(
{