From a6816cb59ce6ee90a889b6cb8aeb1dafa29c1e52 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 3 Apr 2026 15:59:26 +0100 Subject: [PATCH] test: reduce subagent announce import overhead --- .../subagent-announce-delivery.runtime.ts | 4 + src/agents/subagent-announce-delivery.ts | 43 +++++--- src/agents/subagent-announce-output.ts | 12 +-- .../subagent-announce.registry.runtime.ts | 11 ++ src/agents/subagent-announce.runtime.ts | 13 +++ src/agents/subagent-announce.test.ts | 97 ++++++++--------- src/agents/subagent-announce.timeout.test.ts | 102 +++++++++--------- src/agents/subagent-announce.ts | 15 +-- src/agents/tools/session-message-text.ts | 50 +++++++++ src/agents/tools/sessions-send-helpers.ts | 17 ++- src/agents/tools/sessions-send-tokens.ts | 10 ++ 11 files changed, 231 insertions(+), 143 deletions(-) create mode 100644 src/agents/subagent-announce-delivery.runtime.ts create mode 100644 src/agents/subagent-announce.registry.runtime.ts create mode 100644 src/agents/subagent-announce.runtime.ts create mode 100644 src/agents/tools/session-message-text.ts create mode 100644 src/agents/tools/sessions-send-tokens.ts diff --git a/src/agents/subagent-announce-delivery.runtime.ts b/src/agents/subagent-announce-delivery.runtime.ts new file mode 100644 index 00000000000..bf686e442c2 --- /dev/null +++ b/src/agents/subagent-announce-delivery.runtime.ts @@ -0,0 +1,4 @@ +export { resolveQueueSettings } from "../auto-reply/reply/queue.js"; +export { resolveExternalBestEffortDeliveryTarget } from "../infra/outbound/best-effort-delivery.js"; +export { createBoundDeliveryRouter } from "../infra/outbound/bound-delivery-router.js"; +export { resolveConversationIdFromTargets } from "../infra/outbound/conversation-id.js"; diff --git a/src/agents/subagent-announce-delivery.ts b/src/agents/subagent-announce-delivery.ts index 2501d3ed98e..5039f5d6327 100644 --- a/src/agents/subagent-announce-delivery.ts +++ b/src/agents/subagent-announce-delivery.ts @@ -1,16 +1,4 @@ -import { resolveQueueSettings } from "../auto-reply/reply/queue.js"; import { parseExplicitTargetForChannel } from "../channels/plugins/target-parsing.js"; -import { loadConfig } from "../config/config.js"; -import { - loadSessionStore, - resolveAgentIdFromSessionKey, - resolveMainSessionKey, - resolveStorePath, -} from "../config/sessions.js"; -import { callGateway } from "../gateway/call.js"; -import { resolveExternalBestEffortDeliveryTarget } from "../infra/outbound/best-effort-delivery.js"; -import { createBoundDeliveryRouter } from "../infra/outbound/bound-delivery-router.js"; -import { resolveConversationIdFromTargets } from "../infra/outbound/conversation-id.js"; import type { ConversationRef } from "../infra/outbound/session-binding-service.js"; import { getGlobalHookRunner } from "../plugins/hook-runner-global.js"; import { normalizeAccountId, normalizeMainKey } from "../routing/session-key.js"; @@ -31,12 +19,21 @@ import { } from "../utils/message-channel.js"; import { buildAnnounceIdempotencyKey, resolveQueueAnnounceId } from "./announce-idempotency.js"; import type { AgentInternalEvent } from "./internal-events.js"; -import { isEmbeddedPiRunActive, queueEmbeddedPiMessage } from "./pi-embedded.js"; import { runSubagentAnnounceDispatch, type SubagentAnnounceDeliveryResult, } from "./subagent-announce-dispatch.js"; import { type AnnounceQueueItem, enqueueAnnounce } from "./subagent-announce-queue.js"; +import { + callGateway, + isEmbeddedPiRunActive, + loadConfig, + loadSessionStore, + queueEmbeddedPiMessage, + resolveAgentIdFromSessionKey, + resolveMainSessionKey, + resolveStorePath, +} from "./subagent-announce.runtime.js"; import { getSubagentDepthFromSessionStore } from "./subagent-depth.js"; import type { SpawnSubagentMode } from "./subagent-spawn.js"; @@ -56,6 +53,15 @@ const defaultSubagentAnnounceDeliveryDeps: SubagentAnnounceDeliveryDeps = { let subagentAnnounceDeliveryDeps: SubagentAnnounceDeliveryDeps = defaultSubagentAnnounceDeliveryDeps; +let subagentAnnounceDeliveryRuntimePromise: Promise< + typeof import("./subagent-announce-delivery.runtime.js") +> | null = null; + +function loadSubagentAnnounceDeliveryRuntime() { + subagentAnnounceDeliveryRuntimePromise ??= import("./subagent-announce-delivery.runtime.js"); + return subagentAnnounceDeliveryRuntimePromise; +} + function resolveDirectAnnounceTransientRetryDelaysMs() { return process.env.OPENCLAW_TEST_FAST === "1" ? ([8, 16, 32] as const) @@ -260,6 +266,7 @@ export async function resolveSubagentCompletionOrigin(params: { spawnMode?: SpawnSubagentMode; expectsCompletionMessage: boolean; }): Promise { + const deliveryRuntime = await loadSubagentAnnounceDeliveryRuntime(); const requesterOrigin = normalizeDeliveryContext(params.requesterOrigin); const channel = requesterOrigin?.channel?.trim().toLowerCase(); const to = requesterOrigin?.to?.trim(); @@ -270,14 +277,14 @@ export async function resolveSubagentCompletionOrigin(params: { : undefined; const conversationId = threadId || - resolveConversationIdFromTargets({ + deliveryRuntime.resolveConversationIdFromTargets({ targets: [to], }) || ""; const requesterConversation: ConversationRef | undefined = channel && conversationId ? { channel, accountId, conversationId } : undefined; - const route = createBoundDeliveryRouter().resolveDestination({ + const route = deliveryRuntime.createBoundDeliveryRouter().resolveDestination({ eventKind: "task_completion", targetSessionKey: params.childSessionKey, requester: requesterConversation, @@ -438,6 +445,7 @@ async function maybeQueueSubagentAnnounce(params: { if (params.signal?.aborted) { return "none"; } + const deliveryRuntime = await loadSubagentAnnounceDeliveryRuntime(); const { cfg, entry } = loadRequesterSessionEntry(params.requesterSessionKey); const canonicalKey = resolveRequesterStoreKey(cfg, params.requesterSessionKey); const sessionId = entry?.sessionId; @@ -445,7 +453,7 @@ async function maybeQueueSubagentAnnounce(params: { return "none"; } - const queueSettings = resolveQueueSettings({ + const queueSettings = deliveryRuntime.resolveQueueSettings({ cfg, channel: entry?.channel ?? entry?.lastChannel ?? entry?.origin?.provider, sessionEntry: entry, @@ -512,6 +520,7 @@ async function sendSubagentAnnounceDirectly(params: { path: "none", }; } + const deliveryRuntime = await loadSubagentAnnounceDeliveryRuntime(); const cfg = subagentAnnounceDeliveryDeps.loadConfig(); const announceTimeoutMs = resolveSubagentAnnounceTimeoutMs(cfg); const canonicalRequesterSessionKey = resolveRequesterStoreKey( @@ -530,7 +539,7 @@ async function sendSubagentAnnounceDirectly(params: { ? effectiveDirectOrigin : requesterSessionOrigin; const deliveryTarget = !params.requesterIsSubagent - ? resolveExternalBestEffortDeliveryTarget({ + ? deliveryRuntime.resolveExternalBestEffortDeliveryTarget({ channel: effectiveDirectOrigin?.channel, to: effectiveDirectOrigin?.to, accountId: effectiveDirectOrigin?.accountId, diff --git a/src/agents/subagent-announce-output.ts b/src/agents/subagent-announce-output.ts index d53b2d6e730..db27e0f6cbd 100644 --- a/src/agents/subagent-announce-output.ts +++ b/src/agents/subagent-announce-output.ts @@ -1,15 +1,15 @@ import { isSilentReplyText, SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js"; -import { loadConfig } from "../config/config.js"; +import { extractTextFromChatContent } from "../shared/chat-content.js"; import { + callGateway, + loadConfig, loadSessionStore, resolveAgentIdFromSessionKey, resolveStorePath, -} from "../config/sessions.js"; -import { callGateway } from "../gateway/call.js"; -import { extractTextFromChatContent } from "../shared/chat-content.js"; +} from "./subagent-announce.runtime.js"; import { readLatestAssistantReply } from "./tools/agent-step.js"; -import { sanitizeTextContent, extractAssistantText } from "./tools/sessions-helpers.js"; -import { isAnnounceSkip } from "./tools/sessions-send-helpers.js"; +import { extractAssistantText, sanitizeTextContent } from "./tools/session-message-text.js"; +import { isAnnounceSkip } from "./tools/sessions-send-tokens.js"; const FAST_TEST_RETRY_INTERVAL_MS = 8; diff --git a/src/agents/subagent-announce.registry.runtime.ts b/src/agents/subagent-announce.registry.runtime.ts new file mode 100644 index 00000000000..d562994b4b5 --- /dev/null +++ b/src/agents/subagent-announce.registry.runtime.ts @@ -0,0 +1,11 @@ +export { + countActiveDescendantRuns, + countPendingDescendantRuns, + countPendingDescendantRunsExcludingRun, + getLatestSubagentRunByChildSessionKey, + isSubagentSessionRunActive, + listSubagentRunsForRequester, + replaceSubagentRunAfterSteer, + resolveRequesterForChildSession, + shouldIgnorePostCompletionAnnounceForSession, +} from "./subagent-registry-runtime.js"; diff --git a/src/agents/subagent-announce.runtime.ts b/src/agents/subagent-announce.runtime.ts new file mode 100644 index 00000000000..ec73e311584 --- /dev/null +++ b/src/agents/subagent-announce.runtime.ts @@ -0,0 +1,13 @@ +export { loadConfig } from "../config/config.js"; +export { + loadSessionStore, + resolveAgentIdFromSessionKey, + resolveMainSessionKey, + resolveStorePath, +} from "../config/sessions.js"; +export { callGateway } from "../gateway/call.js"; +export { + isEmbeddedPiRunActive, + queueEmbeddedPiMessage, + waitForEmbeddedPiRunEnd, +} from "./pi-embedded.js"; diff --git a/src/agents/subagent-announce.test.ts b/src/agents/subagent-announce.test.ts index fafd5297c26..119f88843fb 100644 --- a/src/agents/subagent-announce.test.ts +++ b/src/agents/subagent-announce.test.ts @@ -35,65 +35,60 @@ const { subagentRegistryRuntimeMock } = vi.hoisted(() => ({ }, })); -vi.mock("../config/config.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - loadConfig: () => mockConfig, - resolveGatewayPort: () => 18789, - }; -}); - -vi.mock("../config/sessions.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - loadSessionStore: (storePath: string) => loadSessionStoreMock(storePath), - resolveAgentIdFromSessionKey: (sessionKey: string) => - resolveAgentIdFromSessionKeyMock(sessionKey), - resolveMainSessionKey: (cfg: unknown) => resolveMainSessionKeyMock(cfg), - resolveStorePath: (store: unknown, options: unknown) => resolveStorePathMock(store, options), - }; -}); - -vi.mock("../gateway/call.js", () => ({ - callGateway: (request: unknown) => callGatewayMock(request), -})); - vi.mock("../plugins/hook-runner-global.js", () => ({ getGlobalHookRunner: () => ({ hasHooks: () => false }), })); - -vi.mock("./pi-embedded.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - isEmbeddedPiRunActive: (sessionId: string) => isEmbeddedPiRunActiveMock(sessionId), - queueEmbeddedPiMessage: (sessionId: string, text: string) => - queueEmbeddedPiMessageMock(sessionId, text), - waitForEmbeddedPiRunEnd: (sessionId: string, timeoutMs?: number) => - waitForEmbeddedPiRunEndMock(sessionId, timeoutMs), - }; -}); +vi.mock("./subagent-announce.runtime.js", () => ({ + callGateway: (request: unknown) => callGatewayMock(request), + isEmbeddedPiRunActive: (sessionId: string) => isEmbeddedPiRunActiveMock(sessionId), + loadConfig: () => mockConfig, + loadSessionStore: (storePath: string) => loadSessionStoreMock(storePath), + queueEmbeddedPiMessage: (sessionId: string, text: string) => + queueEmbeddedPiMessageMock(sessionId, text), + resolveAgentIdFromSessionKey: (sessionKey: string) => + resolveAgentIdFromSessionKeyMock(sessionKey), + resolveMainSessionKey: (cfg: unknown) => resolveMainSessionKeyMock(cfg), + resolveStorePath: (store: unknown, options: unknown) => resolveStorePathMock(store, options), + waitForEmbeddedPiRunEnd: (sessionId: string, timeoutMs?: number) => + waitForEmbeddedPiRunEndMock(sessionId, timeoutMs), +})); vi.mock("./tools/agent-step.js", () => ({ readLatestAssistantReply: (params?: unknown) => readLatestAssistantReplyMock(params), })); -vi.mock("./subagent-registry.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - ...subagentRegistryRuntimeMock, - }; -}); -vi.mock("./subagent-registry-runtime.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - ...subagentRegistryRuntimeMock, - }; -}); +vi.mock("./subagent-announce-delivery.runtime.js", () => ({ + createBoundDeliveryRouter: () => ({ + resolveDestination: () => ({ mode: "none" }), + }), + resolveConversationIdFromTargets: () => "", + resolveExternalBestEffortDeliveryTarget: (params: { + channel?: string; + to?: string; + accountId?: string; + threadId?: string; + }) => ({ + deliver: Boolean(params.channel && params.to), + channel: params.channel, + to: params.to, + accountId: params.accountId, + threadId: params.threadId, + }), + resolveQueueSettings: (params: { + cfg?: { + messages?: { + queue?: { + byChannel?: Record; + }; + }; + }; + channel?: string; + }) => ({ + mode: (params.channel && params.cfg?.messages?.queue?.byChannel?.[params.channel]) ?? "none", + }), +})); + +vi.mock("./subagent-announce.registry.runtime.js", () => subagentRegistryRuntimeMock); import { runSubagentAnnounceFlow } from "./subagent-announce.js"; describe("subagent announce seam flow", () => { diff --git a/src/agents/subagent-announce.timeout.test.ts b/src/agents/subagent-announce.timeout.test.ts index 1dd53ffda3c..f34fa0f41c5 100644 --- a/src/agents/subagent-announce.timeout.test.ts +++ b/src/agents/subagent-announce.timeout.test.ts @@ -79,60 +79,56 @@ function createTimeoutHistoryWithNoReply() { } vi.mock("../gateway/call.js", createGatewayCallModuleMock); -vi.mock("../config/config.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - loadConfig: () => configOverride, - resolveGatewayPort: () => 18789, - }; -}); -vi.mock("../config/sessions.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - ...createSessionsModuleMock(), - }; -}); vi.mock("./subagent-depth.js", createSubagentDepthModuleMock); -vi.mock("./pi-embedded.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - isEmbeddedPiRunActive: (sessionId: string) => isEmbeddedPiRunActiveMock(sessionId), - queueEmbeddedPiMessage: (_sessionId: string, _text: string) => false, - waitForEmbeddedPiRunEnd: (sessionId: string, timeoutMs?: number) => - waitForEmbeddedPiRunEndMock(sessionId, timeoutMs), - }; -}); -vi.mock("./subagent-registry.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - countActiveDescendantRuns: () => 0, - countPendingDescendantRuns: () => pendingDescendantRuns, - countPendingDescendantRunsExcludingRun: () => 0, - listSubagentRunsForRequester: () => [], - isSubagentSessionRunActive: () => subagentSessionRunActive, - shouldIgnorePostCompletionAnnounceForSession: () => shouldIgnorePostCompletion, - replaceSubagentRunAfterSteer: () => true, - resolveRequesterForChildSession: () => fallbackRequesterResolution, - }; -}); -vi.mock("./subagent-registry-runtime.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - countActiveDescendantRuns: () => 0, - countPendingDescendantRuns: () => pendingDescendantRuns, - countPendingDescendantRunsExcludingRun: () => 0, - listSubagentRunsForRequester: () => [], - isSubagentSessionRunActive: () => subagentSessionRunActive, - shouldIgnorePostCompletionAnnounceForSession: () => shouldIgnorePostCompletion, - replaceSubagentRunAfterSteer: () => true, - resolveRequesterForChildSession: () => fallbackRequesterResolution, - }; -}); +vi.mock("./subagent-announce-delivery.runtime.js", () => ({ + createBoundDeliveryRouter: () => ({ + resolveDestination: () => ({ mode: "none" }), + }), + resolveConversationIdFromTargets: () => "", + resolveExternalBestEffortDeliveryTarget: (params: { + channel?: string; + to?: string; + accountId?: string; + threadId?: string; + }) => ({ + deliver: Boolean(params.channel && params.to), + channel: params.channel, + to: params.to, + accountId: params.accountId, + threadId: params.threadId, + }), + resolveQueueSettings: (params: { + cfg?: { + messages?: { + queue?: { + byChannel?: Record; + }; + }; + }; + channel?: string; + }) => ({ + mode: (params.channel && params.cfg?.messages?.queue?.byChannel?.[params.channel]) ?? "none", + }), +})); +vi.mock("./subagent-announce.runtime.js", () => ({ + callGateway: createGatewayCallModuleMock().callGateway, + loadConfig: () => configOverride, + ...createSessionsModuleMock(), + isEmbeddedPiRunActive: (sessionId: string) => isEmbeddedPiRunActiveMock(sessionId), + queueEmbeddedPiMessage: (_sessionId: string, _text: string) => false, + waitForEmbeddedPiRunEnd: (sessionId: string, timeoutMs?: number) => + waitForEmbeddedPiRunEndMock(sessionId, timeoutMs), +})); +vi.mock("./subagent-announce.registry.runtime.js", () => ({ + countActiveDescendantRuns: () => 0, + countPendingDescendantRuns: () => pendingDescendantRuns, + countPendingDescendantRunsExcludingRun: () => 0, + listSubagentRunsForRequester: () => [], + isSubagentSessionRunActive: () => subagentSessionRunActive, + shouldIgnorePostCompletionAnnounceForSession: () => shouldIgnorePostCompletion, + replaceSubagentRunAfterSteer: () => true, + resolveRequesterForChildSession: () => fallbackRequesterResolution, +})); import { runSubagentAnnounceFlow } from "./subagent-announce.js"; type AnnounceFlowParams = Parameters< typeof import("./subagent-announce.js").runSubagentAnnounceFlow diff --git a/src/agents/subagent-announce.ts b/src/agents/subagent-announce.ts index a074baa50f5..f0a41987ea2 100644 --- a/src/agents/subagent-announce.ts +++ b/src/agents/subagent-announce.ts @@ -1,7 +1,5 @@ import { isSilentReplyText, SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js"; import { DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH } from "../config/agent-limits.js"; -import { loadConfig } from "../config/config.js"; -import { callGateway } from "../gateway/call.js"; import { defaultRuntime } from "../runtime.js"; import { isCronSessionKey } from "../sessions/session-key-utils.js"; import { type DeliveryContext, normalizeDeliveryContext } from "../utils/delivery-context.js"; @@ -11,7 +9,6 @@ import { buildAnnounceIdempotencyKey, } from "./announce-idempotency.js"; import { formatAgentInternalEventsForPrompt, type AgentInternalEvent } from "./internal-events.js"; -import { isEmbeddedPiRunActive, waitForEmbeddedPiRunEnd } from "./pi-embedded.js"; import { deliverSubagentAnnouncement, loadRequesterSessionEntry, @@ -32,9 +29,15 @@ import { type SubagentRunOutcome, waitForSubagentRunOutcome, } from "./subagent-announce-output.js"; +import { + callGateway, + isEmbeddedPiRunActive, + loadConfig, + waitForEmbeddedPiRunEnd, +} from "./subagent-announce.runtime.js"; import { getSubagentDepthFromSessionStore } from "./subagent-depth.js"; import type { SpawnSubagentMode } from "./subagent-spawn.js"; -import { isAnnounceSkip } from "./tools/sessions-send-helpers.js"; +import { isAnnounceSkip } from "./tools/sessions-send-tokens.js"; type SubagentAnnounceDeps = { callGateway: typeof callGateway; @@ -49,11 +52,11 @@ const defaultSubagentAnnounceDeps: SubagentAnnounceDeps = { let subagentAnnounceDeps: SubagentAnnounceDeps = defaultSubagentAnnounceDeps; let subagentRegistryRuntimePromise: Promise< - typeof import("./subagent-registry-runtime.js") + typeof import("./subagent-announce.registry.runtime.js") > | null = null; function loadSubagentRegistryRuntime() { - subagentRegistryRuntimePromise ??= import("./subagent-registry-runtime.js"); + subagentRegistryRuntimePromise ??= import("./subagent-announce.registry.runtime.js"); return subagentRegistryRuntimePromise; } diff --git a/src/agents/tools/session-message-text.ts b/src/agents/tools/session-message-text.ts new file mode 100644 index 00000000000..f92211a49e7 --- /dev/null +++ b/src/agents/tools/session-message-text.ts @@ -0,0 +1,50 @@ +import { extractTextFromChatContent } from "../../shared/chat-content.js"; +import { sanitizeUserFacingText } from "../pi-embedded-helpers.js"; +import { + stripDowngradedToolCallText, + stripMinimaxToolCallXml, + stripModelSpecialTokens, + stripThinkingTagsFromText, +} from "../pi-embedded-utils.js"; + +export function stripToolMessages(messages: unknown[]): unknown[] { + return messages.filter((msg) => { + if (!msg || typeof msg !== "object") { + return true; + } + const role = (msg as { role?: unknown }).role; + return role !== "toolResult" && role !== "tool"; + }); +} + +export function sanitizeTextContent(text: string): string { + if (!text) { + return text; + } + return stripThinkingTagsFromText( + stripDowngradedToolCallText(stripModelSpecialTokens(stripMinimaxToolCallXml(text))), + ); +} + +export function extractAssistantText(message: unknown): string | undefined { + if (!message || typeof message !== "object") { + return undefined; + } + if ((message as { role?: unknown }).role !== "assistant") { + return undefined; + } + const content = (message as { content?: unknown }).content; + if (!Array.isArray(content)) { + return undefined; + } + const joined = + extractTextFromChatContent(content, { + sanitizeText: sanitizeTextContent, + joinWith: "", + normalizeText: (text) => text.trim(), + }) ?? ""; + const stopReason = (message as { stopReason?: unknown }).stopReason; + const errorContext = stopReason === "error"; + + return joined ? sanitizeUserFacingText(joined, { errorContext }) : undefined; +} diff --git a/src/agents/tools/sessions-send-helpers.ts b/src/agents/tools/sessions-send-helpers.ts index 66d8129ea35..062fd731a9b 100644 --- a/src/agents/tools/sessions-send-helpers.ts +++ b/src/agents/tools/sessions-send-helpers.ts @@ -5,9 +5,14 @@ import { import { resolveSessionConversationRef } from "../../channels/plugins/session-conversation.js"; import { normalizeChannelId as normalizeChatChannelId } from "../../channels/registry.js"; import type { OpenClawConfig } from "../../config/config.js"; +import { ANNOUNCE_SKIP_TOKEN, REPLY_SKIP_TOKEN } from "./sessions-send-tokens.js"; +export { + ANNOUNCE_SKIP_TOKEN, + REPLY_SKIP_TOKEN, + isAnnounceSkip, + isReplySkip, +} from "./sessions-send-tokens.js"; -const ANNOUNCE_SKIP_TOKEN = "ANNOUNCE_SKIP"; -const REPLY_SKIP_TOKEN = "REPLY_SKIP"; const DEFAULT_PING_PONG_TURNS = 5; const MAX_PING_PONG_TURNS = 5; @@ -115,14 +120,6 @@ export function buildAgentToAgentAnnounceContext(params: { return lines.join("\n"); } -export function isAnnounceSkip(text?: string) { - return (text ?? "").trim() === ANNOUNCE_SKIP_TOKEN; -} - -export function isReplySkip(text?: string) { - return (text ?? "").trim() === REPLY_SKIP_TOKEN; -} - export function resolvePingPongTurns(cfg?: OpenClawConfig) { const raw = cfg?.session?.agentToAgent?.maxPingPongTurns; const fallback = DEFAULT_PING_PONG_TURNS; diff --git a/src/agents/tools/sessions-send-tokens.ts b/src/agents/tools/sessions-send-tokens.ts new file mode 100644 index 00000000000..1c333bb8ede --- /dev/null +++ b/src/agents/tools/sessions-send-tokens.ts @@ -0,0 +1,10 @@ +export const ANNOUNCE_SKIP_TOKEN = "ANNOUNCE_SKIP"; +export const REPLY_SKIP_TOKEN = "REPLY_SKIP"; + +export function isAnnounceSkip(text?: string) { + return (text ?? "").trim() === ANNOUNCE_SKIP_TOKEN; +} + +export function isReplySkip(text?: string) { + return (text ?? "").trim() === REPLY_SKIP_TOKEN; +}