File size: 4,850 Bytes
e249c6d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
import type {
ChannelOutboundTargetMode,
ChannelPlugin,
} from "../../channels/plugins/types.public.js";
import type { SessionEntry } from "../../config/sessions/types.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import {
resolveAgentDeliveryPlanWithSessionRoute,
resolveAgentOutboundTarget,
} from "../../infra/outbound/agent-delivery.js";
import { resolveMessageChannelSelection } from "../../infra/outbound/channel-selection.js";
import {
normalizeDeliveryContext,
type DeliveryContext,
} from "../../utils/delivery-context.shared.js";
import {
INTERNAL_MESSAGE_CHANNEL,
isDeliverableMessageChannel,
} from "../../utils/message-channel.js";
import type { AgentRunSessionTarget } from "../run-session-target.js";
import type { AgentCommandOpts } from "./types.js";
export function clearPendingFinalDelivery(entry: SessionEntry, updatedAt: number): SessionEntry {
return {
...entry,
pendingFinalDelivery: undefined,
restartRecoveryForceSafeTools: undefined,
restartRecoveryDeliveryMediaUrls: undefined,
restartRecoveryDisableMessageTool: undefined,
restartRecoverySuppressTextDelivery: undefined,
updatedAt,
};
}
type PreparedCurrentRunDelivery = {
context: DeliveryContext;
targetMode: ChannelOutboundTargetMode;
};
export async function prepareCurrentRunDelivery(params: {
cfg: OpenClawConfig;
opts: AgentCommandOpts;
agentId: string;
currentSessionKey?: string;
sessionEntry?: SessionEntry;
}): Promise<PreparedCurrentRunDelivery | undefined> {
const { cfg, opts, sessionEntry } = params;
if (opts.deliver !== true) {
return undefined;
}
const buildPlan = async (requestedChannel: string | undefined, preparedPlugin?: ChannelPlugin) =>
await resolveAgentDeliveryPlanWithSessionRoute({
cfg,
agentId: params.agentId,
currentSessionKey: params.currentSessionKey,
sessionEntry,
requestedChannel,
explicitTo: opts.replyTo ?? opts.to,
explicitThreadId: opts.threadId,
accountId: opts.replyAccountId ?? opts.accountId,
wantsDelivery: true,
turnSourceChannel: opts.runContext?.messageChannel ?? opts.messageChannel,
turnSourceTo: opts.runContext?.currentChannelId ?? opts.to,
turnSourceAccountId: opts.runContext?.accountId ?? opts.accountId,
turnSourceThreadId: opts.runContext?.currentThreadTs ?? opts.threadId,
preparedPlugin,
});
let deliveryPlan = await buildPlan(opts.replyChannel ?? opts.channel);
const explicitChannelHint = normalizeOptionalString(opts.replyChannel ?? opts.channel);
const explicitThreadId =
opts.threadId != null && opts.threadId !== "" ? opts.threadId : undefined;
if (deliveryPlan.resolvedChannel === INTERNAL_MESSAGE_CHANNEL && !explicitChannelHint) {
const selection = await resolveMessageChannelSelection({ cfg });
deliveryPlan = await buildPlan(selection.channel, selection.plugin);
}
if (deliveryPlan.targetResolutionError) {
throw deliveryPlan.targetResolutionError;
}
if (!isDeliverableMessageChannel(deliveryPlan.resolvedChannel)) {
throw new Error(
"delivery channel is required: pass --channel/--reply-channel or use a main session with a previous channel",
);
}
const targetMode =
opts.deliveryTargetMode ??
deliveryPlan.deliveryTargetMode ??
((opts.replyTo ?? opts.to) ? "explicit" : "implicit");
const resolved = resolveAgentOutboundTarget({
cfg,
plan: deliveryPlan,
targetMode,
validateExplicitTarget: true,
});
if (resolved.resolvedTarget && !resolved.resolvedTarget.ok) {
throw resolved.resolvedTarget.error;
}
const resolvedTo = resolved.resolvedTo;
if (!resolvedTo) {
throw new Error(`delivery target is required for ${deliveryPlan.resolvedChannel}`);
}
const threadId =
targetMode === "explicit"
? (explicitThreadId ??
(deliveryPlan.baseDelivery.threadIdSource === "explicit"
? deliveryPlan.resolvedThreadId
: undefined))
: deliveryPlan.resolvedThreadId;
const context = normalizeDeliveryContext({
channel: deliveryPlan.resolvedChannel,
to: resolvedTo,
accountId: deliveryPlan.resolvedAccountId,
threadId,
});
return context ? { context, targetMode } : undefined;
}
export function resolveInternalSessionEffectsSource(params: {
agentId: string;
sessionId: string;
sessionKey?: string;
storePath?: string;
}):
| Required<Pick<AgentRunSessionTarget, "agentId" | "sessionId" | "sessionKey" | "storePath">>
| undefined {
if (!params.storePath || !params.sessionKey) {
return undefined;
}
return {
agentId: params.agentId,
sessionId: params.sessionId,
sessionKey: params.sessionKey,
storePath: params.storePath,
};
}
|