openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
346 lines (345 loc) • 12.6 kB
JavaScript
import { c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js";
import { i as formatErrorMessage } from "./errors-BXgSefBE.js";
import { a as isSubagentSessionKey, n as isAcpSessionKey } from "./session-key-utils-Bx3apsJ3.js";
import { d as normalizeMainKey } from "./session-key-B_NoIfpX.js";
import { i as getRuntimeConfig } from "./io-Gi7-pyU-.js";
import "./config-C9RxTsn1.js";
import { n as GATEWAY_CLIENT_IDS, o as normalizeGatewayClientId } from "./client-info-CcqJJIan.js";
import { o as callGateway } from "./call-B5-GYOlf.js";
import { a as listSpawnedSessionKeys, s as resolveSandboxSessionToolsVisibility } from "./session-visibility-HcnRYqQk.js";
import "./chat-history-text-D43w1rZt.js";
//#region src/sessions/session-id.ts
const SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
function looksLikeSessionId(value) {
return SESSION_ID_RE.test(value.trim());
}
//#endregion
//#region src/agents/tools/sessions-resolution.ts
/**
* Session key resolution helpers.
*
* Normalizes display/internal/current-session aliases and resolves session-id inputs through Gateway.
*/
const defaultSessionsResolutionDeps = { callGateway };
const CURRENT_SESSION_CLIENT_ALIAS_IDS = new Set([
GATEWAY_CLIENT_IDS.TUI,
GATEWAY_CLIENT_IDS.CLI,
GATEWAY_CLIENT_IDS.WEBCHAT_UI,
GATEWAY_CLIENT_IDS.CONTROL_UI,
GATEWAY_CLIENT_IDS.MACOS_APP,
GATEWAY_CLIENT_IDS.IOS_APP,
GATEWAY_CLIENT_IDS.ANDROID_APP
]);
let sessionsResolutionDeps = defaultSessionsResolutionDeps;
function resolveMainSessionAlias(cfg) {
const mainKey = normalizeMainKey(cfg.session?.mainKey);
const scope = cfg.session?.scope ?? "per-sender";
return {
mainKey,
alias: scope === "global" ? "global" : mainKey,
scope
};
}
function resolveDisplaySessionKey(params) {
if (params.key === params.alias) return "main";
if (params.key === params.mainKey) return "main";
return params.key;
}
function resolveInternalSessionKey(params) {
if (params.key === "current") return params.requesterInternalKey ?? params.key;
if (params.key === "main") return params.alias;
return params.key;
}
function resolveCurrentSessionClientAlias(params) {
const requesterKey = normalizeOptionalString(params.requesterInternalKey);
if (!requesterKey) return;
const clientId = normalizeGatewayClientId(params.key);
if (!clientId || !CURRENT_SESSION_CLIENT_ALIAS_IDS.has(clientId)) return;
return requesterKey;
}
async function isRequesterSpawnedSessionVisible(params) {
if (params.requesterSessionKey === params.targetSessionKey) return true;
try {
const resolved = await sessionsResolutionDeps.callGateway({
method: "sessions.resolve",
params: {
key: params.targetSessionKey,
spawnedBy: params.requesterSessionKey
}
});
if (typeof resolved?.key === "string" && resolved.key.trim() === params.targetSessionKey) return true;
} catch {}
return (await listSpawnedSessionKeys({
requesterSessionKey: params.requesterSessionKey,
limit: params.limit
})).has(params.targetSessionKey);
}
function shouldVerifyRequesterSpawnedSessionVisibility(params) {
return params.restrictToSpawned && !params.resolvedViaSessionId && params.requesterSessionKey !== params.targetSessionKey;
}
async function isResolvedSessionVisibleToRequester(params) {
if (!shouldVerifyRequesterSpawnedSessionVisibility({
requesterSessionKey: params.requesterSessionKey,
targetSessionKey: params.targetSessionKey,
restrictToSpawned: params.restrictToSpawned,
resolvedViaSessionId: params.resolvedViaSessionId
})) return true;
return await isRequesterSpawnedSessionVisible({
requesterSessionKey: params.requesterSessionKey,
targetSessionKey: params.targetSessionKey,
limit: params.limit
});
}
function looksLikeSessionKey(value) {
const raw = normalizeOptionalString(value) ?? "";
if (!raw) return false;
if (raw === "main" || raw === "global" || raw === "unknown" || raw === "current") return true;
if (isAcpSessionKey(raw)) return true;
if (raw.startsWith("agent:")) return true;
if (raw.startsWith("cron:") || raw.startsWith("hook:")) return true;
if (raw.startsWith("node-") || raw.startsWith("node:")) return true;
if (raw.includes(":group:") || raw.includes(":channel:")) return true;
return false;
}
function shouldResolveSessionIdInput(value) {
return looksLikeSessionId(value) || !looksLikeSessionKey(value);
}
function buildResolvedSessionReference(params) {
return {
ok: true,
key: params.key,
displayKey: resolveDisplaySessionKey({
key: params.key,
alias: params.alias,
mainKey: params.mainKey
}),
resolvedViaSessionId: params.resolvedViaSessionId
};
}
function buildSessionIdResolveParams(params) {
return {
sessionId: params.sessionId,
spawnedBy: params.restrictToSpawned ? params.requesterInternalKey : void 0,
includeGlobal: !params.restrictToSpawned,
includeUnknown: !params.restrictToSpawned
};
}
async function callGatewayResolveSessionId(params) {
const key = normalizeOptionalString((await sessionsResolutionDeps.callGateway({
method: "sessions.resolve",
params: buildSessionIdResolveParams(params)
}))?.key) ?? "";
if (!key) throw new Error(`Session not found: ${params.sessionId} (use the full sessionKey from sessions_list)`);
return key;
}
async function resolveSessionKeyFromSessionId(params) {
try {
return buildResolvedSessionReference({
key: await callGatewayResolveSessionId(params),
alias: params.alias,
mainKey: params.mainKey,
resolvedViaSessionId: true
});
} catch (err) {
if (params.restrictToSpawned) return {
ok: false,
status: "forbidden",
error: `Session not visible from this sandboxed agent session: ${params.sessionId}`
};
return {
ok: false,
status: "error",
error: formatErrorMessage(err) || `Session not found: ${params.sessionId} (use the full sessionKey from sessions_list)`
};
}
}
async function resolveSessionKeyFromKey(params) {
try {
const key = normalizeOptionalString((await sessionsResolutionDeps.callGateway({
method: "sessions.resolve",
params: {
key: params.key,
spawnedBy: params.restrictToSpawned ? params.requesterInternalKey : void 0
}
}))?.key) ?? "";
if (!key) return null;
return buildResolvedSessionReference({
key,
alias: params.alias,
mainKey: params.mainKey,
resolvedViaSessionId: false
});
} catch {
return null;
}
}
async function tryResolveSessionKeyFromSessionId(params) {
try {
return buildResolvedSessionReference({
key: await callGatewayResolveSessionId(params),
alias: params.alias,
mainKey: params.mainKey,
resolvedViaSessionId: true
});
} catch {
return null;
}
}
async function resolveSessionReferenceByKeyOrSessionId(params) {
if (!params.skipKeyLookup) {
const resolvedByKey = await resolveSessionKeyFromKey({
key: params.raw,
alias: params.alias,
mainKey: params.mainKey,
requesterInternalKey: params.requesterInternalKey,
restrictToSpawned: params.restrictToSpawned
});
if (resolvedByKey) return resolvedByKey;
}
if (!(params.forceSessionIdLookup || shouldResolveSessionIdInput(params.raw))) return null;
if (params.allowUnresolvedSessionId) return await tryResolveSessionKeyFromSessionId({
sessionId: params.raw,
alias: params.alias,
mainKey: params.mainKey,
requesterInternalKey: params.requesterInternalKey,
restrictToSpawned: params.restrictToSpawned
});
return await resolveSessionKeyFromSessionId({
sessionId: params.raw,
alias: params.alias,
mainKey: params.mainKey,
requesterInternalKey: params.requesterInternalKey,
restrictToSpawned: params.restrictToSpawned
});
}
async function resolveSessionReference(params) {
const rawInput = resolveCurrentSessionClientAlias({
key: params.sessionKey,
requesterInternalKey: params.requesterInternalKey
}) ?? params.sessionKey.trim();
if (rawInput === "current") {
const resolvedCurrent = await resolveSessionReferenceByKeyOrSessionId({
raw: rawInput,
alias: params.alias,
mainKey: params.mainKey,
requesterInternalKey: params.requesterInternalKey,
restrictToSpawned: params.restrictToSpawned,
allowUnresolvedSessionId: true,
skipKeyLookup: params.restrictToSpawned,
forceSessionIdLookup: true
});
if (resolvedCurrent) return resolvedCurrent;
}
const raw = rawInput === "current" && params.requesterInternalKey ? params.requesterInternalKey : rawInput;
if (shouldResolveSessionIdInput(raw)) {
const resolvedByGateway = await resolveSessionReferenceByKeyOrSessionId({
raw,
alias: params.alias,
mainKey: params.mainKey,
requesterInternalKey: params.requesterInternalKey,
restrictToSpawned: params.restrictToSpawned,
allowUnresolvedSessionId: false
});
if (resolvedByGateway) return resolvedByGateway;
}
const resolvedKey = resolveInternalSessionKey({
key: raw,
alias: params.alias,
mainKey: params.mainKey,
requesterInternalKey: params.requesterInternalKey
});
return {
ok: true,
key: resolvedKey,
displayKey: resolveDisplaySessionKey({
key: resolvedKey,
alias: params.alias,
mainKey: params.mainKey
}),
resolvedViaSessionId: false
};
}
async function resolveVisibleSessionReference(params) {
const resolvedKey = params.resolvedSession.key;
const displayKey = params.resolvedSession.displayKey;
if (!await isResolvedSessionVisibleToRequester({
requesterSessionKey: params.requesterSessionKey,
targetSessionKey: resolvedKey,
restrictToSpawned: params.restrictToSpawned,
resolvedViaSessionId: params.resolvedSession.resolvedViaSessionId
})) return {
ok: false,
status: "forbidden",
error: `Session not visible from this sandboxed agent session: ${params.visibilitySessionKey}`,
displayKey
};
return {
ok: true,
key: resolvedKey,
displayKey
};
}
//#endregion
//#region src/agents/tools/sessions-access.ts
/**
* Session visibility and access helpers for session tools.
*
* Adds OpenClaw session-key alias normalization and sandbox requester scoping over SDK visibility contracts.
*/
/** Resolves the requester context used to filter sandboxed session-tool access. */
function resolveSandboxedSessionToolContext(params) {
const { mainKey, alias } = resolveMainSessionAlias(params.cfg);
const visibility = resolveSandboxSessionToolsVisibility(params.cfg);
const requesterSessionKey = normalizeOptionalString(params.agentSessionKey);
const requesterInternalKey = requesterSessionKey ? resolveInternalSessionKey({
key: requesterSessionKey,
alias,
mainKey
}) : void 0;
return {
mainKey,
alias,
visibility,
requesterInternalKey,
effectiveRequesterKey: requesterInternalKey ?? alias,
restrictToSpawned: params.sandboxed === true && visibility === "spawned" && Boolean(requesterInternalKey) && !isSubagentSessionKey(requesterInternalKey)
};
}
//#endregion
//#region src/agents/tools/sessions-helpers.ts
/** Resolves config plus sandbox visibility context for a session tool call. */
function resolveSessionToolContext(opts) {
const cfg = opts?.config ?? getRuntimeConfig();
return {
cfg,
...resolveSandboxedSessionToolContext({
cfg,
agentSessionKey: opts?.agentSessionKey,
sandboxed: opts?.sandboxed
})
};
}
/** Classifies a session key/gateway kind into the row category used by tools. */
function classifySessionKind(params) {
const key = params.key;
if (key === params.alias || key === params.mainKey) return "main";
if (key.startsWith("cron:")) return "cron";
if (key.startsWith("hook:")) return "hook";
if (key.startsWith("node-") || key.startsWith("node:")) return "node";
if (params.gatewayKind === "group") return "group";
if (key.includes(":group:") || key.includes(":channel:")) return "group";
return "other";
}
/** Derives the best channel label for a session row. */
function deriveChannel(params) {
if (params.kind === "cron" || params.kind === "hook" || params.kind === "node") return "internal";
const channel = normalizeOptionalString(params.channel ?? void 0);
if (channel) return channel;
const lastChannel = normalizeOptionalString(params.lastChannel ?? void 0);
if (lastChannel) return lastChannel;
const parts = params.key.split(":").filter(Boolean);
if (parts.length >= 3 && (parts[1] === "group" || parts[1] === "channel")) return parts[0];
return "unknown";
}
//#endregion
export { resolveCurrentSessionClientAlias as a, resolveMainSessionAlias as c, shouldResolveSessionIdInput as d, SESSION_ID_RE as f, resolveSandboxedSessionToolContext as i, resolveSessionReference as l, deriveChannel as n, resolveDisplaySessionKey as o, looksLikeSessionId as p, resolveSessionToolContext as r, resolveInternalSessionKey as s, classifySessionKind as t, resolveVisibleSessionReference as u };