From 42d6e35cb45f753fc2f4f3b4050cb42e2f3eb7a7 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 14 Mar 2026 01:36:13 +0000 Subject: [PATCH] refactor: share session tool context setup --- src/agents/tools/sessions-helpers.ts | 18 ++++ src/agents/tools/sessions-send-tool.ts | 109 +++++++++++++------------ 2 files changed, 75 insertions(+), 52 deletions(-) diff --git a/src/agents/tools/sessions-helpers.ts b/src/agents/tools/sessions-helpers.ts index e638438758c..74393ef44ad 100644 --- a/src/agents/tools/sessions-helpers.ts +++ b/src/agents/tools/sessions-helpers.ts @@ -12,6 +12,7 @@ export { resolveSandboxedSessionToolContext, resolveSessionToolsVisibility, } from "./sessions-access.js"; +import { resolveSandboxedSessionToolContext } from "./sessions-access.js"; export type { SessionReferenceResolution } from "./sessions-resolution.js"; export { isRequesterSpawnedSessionVisible, @@ -27,6 +28,7 @@ export { shouldResolveSessionIdInput, shouldVerifyRequesterSpawnedSessionVisibility, } from "./sessions-resolution.js"; +import { type OpenClawConfig, loadConfig } from "../../config/config.js"; import { extractTextFromChatContent } from "../../shared/chat-content.js"; import { sanitizeUserFacingText } from "../pi-embedded-helpers.js"; import { @@ -73,6 +75,22 @@ function normalizeKey(value?: string) { return trimmed ? trimmed : undefined; } +export function resolveSessionToolContext(opts?: { + agentSessionKey?: string; + sandboxed?: boolean; + config?: OpenClawConfig; +}) { + const cfg = opts?.config ?? loadConfig(); + return { + cfg, + ...resolveSandboxedSessionToolContext({ + cfg, + agentSessionKey: opts?.agentSessionKey, + sandboxed: opts?.sandboxed, + }), + }; +} + export function classifySessionKind(params: { key: string; gatewayKind?: string | null; diff --git a/src/agents/tools/sessions-send-tool.ts b/src/agents/tools/sessions-send-tool.ts index d9ad6e6b907..b2873e5cd1f 100644 --- a/src/agents/tools/sessions-send-tool.ts +++ b/src/agents/tools/sessions-send-tool.ts @@ -1,6 +1,6 @@ import crypto from "node:crypto"; import { Type } from "@sinclair/typebox"; -import { type OpenClawConfig, loadConfig } from "../../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { callGateway } from "../../gateway/call.js"; import { normalizeAgentId, resolveAgentIdFromSessionKey } from "../../routing/session-key.js"; import { SESSION_LABEL_MAX_LENGTH } from "../../sessions/session-label.js"; @@ -17,7 +17,7 @@ import { extractAssistantText, resolveEffectiveSessionToolsVisibility, resolveSessionReference, - resolveSandboxedSessionToolContext, + resolveSessionToolContext, resolveVisibleSessionReference, stripToolMessages, } from "./sessions-helpers.js"; @@ -32,6 +32,36 @@ const SessionsSendToolSchema = Type.Object({ timeoutSeconds: Type.Optional(Type.Number({ minimum: 0 })), }); +async function startAgentRun(params: { + runId: string; + sendParams: Record; + sessionKey: string; +}): Promise<{ ok: true; runId: string } | { ok: false; result: ReturnType }> { + try { + const response = await callGateway<{ runId: string }>({ + method: "agent", + params: params.sendParams, + timeoutMs: 10_000, + }); + return { + ok: true, + runId: typeof response?.runId === "string" && response.runId ? response.runId : params.runId, + }; + } catch (err) { + const messageText = + err instanceof Error ? err.message : typeof err === "string" ? err : "error"; + return { + ok: false, + result: jsonResult({ + runId: params.runId, + status: "error", + error: messageText, + sessionKey: params.sessionKey, + }), + }; + } +} + export function createSessionsSendTool(opts?: { agentSessionKey?: string; agentChannel?: GatewayMessageChannel; @@ -47,13 +77,8 @@ export function createSessionsSendTool(opts?: { execute: async (_toolCallId, args) => { const params = args as Record; const message = readStringParam(params, "message", { required: true }); - const cfg = opts?.config ?? loadConfig(); - const { mainKey, alias, effectiveRequesterKey, restrictToSpawned } = - resolveSandboxedSessionToolContext({ - cfg, - agentSessionKey: opts?.agentSessionKey, - sandboxed: opts?.sandboxed, - }); + const { cfg, mainKey, alias, effectiveRequesterKey, restrictToSpawned } = + resolveSessionToolContext(opts); const a2aPolicy = createAgentToAgentPolicy(cfg); const sessionVisibility = resolveEffectiveSessionToolsVisibility({ @@ -252,54 +277,34 @@ export function createSessionsSendTool(opts?: { }; if (timeoutSeconds === 0) { - try { - const response = await callGateway<{ runId: string }>({ - method: "agent", - params: sendParams, - timeoutMs: 10_000, - }); - if (typeof response?.runId === "string" && response.runId) { - runId = response.runId; - } - startA2AFlow(undefined, runId); - return jsonResult({ - runId, - status: "accepted", - sessionKey: displayKey, - delivery, - }); - } catch (err) { - const messageText = - err instanceof Error ? err.message : typeof err === "string" ? err : "error"; - return jsonResult({ - runId, - status: "error", - error: messageText, - sessionKey: displayKey, - }); - } - } - - try { - const response = await callGateway<{ runId: string }>({ - method: "agent", - params: sendParams, - timeoutMs: 10_000, - }); - if (typeof response?.runId === "string" && response.runId) { - runId = response.runId; - } - } catch (err) { - const messageText = - err instanceof Error ? err.message : typeof err === "string" ? err : "error"; - return jsonResult({ + const start = await startAgentRun({ runId, - status: "error", - error: messageText, + sendParams, sessionKey: displayKey, }); + if (!start.ok) { + return start.result; + } + runId = start.runId; + startA2AFlow(undefined, runId); + return jsonResult({ + runId, + status: "accepted", + sessionKey: displayKey, + delivery, + }); } + const start = await startAgentRun({ + runId, + sendParams, + sessionKey: displayKey, + }); + if (!start.ok) { + return start.result; + } + runId = start.runId; + let waitStatus: string | undefined; let waitError: string | undefined; try {