openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
115 lines (114 loc) • 5.63 kB
JavaScript
import { t as formatErrorMessage } from "./errors-BvOkmQM5.mjs";
import { t as createSubsystemLogger } from "./subsystem-4NzR43uz.mjs";
import { w as runWithGatewayDetachedWorkContinuation } from "./gateway-work-admission-DAV5kkgV.mjs";
import { a as execRequestAbortSignal, l as withExecRequestOwners, u as withExecRequestTurn } from "./exec-request-context-u4rNuPjF.mjs";
import { r as runOutsidePreparedModelRuntimePluginGenerationScope } from "./prepared-model-runtime-generation-scope-Ck1wk1tN.mjs";
import { n as ToolInputError } from "./tool-input-error-mjW74R8m.mjs";
import { t as GatewayClientRequestError } from "./request-error-DgMXHa-w.mjs";
import { o as getGatewayToolCallerIdentity } from "./gateway-caller-context-CU8n6n_e.mjs";
import { t as jsonResult } from "./tool-results-BCM3fdVS.mjs";
import "./common-BkU19q6Q.mjs";
import { o as prepareSessionEventTargetForHost, r as captureSessionEventTargetForHost, t as enqueueSessionEventForHost } from "./session-event-handoff-BkyE9Uzx.mjs";
import { R as resolveReplyRunForCurrentSessionId } from "./reply-run-registry.state-BgHFgrrj.mjs";
import "./reply-run-registry-1HN3_KMU.mjs";
import { n as getAgentToolExecutionContext } from "./tool-execution-context-BwYF5HLu.mjs";
import { o as captureOperatorToolGatewayContinuationContext } from "./server-plugin-in-process-dispatch-CHKjkAiH.mjs";
import { n as callAgentToolGatewayRequest } from "./in-process-gateway-BYRZzLBf.mjs";
import { randomUUID } from "node:crypto";
//#region src/agents/tools/plugins-reload-handoff.ts
const log = createSubsystemLogger("plugins/reload-handoff");
const pending = /* @__PURE__ */ new WeakSet();
/** The reply owner releases the turn; the ordinary reload owner still drains physical leases. */
async function handoffPluginReload(params) {
if (getAgentToolExecutionContext()?.hasUnobservedAsyncToolResults) return jsonResult({
status: "deferred",
message: "Read earlier async results before handing off the reload."
});
const caller = getGatewayToolCallerIdentity();
const operation = params.sessionId ? resolveReplyRunForCurrentSessionId(params.sessionId) : void 0;
if (!caller || !params.onYield || !operation?.ownerSettlement) throw new ToolInputError("reloadAndResume requires an active Gateway conversation with turn yielding.");
if (pending.has(operation)) throw new ToolInputError("This turn already handed off a plugin reload.");
pending.add(operation);
let continuation = void 0;
try {
continuation = await captureOperatorToolGatewayContinuationContext({
agentId: caller.agentId,
sessionKey: caller.sessionKey
});
if (!continuation) throw new ToolInputError("reloadAndResume requires its admitted Gateway.");
const target = await captureSessionEventTargetForHost(caller.agentId, caller.sessionKey);
if (target.sessionId !== params.sessionId) throw new ToolInputError("The reload requester session changed before handoff.");
continuation.assertCurrent();
operation.abortSignal.throwIfAborted();
params.signal?.throwIfAborted();
await params.onYield("Plugin reload handed off; resume with its result in this same conversation.");
const retained = continuation;
runOutsidePreparedModelRuntimePluginGenerationScope(() => runWithGatewayDetachedWorkContinuation(() => withExecRequestTurn({
identity: {
runId: params.runId,
sessionId: params.sessionId,
sessionKey: caller.sessionKey,
agentId: caller.agentId
},
owners: params.requestOwners
}, async () => {
const signal = execRequestAbortSignal(params.requestOwners, operation.abortSignal) ?? operation.abortSignal;
try {
await operation.ownerSettlement;
if (signal.aborted) return;
let result;
try {
const destination = await prepareSessionEventTargetForHost(target);
try {
result = await retained.run(() => callAgentToolGatewayRequest({
method: "plugins.reload",
params: params.request,
sessionMutationCommitGuard: destination.assertCurrent,
signal: AbortSignal.any([retained.signal, signal]),
timeoutMs: null
}));
} finally {
destination.release();
}
} catch (error) {
result = {
ok: false,
error: formatErrorMessage(error),
...error instanceof GatewayClientRequestError ? {
code: error.gatewayCode,
details: error.details
} : {}
};
}
if (signal.aborted) return;
const receipt = enqueueSessionEventForHost("Plugin reload result: " + params.formatResult(result) + "\nContinue the original task in this conversation. Do not repeat a completed reload.", withExecRequestOwners({
agentId: caller.agentId,
sessionKey: caller.sessionKey,
source: "plugin",
contextKey: "plugin-reload:" + randomUUID(),
expectedTarget: target,
assertCurrent: retained.assertCurrent,
abortSignal: signal
}, params.requestOwners));
const accepted = await receipt.accepted;
if (!accepted.ok) throw new Error(accepted.error);
const outcome = await receipt.settled;
if (outcome.status === "failed") throw new Error(outcome.error ?? "Plugin reload resume failed");
} finally {
retained.release();
}
}), "plugins:reload-handoff")).catch((error) => log.error("Plugin reload handoff failed: " + formatErrorMessage(error))).finally(() => retained.release());
return jsonResult({
status: "started",
async: true,
yielded: true,
message: "Reload will run after turn cleanup; its result will resume this session."
});
} catch (error) {
pending.delete(operation);
continuation?.release();
throw error;
}
}
//#endregion
export { handoffPluginReload };