diff --git a/src/auto-reply/reply/commands-acp/lifecycle.ts b/src/auto-reply/reply/commands-acp/lifecycle.ts index c33516084f8..03c5741d2bb 100644 --- a/src/auto-reply/reply/commands-acp/lifecycle.ts +++ b/src/auto-reply/reply/commands-acp/lifecycle.ts @@ -35,7 +35,10 @@ import { updateSessionStore } from "../../../config/sessions.js"; import type { SessionAcpMeta } from "../../../config/sessions/types.js"; import { getSessionBindingService, + type ConversationRef, + type SessionBindingPlacement, type SessionBindingRecord, + type SessionBindingService, } from "../../../infra/outbound/session-binding-service.js"; import type { CommandHandlerResult, HandleCommandsParams } from "../commands-types.js"; import { @@ -92,6 +95,90 @@ async function resolveBoundReplyChannelData(params: { return resolved ?? undefined; } +function buildSpawnedAcpBindingMetadata(params: { + cfg: OpenClawConfig; + channel: string; + accountId: string; + sessionKey: string; + agentId: string; + label: string; + senderId: string; + sessionMeta?: SessionAcpMeta; +}): Record { + return { + threadName: resolveThreadBindingThreadName({ + agentId: params.agentId, + label: params.label, + }), + agentId: params.agentId, + label: params.label, + boundBy: params.senderId || "unknown", + introText: resolveThreadBindingIntroText({ + agentId: params.agentId, + label: params.label, + idleTimeoutMs: resolveThreadBindingIdleTimeoutMsForChannel({ + cfg: params.cfg, + channel: params.channel, + accountId: params.accountId, + }), + maxAgeMs: resolveThreadBindingMaxAgeMsForChannel({ + cfg: params.cfg, + channel: params.channel, + accountId: params.accountId, + }), + sessionCwd: resolveAcpSessionCwd(params.sessionMeta), + sessionDetails: resolveAcpThreadSessionDetailLines({ + sessionKey: params.sessionKey, + meta: params.sessionMeta, + }), + }), + }; +} + +async function bindSpawnedAcpSession(params: { + bindingService: SessionBindingService; + sessionKey: string; + conversationRef: ConversationRef; + placement: SessionBindingPlacement; + cfg: OpenClawConfig; + channel: string; + accountId: string; + agentId: string; + label: string; + senderId: string; + sessionMeta?: SessionAcpMeta; + bindError: string; +}): Promise<{ ok: true; binding: SessionBindingRecord } | { ok: false; error: string }> { + try { + const binding = await params.bindingService.bind({ + targetSessionKey: params.sessionKey, + targetKind: "session", + conversation: params.conversationRef, + placement: params.placement, + metadata: buildSpawnedAcpBindingMetadata({ + cfg: params.cfg, + channel: params.channel, + accountId: params.accountId, + sessionKey: params.sessionKey, + agentId: params.agentId, + label: params.label, + senderId: params.senderId, + sessionMeta: params.sessionMeta, + }), + }); + return { + ok: true, + binding, + }; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + return { + ok: false, + error: message || params.bindError, + }; + } +} + async function bindSpawnedAcpSessionToCurrentConversation(params: { commandParams: HandleCommandsParams; sessionKey: string; @@ -188,53 +275,20 @@ async function bindSpawnedAcpSessionToCurrentConversation(params: { } const label = params.label || params.agentId; - try { - const binding = await bindingService.bind({ - targetSessionKey: params.sessionKey, - targetKind: "session", - conversation: conversationRef, - placement: "current", - metadata: { - threadName: resolveThreadBindingThreadName({ - agentId: params.agentId, - label, - }), - agentId: params.agentId, - label, - boundBy: senderId || "unknown", - introText: resolveThreadBindingIntroText({ - agentId: params.agentId, - label, - idleTimeoutMs: resolveThreadBindingIdleTimeoutMsForChannel({ - cfg: params.commandParams.cfg, - channel: bindingPolicy.channel, - accountId: bindingPolicy.accountId, - }), - maxAgeMs: resolveThreadBindingMaxAgeMsForChannel({ - cfg: params.commandParams.cfg, - channel: bindingPolicy.channel, - accountId: bindingPolicy.accountId, - }), - sessionCwd: resolveAcpSessionCwd(params.sessionMeta), - sessionDetails: resolveAcpThreadSessionDetailLines({ - sessionKey: params.sessionKey, - meta: params.sessionMeta, - }), - }), - }, - }); - return { - ok: true, - binding, - }; - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - ok: false, - error: - message || `Failed to bind the current ${channel} conversation to the new ACP session.`, - }; - } + return bindSpawnedAcpSession({ + bindingService, + sessionKey: params.sessionKey, + conversationRef, + placement: "current", + cfg: params.commandParams.cfg, + channel: bindingPolicy.channel, + accountId: bindingPolicy.accountId, + agentId: params.agentId, + label, + senderId, + sessionMeta: params.sessionMeta, + bindError: `Failed to bind the current ${channel} conversation to the new ACP session.`, + }); } async function bindSpawnedAcpSessionToThread(params: { @@ -369,53 +423,20 @@ async function bindSpawnedAcpSessionToThread(params: { } const label = params.label || params.agentId; - - try { - const binding = await bindingService.bind({ - targetSessionKey: params.sessionKey, - targetKind: "session", - conversation: conversationRef, - placement, - metadata: { - threadName: resolveThreadBindingThreadName({ - agentId: params.agentId, - label, - }), - agentId: params.agentId, - label, - boundBy: senderId || "unknown", - introText: resolveThreadBindingIntroText({ - agentId: params.agentId, - label, - idleTimeoutMs: resolveThreadBindingIdleTimeoutMsForChannel({ - cfg: commandParams.cfg, - channel: spawnPolicy.channel, - accountId: spawnPolicy.accountId, - }), - maxAgeMs: resolveThreadBindingMaxAgeMsForChannel({ - cfg: commandParams.cfg, - channel: spawnPolicy.channel, - accountId: spawnPolicy.accountId, - }), - sessionCwd: resolveAcpSessionCwd(params.sessionMeta), - sessionDetails: resolveAcpThreadSessionDetailLines({ - sessionKey: params.sessionKey, - meta: params.sessionMeta, - }), - }), - }, - }); - return { - ok: true, - binding, - }; - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - ok: false, - error: message || `Failed to bind a ${channel} thread/conversation to the new ACP session.`, - }; - } + return bindSpawnedAcpSession({ + bindingService, + sessionKey: params.sessionKey, + conversationRef, + placement, + cfg: commandParams.cfg, + channel: spawnPolicy.channel, + accountId: spawnPolicy.accountId, + agentId: params.agentId, + label, + senderId, + sessionMeta: params.sessionMeta, + bindError: `Failed to bind a ${channel} thread/conversation to the new ACP session.`, + }); } async function cleanupFailedSpawn(params: {