UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

135 lines (134 loc) 6.77 kB
import { c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js"; import { t as normalizeChatType } from "./chat-type-CxEvM45e.js"; import { a as resolveAcpThreadSessionDetailLines, n as resolveAcpSessionCwd } from "./session-identifiers-Yz4V9hoo.js"; import { n as readAcpSessionEntry } from "./session-meta-BuCj-TpW.js"; import { n as getSessionBindingService, s as normalizeConversationRef } from "./session-binding-service-cfUL2BWM.js"; import { c as resolveThreadBindingMaxAgeMsForChannel, l as resolveThreadBindingPlacementForCurrentContext, n as formatThreadBindingSpawnDisabledError, o as resolveThreadBindingIdleTimeoutMsForChannel, t as formatThreadBindingDisabledError, u as resolveThreadBindingSpawnPolicy } from "./thread-bindings-policy-DZGWBoLX.js"; import { i as resolveThreadBindingThreadName, r as resolveThreadBindingIntroText } from "./thread-bindings-messages-Dew3j_KP.js"; import { r as resolveConversationBindingContextFromAcpCommand } from "./conversation-binding-input-DT_BtDDW.js"; import { i as resolveFocusTargetSession, l as stopWithText, r as resolveCommandSubagentController } from "./shared-jeYHliLc.js"; //#region src/auto-reply/reply/commands-subagents/action-focus.ts function resolveFocusBindingContext(params) { const bindingContext = resolveConversationBindingContextFromAcpCommand(params); if (!bindingContext) return null; const chatType = normalizeChatType(params.ctx.ChatType); const conversation = normalizeConversationRef({ channel: bindingContext.channel, accountId: bindingContext.accountId, conversationId: bindingContext.conversationId, parentConversationId: bindingContext.parentConversationId }); return { channel: conversation.channel, accountId: conversation.accountId, conversationId: conversation.conversationId, ...conversation.parentConversationId ? { parentConversationId: conversation.parentConversationId } : {}, placement: chatType === "direct" ? "current" : resolveThreadBindingPlacementForCurrentContext({ channel: bindingContext.channel, threadId: bindingContext.threadId || void 0 }) }; } async function handleSubagentsFocusAction(ctx) { const { params, runs, restTokens } = ctx; const token = restTokens.join(" ").trim(); if (!token) return stopWithText("Usage: /focus <subagent-label|session-key|session-id|session-label>"); const controller = resolveCommandSubagentController(params, ctx.requesterKey); if (controller.controlScope !== "children") return stopWithText("⚠️ Leaf subagents cannot control other sessions."); const bindingContext = resolveFocusBindingContext(params); if (!bindingContext) return stopWithText("⚠️ /focus must be run inside a bindable conversation."); const bindingService = getSessionBindingService(); const capabilities = bindingService.getCapabilities({ channel: bindingContext.channel, accountId: bindingContext.accountId }); if (!capabilities.adapterAvailable || !capabilities.bindSupported) return stopWithText("⚠️ Conversation bindings are unavailable for this account."); const focusTarget = await resolveFocusTargetSession({ runs, token, requesterKey: controller.controllerSessionKey }); if (!focusTarget) return stopWithText(`⚠️ Unable to resolve focus target: ${token}`); if (bindingContext.placement === "child") { const spawnPolicy = resolveThreadBindingSpawnPolicy({ cfg: params.cfg, channel: bindingContext.channel, accountId: bindingContext.accountId, kind: "subagent" }); if (!spawnPolicy.enabled) return stopWithText(`⚠️ ${formatThreadBindingDisabledError({ channel: spawnPolicy.channel, accountId: spawnPolicy.accountId, kind: "subagent" })}`); if (bindingContext.placement === "child" && !spawnPolicy.spawnEnabled) return stopWithText(`⚠️ ${formatThreadBindingSpawnDisabledError({ channel: spawnPolicy.channel, accountId: spawnPolicy.accountId, kind: "subagent" })}`); } const senderId = normalizeOptionalString(params.command.senderId) ?? ""; const conversationRef = normalizeConversationRef({ channel: bindingContext.channel, accountId: bindingContext.accountId, conversationId: bindingContext.conversationId, parentConversationId: bindingContext.parentConversationId }); const existingBinding = bindingService.resolveByConversation(conversationRef); const boundBy = typeof existingBinding?.metadata?.boundBy === "string" ? existingBinding.metadata.boundBy.trim() : ""; if (existingBinding && boundBy && boundBy !== "system" && senderId && senderId !== boundBy) return stopWithText(`⚠️ Only ${boundBy} can refocus this conversation.`); const label = focusTarget.label || token; const accountId = bindingContext.accountId; const acpMeta = focusTarget.targetKind === "acp" ? readAcpSessionEntry({ cfg: params.cfg, sessionKey: focusTarget.targetSessionKey })?.acp : void 0; if (!capabilities.placements.includes(bindingContext.placement)) return stopWithText("⚠️ Conversation bindings are unavailable for this account."); let binding; try { binding = await bindingService.bind({ targetSessionKey: focusTarget.targetSessionKey, targetKind: focusTarget.targetKind === "acp" ? "session" : "subagent", conversation: normalizeConversationRef({ channel: bindingContext.channel, accountId: bindingContext.accountId, conversationId: bindingContext.conversationId, parentConversationId: bindingContext.parentConversationId }), placement: bindingContext.placement, metadata: { threadName: resolveThreadBindingThreadName({ agentId: focusTarget.agentId, label }), agentId: focusTarget.agentId, label, boundBy: senderId || "unknown", introText: resolveThreadBindingIntroText({ agentId: focusTarget.agentId, label, idleTimeoutMs: resolveThreadBindingIdleTimeoutMsForChannel({ cfg: params.cfg, channel: bindingContext.channel, accountId }), maxAgeMs: resolveThreadBindingMaxAgeMsForChannel({ cfg: params.cfg, channel: bindingContext.channel, accountId }), sessionCwd: focusTarget.targetKind === "acp" ? resolveAcpSessionCwd(acpMeta) : void 0, sessionDetails: focusTarget.targetKind === "acp" ? resolveAcpThreadSessionDetailLines({ sessionKey: focusTarget.targetSessionKey, meta: acpMeta }) : [] }) } }); } catch { return stopWithText("⚠️ Failed to bind this conversation to the target session."); } return stopWithText(`✅ ${bindingContext.placement === "child" ? `created child conversation ${binding.conversation.conversationId} and bound it to ${binding.targetSessionKey}` : `bound this conversation to ${binding.targetSessionKey}`} (${focusTarget.targetKind}).`); } //#endregion export { handleSubagentsFocusAction };