UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

149 lines (148 loc) 8.12 kB
import "./src-vebZIeLe.js"; import { c as isRecord } from "./record-coerce-DItp3I4t.js"; import { t as stableStringify } from "./stable-stringify-C8X7niaI.js"; import { o as isToolExecutionAllowed } from "./tool-policy-shared-DIyS0iQC.js"; import { f as emitSessionLifecycleEvent } from "./session-history-eviction-C4srftLJ.js"; import { n as ToolInputError } from "./tool-input-error-mjW74R8m.js"; import "./common-Bm6UTDDA.js"; import { o as runAgentToolSourceExecutionGuard, r as captureAgentToolSourceExecutionGuard } from "./agent-tool-source-execution-guard-C6m-5OB2.js"; import { i as isCollectorSpawnTool, o as runWithJoinedCollectorSpawn } from "./swarm-collector-capability-CNerMvSC.js"; import { m as resolveMainSessionAlias, p as resolveInternalSessionKey } from "./sessions-helpers-B2gzzr60.js"; import { d as getSwarmRunByLaunchReplayKey, f as initSubagentRegistry } from "./subagent-registry-BMJDw92y.js"; import { t as resolveSwarmConfig } from "./swarm-config-XTe8M2h4.js"; import { n as waitForCollectorCompletion } from "./agents-wait-tool-DdzY5vKN.js"; import { n as SWARM_CODE_MODE_REQUEST_FINGERPRINT, t as SWARM_CODE_MODE_IDEMPOTENCY_KEY } from "./swarm-code-mode-DXtHU4JN.js"; import { createHash } from "node:crypto"; //#region src/agents/code-mode-swarm.runtime.ts function resolveCodeModeRequesterSessionKey(ctx) { const sessionKey = ctx.sessionKey?.trim(); if (!sessionKey) throw new ToolInputError("code mode swarm globals require session and run identity."); const { mainKey, alias } = resolveMainSessionAlias(ctx.runtimeConfig ?? ctx.config ?? {}); return resolveInternalSessionKey({ key: sessionKey, alias, mainKey }); } function resolveCodeModeSwarmGroupId(ctx) { const sessionKey = resolveCodeModeRequesterSessionKey(ctx); const runId = ctx.runId?.trim(); if (!runId) throw new ToolInputError("code mode swarm globals require session and run identity."); return `swarm:${sessionKey}:${runId}`; } function replayedSpawnResult(entry) { return { status: "accepted", runId: entry.swarmRunId ?? entry.runId, sessionKey: entry.childSessionKey, ...entry.label ? { label: entry.label } : {} }; } function readOptionalStringOption(options, key) { const value = options[key]; if (value === void 0) return; if (typeof value !== "string" || !value.trim()) throw new ToolInputError(`agents.run ${key} must be a non-empty string.`); return value.trim(); } async function runAgentSpawnBridge(params) { const prompt = params.request.args[0]; const options = isRecord(params.request.args[1]) ? params.request.args[1] : {}; if (typeof prompt !== "string" || !prompt.trim()) throw new ToolInputError("agents.run prompt must be a non-empty string."); const fastMode = options.fastMode; if (fastMode !== void 0 && fastMode !== true && fastMode !== false && fastMode !== "auto") throw new ToolInputError("agents.run fastMode must be boolean or \"auto\"."); const schema = options.schema; if (schema !== void 0 && !isRecord(schema)) throw new ToolInputError("agents.run schema must be a JSON schema object."); const label = readOptionalStringOption(options, "label"); const model = readOptionalStringOption(options, "model"); const thinking = readOptionalStringOption(options, "thinking"); const agentId = readOptionalStringOption(options, "agentId"); const catalog = params.ctx.catalogRef?.current; const spawnEntry = catalog?.entries.find((entry) => entry.name === "sessions_spawn" && isCollectorSpawnTool(entry.tool)); if (!catalog || !spawnEntry || !isCollectorSpawnTool(spawnEntry.tool)) throw new ToolInputError("agents.run requires the native sessions_spawn tool."); const spawnTool = spawnEntry.tool; const assertSourceActive = captureAgentToolSourceExecutionGuard(params.signal); const assertCurrent = () => { assertSourceActive(); params.ctx.abortSignal?.throwIfAborted(); if (params.ctx.catalogRef?.current !== catalog || !catalog.entries.includes(spawnEntry) || !resolveSwarmConfig(params.ctx.runtimeConfig ?? params.ctx.config, params.ctx.agentId).enabled || params.ctx.toolExecutionAllow && !isToolExecutionAllowed(params.ctx.toolExecutionAllow, "sessions_spawn")) throw new ToolInputError("Joined collector spawn catalog is no longer active."); runAgentToolSourceExecutionGuard(spawnTool); }; assertCurrent(); const spawnInput = { task: prompt.trim(), collect: true, groupId: resolveCodeModeSwarmGroupId(params.ctx), ...label ? { label } : {}, ...model ? { model } : {}, ...thinking ? { thinking } : {}, ...agentId ? { agentId } : {}, ...fastMode !== void 0 ? { fastMode } : {}, ...schema ? { outputSchema: schema } : {} }; const requestFingerprint = `sha256:${createHash("sha256").update(stableStringify(spawnInput)).digest("hex")}`; const idempotencyKey = `${params.codeModeRunId}:${params.request.id}`; const requesterSessionKey = resolveCodeModeRequesterSessionKey(params.ctx); let existing = getSwarmRunByLaunchReplayKey(idempotencyKey, requesterSessionKey, params.ctx.agentId); if (existing) { if (existing.swarmLaunchRequestFingerprint !== requestFingerprint) throw new ToolInputError("agents.run replay request does not match the persisted collector."); if (existing.swarmLaunchPending === true) { if (!existing.queuedLaunch) throw new ToolInputError("agents.run persisted launch reservation cannot be recovered."); initSubagentRegistry(); existing = getSwarmRunByLaunchReplayKey(idempotencyKey, requesterSessionKey, params.ctx.agentId) ?? existing; if (existing.swarmLaunchPending === true && !existing.queuedLaunch) throw new ToolInputError("agents.run persisted launch reservation cannot be recovered."); } assertCurrent(); return replayedSpawnResult(existing); } Object.defineProperty(spawnInput, SWARM_CODE_MODE_IDEMPOTENCY_KEY, { value: idempotencyKey }); Object.defineProperty(spawnInput, SWARM_CODE_MODE_REQUEST_FINGERPRINT, { value: requestFingerprint }); const called = await runWithJoinedCollectorSpawn(spawnEntry.tool, assertCurrent, () => params.runtime.callExactId(spawnEntry.id, spawnInput, { parentToolCallId: params.parentToolCallId, signal: params.signal, onUpdate: params.onUpdate })); assertCurrent(); const value = isRecord(called.result) && "details" in called.result ? called.result.details : called.result; if (!isRecord(value) || value.status !== "accepted" || typeof value.runId !== "string") { const detail = isRecord(value) && typeof value.error === "string" ? value.error : "collector spawn was not accepted"; throw new ToolInputError(`agents.run spawn failed: ${detail}`); } return value; } async function runAgentWaitBridge(params) { const runId = params.request.args[0]; if (typeof runId !== "string" || !runId.trim()) throw new ToolInputError("agentWait run id must be a non-empty string."); const rawSessionKey = params.ctx.sessionKey?.trim(); if (!rawSessionKey) throw new ToolInputError("agents.run wait requires session identity."); const requesterSessionKey = resolveCodeModeRequesterSessionKey(params.ctx); return await waitForCollectorCompletion({ runId: runId.trim(), currentSessionKeys: /* @__PURE__ */ new Set([rawSessionKey, requesterSessionKey]), currentAgentId: params.ctx.agentId, config: params.ctx.runtimeConfig ?? params.ctx.config, signal: params.signal }); } function runSwarmNoteBridge(params) { const note = isRecord(params.request.args[0]) ? params.request.args[0] : void 0; const kind = note?.kind; const text = note?.text; if (kind !== "phase" && kind !== "log" || typeof text !== "string" || !text.trim()) throw new ToolInputError("swarmNote requires phase/log kind and non-empty text."); const sessionKey = params.ctx.sessionKey?.trim(); if (!sessionKey) throw new ToolInputError("swarmNote requires session identity."); emitSessionLifecycleEvent({ sessionKey, reason: "swarm-note", swarmGroupId: resolveCodeModeSwarmGroupId(params.ctx), kind, text: text.trim() }); return { ok: true }; } const codeModeSwarmHandlers = { agentSpawn: runAgentSpawnBridge, agentWait: runAgentWaitBridge, swarmNote: runSwarmNoteBridge }; //#endregion export { codeModeSwarmHandlers };