openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
390 lines (389 loc) • 17.8 kB
JavaScript
import { r as truncateUtf16Safe } from "./utf16-slice-D_ngcYKd.js";
import { m as redactToolDetail } from "./redact-BtvPPfTi.js";
import "./utils-P__uGsPB.js";
import "./session-key-BnWWjqNc.js";
import "./errors-Db3Ymjlb.js";
import { t as createSubsystemLogger } from "./subsystem-Dy2tqXOS.js";
import "./version-v1kuAkGj.js";
import "./agent-scope-DbtJyKUL.js";
import "./agent-events-CoxiItUi.js";
import { p as shouldLoadRequesterScopedMcpHarnessRuntime } from "./agent-bundle-mcp-manager-api-DCHQm4w1.js";
import { t as getGlobalHookRunner, v as joinPresentTextSegments } from "./hook-runner-global-0kfmMG4T.js";
import { l as listCodexAppServerExtensionFactories } from "./loader-DPiOPJjR.js";
import "./registry-B0bOFDjU.js";
import "./reply-payload-DahKk-7n.js";
import "./agent-tools.before-tool-call-Bb7DJuFB.js";
import "./provider-request-config-DIOYidiO.js";
import "./registry-D1_C7waJ.js";
import "./usage-CtmV8Xxq.js";
import "./user-turn-transcript.message-LcwHBB2I.js";
import "./model-auth-C48_DZ-I.js";
import { d as normalizeAgentRunAttemptTerminal, f as projectAgentRunAttemptTerminal, p as setAgentRunAttemptTerminalFailure, u as mergeAgentRunAttemptTerminal } from "./agent-run-terminal-outcome-CigeY75d.js";
import "./run-termination-jabvTOp5.js";
import "./diagnostic-ryAZMr5N.js";
import { _ as queueEmbeddedAgentMessageWithOutcome } from "./runs-Cb42qain.js";
import "./tool-metadata-B5aqo73s.js";
import "./agent-tool-metadata-CZvIgxro.js";
import "./active-run-projections-C4mdt8WG.js";
import "./tool-result-error-CbDLJzG-.js";
import "./gateway-CB9m4Gcq.js";
import "./tool-loop-detection-C39fRNx6.js";
import "./hook-helpers-3JS9XC0_.js";
import "./gateway-question-DoL5eagC.js";
import "./openclaw-tools-CNOZOjlX.js";
import { r as inferToolMetaFromArgsCore } from "./tool-display-CzOArp4x.js";
import "./tool-meta-DUrV7YlL.js";
import "./local-model-lean-B52ThaBJ.js";
import "./tool-schema-projection-a_T2Sr4Q.js";
import "./tool-replay-safety-CC9wuc1q.js";
import "./logger-C3TD2wdV.js";
import "./bootstrap-files-DbaSu-Uk.js";
import "./context-engine-lifecycle-Bkch2-qE.js";
import "./fs-paths-a-ImteWc.js";
import "./sandbox-A2KOznlu.js";
import "./nodes-utils-CL3pooh5.js";
import "./helpers-CkZ0XN7O.js";
import { _ as wrapPluginSystemContextSection } from "./attempt-prompt-helpers-Cmig-B3c.js";
import "./prepare-auth-Ci9igqt8.js";
import "./heartbeat-tool-response-B4VYc0rg.js";
import "./sessions-helpers-B2gzzr60.js";
import "./tools-CAIhAR2v.js";
import "./attempt-tool-construction-plan-CRC43c_k.js";
import "./embedded-agent-tool-media-_o_qAQ7H.js";
import "./tool-result-middleware-CKWUyjq4.js";
import "./embedded-agent-tool-results-ZMp1V0-a.js";
import "./embedded-agent-message-tool-source-reply-BNQPPjZe.js";
import "./hook-agent-context-kN_gMcDh.js";
import { s as buildAgentHookContext } from "./lifecycle-hook-helpers-Cpmpoz3T.js";
import "./agent-end-side-effects-M4dmThgX.js";
import "./settled-turn-finalization-result-CuiDqyLX.js";
import "./attempt-thread-helpers-BK4JQFTZ.js";
import "./date-time-C7YbYLih.js";
import { n as prepareWatchedSessionsPrompt, t as buildWatchedSessionsPromptLines } from "./watched-sessions-prompt-CPQUEGFd.js";
import "./execution-auth-binding-CmucNoqo.js";
import "./agent-scope-runtime-h57Nypqc.js";
import "./result-fallback-classifier-C3DQO8OC.js";
import "./build-DHcslHXI.js";
import "./native-hook-relay-y7mVheMp.js";
import { a as snapshotStructuredInput, i as isStructuredInputRecord, n as compileStructuredInputQuestions, o as runStructuredInput, r as compileStructuredInputUrl, t as compileStructuredInputForm } from "./structured-input-BvzwNGZ1.js";
//#region src/plugin-sdk/session-write-lock-runtime.ts
const DEFAULT_SESSION_WRITE_LOCK_ACQUIRE_TIMEOUT_MS = 6e4;
const DEFAULT_SESSION_WRITE_LOCK_STALE_MS = 18e5;
const DEFAULT_SESSION_WRITE_LOCK_MAX_HOLD_MS = 3e5;
/**
* @deprecated Session write leases were removed. This compatibility stub is scheduled for
* removal in the 2026.10 release train; use the session lane and durable writer claim/fence.
*/
function resolveSessionWriteLockAcquireTimeoutMs(_config, _env) {
return DEFAULT_SESSION_WRITE_LOCK_ACQUIRE_TIMEOUT_MS;
}
/**
* @deprecated Session write leases were removed. This compatibility stub is scheduled for
* removal in the 2026.10 release train; use the session lane and durable writer claim/fence.
*/
function resolveSessionWriteLockOptions(_config, _params = {}) {
return {
timeoutMs: DEFAULT_SESSION_WRITE_LOCK_ACQUIRE_TIMEOUT_MS,
staleMs: DEFAULT_SESSION_WRITE_LOCK_STALE_MS,
maxHoldMs: DEFAULT_SESSION_WRITE_LOCK_MAX_HOLD_MS
};
}
/**
* @deprecated Session write leases were removed. This no-op compatibility stub is scheduled
* for removal in the 2026.10 release train; use the session lane and durable writer claim/fence.
*/
async function acquireSessionWriteLock(_params) {
return {
assertOwned: () => void 0,
release: async () => void 0
};
}
//#endregion
//#region src/agents/harness/prompt-compaction-hook-helpers.ts
/**
* Agent harness prompt and compaction hook helpers.
*
* Harness runtimes use this to run plugin hooks around prompt construction and
* compaction while keeping hook failures non-fatal.
*/
const log$1 = createSubsystemLogger("agents/harness");
/** Runs before-prompt hooks and returns the adjusted prompt fields. */
async function resolveAgentHarnessBeforePromptBuildResult(params) {
const hookRunner = getGlobalHookRunner();
const hasHeartbeatContribution = params.ctx.trigger === "heartbeat" && Boolean(hookRunner?.hasHooks("heartbeat_prompt_contribution"));
const hasPromptBuildHooks = Boolean(hookRunner?.hasHooks("before_prompt_build"));
if (!hasHeartbeatContribution && !hasPromptBuildHooks) {
const developerInstructions = resolveDeveloperInstructions(params.developerInstructions);
return {
prompt: params.prompt,
developerInstructions,
promptInputRange: {
start: 0,
end: params.prompt.length
}
};
}
const hookCtx = buildAgentHookContext(params.ctx);
const promptEvent = {
prompt: params.prompt,
messages: params.messages
};
const heartbeatResult = hasHeartbeatContribution && hookRunner ? await hookRunner.runHeartbeatPromptContribution({
sessionKey: params.ctx.sessionKey,
agentId: params.ctx.agentId,
heartbeatName: "heartbeat"
}, hookCtx).catch((error) => {
log$1.warn(`heartbeat_prompt_contribution hook failed: ${String(error)}`);
}) : void 0;
const promptBuildResult = hookRunner && hasPromptBuildHooks ? await hookRunner.runBeforePromptBuild(promptEvent, hookCtx).catch((error) => {
log$1.warn(`before_prompt_build hook failed: ${String(error)}`);
}) : void 0;
const developerInstructions = resolveDeveloperInstructions(params.developerInstructions, promptBuildResult?.toolsAllow);
const toolAuthority = params.toolAuthority;
const toolAuthorityFingerprint = toolAuthority?.fingerprint?.trim();
const authorizedPromptBuildResult = hookRunner && toolAuthorityFingerprint && toolAuthority ? await hookRunner.runAuthorizedPromptBuild(promptEvent, hookCtx, {
toolAuthorityFingerprint,
activeToolNames: toolAuthority.activeToolNames(),
assertHostActive: toolAuthority.assertActive
}).catch((error) => {
log$1.warn(`authorized before_prompt_build hook failed: ${String(error)}`);
}) : void 0;
const systemPrompt = resolvePromptBuildSystemPrompt({
developerInstructions,
promptBuildResult
});
const promptPrefix = joinPresentTextSegments([
heartbeatResult?.prependContext,
promptBuildResult?.prependContext,
authorizedPromptBuildResult?.prependContext
]);
const promptSuffix = joinPresentTextSegments([
heartbeatResult?.appendContext,
promptBuildResult?.appendContext,
authorizedPromptBuildResult?.appendContext
]);
const prompt = joinPresentTextSegments([
promptPrefix,
params.prompt,
promptSuffix
]) ?? params.prompt;
const promptInputStart = params.prompt.length === 0 ? promptPrefix?.length ?? 0 : promptPrefix ? promptPrefix.length + 2 : 0;
return {
prompt,
...promptBuildResult?.toolsAllow !== void 0 ? { toolsAllow: promptBuildResult.toolsAllow } : {},
developerInstructions: joinPresentTextSegments([
wrapPluginSystemContextSection(promptBuildResult?.prependSystemContext),
systemPrompt,
wrapPluginSystemContextSection(promptBuildResult?.appendSystemContext)
]) ?? systemPrompt,
promptInputRange: {
start: promptInputStart,
end: promptInputStart + params.prompt.length
}
};
}
function resolveDeveloperInstructions(instructions, toolsAllow) {
return typeof instructions === "string" ? instructions : instructions.build({ toolsAllow }) ?? "";
}
function resolvePromptBuildSystemPrompt(params) {
if (typeof params.promptBuildResult?.systemPrompt === "string") return params.promptBuildResult.systemPrompt;
return params.developerInstructions;
}
/** Runs best-effort before-compaction hooks for a harness session. */
async function runAgentHarnessBeforeCompactionHook(params) {
const hookRunner = getGlobalHookRunner();
if (!hookRunner?.hasHooks("before_compaction")) return;
try {
await hookRunner.runBeforeCompaction({
messageCount: params.messages?.length ?? -1,
...params.messages ? { messages: params.messages } : {},
sessionFile: params.sessionFile
}, buildAgentHookContext(params.ctx));
} catch (error) {
log$1.warn(`before_compaction hook failed: ${String(error)}`);
}
}
/** Runs best-effort after-compaction hooks for a harness session. */
async function runAgentHarnessAfterCompactionHook(params) {
const hookRunner = getGlobalHookRunner();
if (!hookRunner?.hasHooks("after_compaction")) return;
try {
await hookRunner.runAfterCompaction({
messageCount: params.messages?.length ?? -1,
compactedCount: params.compactedCount,
sessionFile: params.sessionFile
}, buildAgentHookContext(params.ctx));
} catch (error) {
log$1.warn(`after_compaction hook failed: ${String(error)}`);
}
}
//#endregion
//#region src/agents/harness/codex-app-server-extensions.ts
/**
* Codex app-server extension runner.
*
* Harness integration uses this to let registered extensions observe and adjust
* tool results before they are returned to the agent runtime.
*/
const log = createSubsystemLogger("agents/harness");
/** Creates a runner that applies registered Codex app-server tool-result extensions. */
function createCodexAppServerToolResultExtensionRunner(ctx, factories = listCodexAppServerExtensionFactories()) {
const handlers = [];
const runtime = { on(event, handler) {
if (event === "tool_result") handlers.push(handler);
} };
const initPromise = (async () => {
for (const factory of factories) await factory(runtime);
})();
return { async applyToolResultExtensions(event) {
await initPromise;
let current = event.result;
for (const handler of handlers) try {
const next = await handler({
...event,
result: current
}, ctx);
if (next?.result) current = next.result;
} catch (error) {
const detail = error instanceof Error ? error.message : String(error);
log.warn(`[codex] tool_result extension failed for ${event.toolName}: ${detail}`);
}
return current;
} };
}
//#endregion
//#region src/plugin-sdk/agent-harness-runtime.ts
/** Default truncation limit for user-facing tool progress output. */
const TOOL_PROGRESS_OUTPUT_MAX_CHARS = 8e3;
/**
* Renders the Watched Sessions prompt block for plugin-owned harness prompts.
* Harness runtimes that assemble their own instruction layers (e.g. Codex)
* must surface the same watched-session facts as the embedded prompt, or the
* model keeps refusing cross-session questions on those runtimes (openclaw#114797).
*/
function buildWatchedSessionsHarnessContext(params) {
const lines = buildWatchedSessionsPromptLines(prepareWatchedSessionsPrompt({
enabled: true,
...params
}));
return lines.length > 0 ? lines.join("\n").trimEnd() : void 0;
}
const agentHarnessAttemptTerminal = {
merge: mergeAgentRunAttemptTerminal,
normalize: normalizeAgentRunAttemptTerminal,
project: projectAgentRunAttemptTerminal,
setFailure: setAgentRunAttemptTerminalFailure
};
/** Bounded structured-input compilation and execution for native agent harnesses. */
const agentHarnessStructuredInput = Object.freeze({
compileForm: compileStructuredInputForm,
compileQuestions: compileStructuredInputQuestions,
compileUrl: compileStructuredInputUrl,
isRecord: isStructuredInputRecord,
run: runStructuredInput,
snapshot: snapshotStructuredInput
});
/**
* @deprecated Active-run queueing is an internal runtime concern. This legacy
* boolean API only reports immediate queue eligibility and cannot observe async
* runtime rejection; runtime-owned delivery paths should use acceptance-aware
* steering instead of public SDK queueing.
*/
function queueAgentHarnessMessage(sessionId, text, options) {
return queueEmbeddedAgentMessageWithOutcome(sessionId, text, options).queued;
}
/** Detect prompt image references and load them through the same limits used by embedded runs. */
async function detectAndLoadAgentHarnessPromptImages(params) {
const [{ resolveImageSanitizationLimits }, { detectAndLoadPromptImages }, { MAX_IMAGE_BYTES }] = await Promise.all([
import("./image-sanitization-CGRMun8e.js"),
import("./images-BRcYcBdD.js"),
import("./media-core/constants.js")
]);
return detectAndLoadPromptImages({
prompt: params.prompt,
workspaceDir: params.workspaceDir,
model: params.model,
existingImages: params.existingImages,
imageOrder: params.imageOrder,
media: params.media,
userTurnTranscriptRecorder: params.userTurnTranscriptRecorder,
maxBytes: MAX_IMAGE_BYTES,
maxDimensionPx: resolveImageSanitizationLimits(params.config).maxDimensionPx,
workspaceOnly: params.workspaceOnly,
localRoots: params.localRoots,
sandbox: params.sandbox
});
}
/** Load Codex bundle MCP thread config without forcing the heavy config module into SDK imports. */
async function loadCodexBundleMcpThreadConfig(params) {
const { loadCodexBundleMcpThreadConfigCore: load } = await import("./codex-mcp-config-DokUDtnF.js");
return load(params);
}
/**
* Materialize an MCP App view for a tool executed by a harness-native MCP client.
* The harness supplies a runtime adapter so the view keeps using that exact connection.
*/
async function prepareHarnessNativeMcpAppPreview(params) {
if (params.runtime.mcpAppsEnabled !== true) return;
const { buildMcpAppCanvasPayload, fetchMcpAppView } = await import("./mcp-ui-resource-D3Owfqjc.js");
const view = await fetchMcpAppView({
runtime: params.runtime,
agentId: params.agentId,
serverName: params.serverName,
toolName: params.toolName,
uiResourceUri: params.uiResourceUri,
toolCallId: params.toolCallId,
toolInput: params.toolInput,
toolResult: params.toolResult,
allowedAppToolNames: params.allowedAppToolNames
});
if (!view) return;
return { mcpAppPreview: buildMcpAppCanvasPayload({
...view,
...params.runtime.sessionKey ? { originSessionKey: params.runtime.sessionKey } : {},
...params.resultMetaState ? { resultMetaState: params.resultMetaState } : {}
}) };
}
/**
* Materialize requester-scoped MCP tools for a harness run (dynamic tools, not
* harness-native MCP config). Lazy-loaded so harness plugins avoid the MCP manager graph.
*/
async function materializeRequesterScopedMcpToolsForHarnessRun(params) {
if (!shouldLoadRequesterScopedMcpHarnessRuntime(params)) return;
const { materializeRequesterScopedMcpToolsForHarnessRunCore: materialize } = await import("./agent-bundle-mcp-harness-C295I9Pj.js");
return materialize(params);
}
/** Infer compact display metadata for one tool invocation from its name and arguments. */
function inferToolMetaFromArgs(toolName, args, options) {
return inferToolMetaFromArgsCore(toolName, args, options);
}
/**
* Prepare verbose tool output for user-facing progress messages.
*/
function formatToolProgressOutput(output, options) {
const trimmed = output.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trim();
if (!trimmed) return;
const redacted = redactToolDetail(trimmed);
const maxChars = options?.maxChars ?? 8e3;
if (redacted.length <= maxChars) return redacted;
return `${truncateUtf16Safe(redacted, maxChars)}\n...(truncated)...`;
}
/**
* Classify terminal harness turns that completed without assistant output that
* should advance fallback. Deliberate silent replies such as NO_REPLY count as
* intentional output, while whitespace-only text remains fallback-eligible.
* This is intentionally SDK-level so plugin harness adapters such as Codex
* preserve the same OpenClaw-owned fallback signals as the built-in OpenClaw path
* without re-implementing terminal-result policy.
*/
function classifyAgentHarnessTerminalOutcome(params) {
if (!params.turnCompleted || params.promptError !== void 0 && params.promptError !== null || hasVisibleAssistantText(params.assistantTexts)) return;
if (params.planText?.trim()) return "planning-only";
if (params.reasoningText?.trim()) return "reasoning-only";
return "empty";
}
function hasVisibleAssistantText(assistantTexts) {
return assistantTexts.some((text) => text.trim().length > 0);
}
//#endregion
export { acquireSessionWriteLock as _, classifyAgentHarnessTerminalOutcome as a, inferToolMetaFromArgs as c, prepareHarnessNativeMcpAppPreview as d, queueAgentHarnessMessage as f, runAgentHarnessBeforeCompactionHook as g, runAgentHarnessAfterCompactionHook as h, buildWatchedSessionsHarnessContext as i, loadCodexBundleMcpThreadConfig as l, resolveAgentHarnessBeforePromptBuildResult as m, agentHarnessAttemptTerminal as n, detectAndLoadAgentHarnessPromptImages as o, createCodexAppServerToolResultExtensionRunner as p, agentHarnessStructuredInput as r, formatToolProgressOutput as s, TOOL_PROGRESS_OUTPUT_MAX_CHARS as t, materializeRequesterScopedMcpToolsForHarnessRun as u, resolveSessionWriteLockAcquireTimeoutMs as v, resolveSessionWriteLockOptions as y };