mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-23 07:51:33 +00:00
117 lines
3.5 KiB
TypeScript
117 lines
3.5 KiB
TypeScript
import type { OpenClawConfig } from "../config/config.js";
|
|
import { logWarn } from "../logger.js";
|
|
import { redactIdentifier } from "../logging/redact-identifier.js";
|
|
import {
|
|
classifySessionKeyShape,
|
|
DEFAULT_AGENT_ID,
|
|
normalizeAgentId,
|
|
parseAgentSessionKey,
|
|
} from "../routing/session-key.js";
|
|
import { resolveUserPath } from "../utils.js";
|
|
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "./agent-scope.js";
|
|
import { sanitizeForPromptLiteral } from "./sanitize-for-prompt.js";
|
|
|
|
export type WorkspaceFallbackReason = "missing" | "blank" | "invalid_type";
|
|
type AgentIdSource = "explicit" | "session_key" | "default";
|
|
|
|
export type ResolveRunWorkspaceResult = {
|
|
workspaceDir: string;
|
|
usedFallback: boolean;
|
|
fallbackReason?: WorkspaceFallbackReason;
|
|
agentId: string;
|
|
agentIdSource: AgentIdSource;
|
|
};
|
|
|
|
function resolveRunAgentId(params: {
|
|
sessionKey?: string;
|
|
agentId?: string;
|
|
config?: OpenClawConfig;
|
|
}): {
|
|
agentId: string;
|
|
agentIdSource: AgentIdSource;
|
|
} {
|
|
const rawSessionKey = params.sessionKey?.trim() ?? "";
|
|
const shape = classifySessionKeyShape(rawSessionKey);
|
|
if (shape === "malformed_agent") {
|
|
throw new Error("Malformed agent session key; refusing workspace resolution.");
|
|
}
|
|
|
|
const explicit =
|
|
typeof params.agentId === "string" && params.agentId.trim()
|
|
? normalizeAgentId(params.agentId)
|
|
: undefined;
|
|
if (explicit) {
|
|
return { agentId: explicit, agentIdSource: "explicit" };
|
|
}
|
|
|
|
const defaultAgentId = resolveDefaultAgentId(params.config ?? {});
|
|
if (shape === "missing" || shape === "legacy_or_alias") {
|
|
return {
|
|
agentId: defaultAgentId || DEFAULT_AGENT_ID,
|
|
agentIdSource: "default",
|
|
};
|
|
}
|
|
|
|
const parsed = parseAgentSessionKey(rawSessionKey);
|
|
if (parsed?.agentId) {
|
|
return {
|
|
agentId: normalizeAgentId(parsed.agentId),
|
|
agentIdSource: "session_key",
|
|
};
|
|
}
|
|
|
|
// Defensive fallback, should be unreachable for non-malformed shapes.
|
|
return {
|
|
agentId: defaultAgentId || DEFAULT_AGENT_ID,
|
|
agentIdSource: "default",
|
|
};
|
|
}
|
|
|
|
export function redactRunIdentifier(value: string | undefined): string {
|
|
return redactIdentifier(value, { len: 12 });
|
|
}
|
|
|
|
export function resolveRunWorkspaceDir(params: {
|
|
workspaceDir: unknown;
|
|
sessionKey?: string;
|
|
agentId?: string;
|
|
config?: OpenClawConfig;
|
|
}): ResolveRunWorkspaceResult {
|
|
const requested = params.workspaceDir;
|
|
const { agentId, agentIdSource } = resolveRunAgentId({
|
|
sessionKey: params.sessionKey,
|
|
agentId: params.agentId,
|
|
config: params.config,
|
|
});
|
|
if (typeof requested === "string") {
|
|
const trimmed = requested.trim();
|
|
if (trimmed) {
|
|
const sanitized = sanitizeForPromptLiteral(trimmed);
|
|
if (sanitized !== trimmed) {
|
|
logWarn("Control/format characters stripped from workspaceDir (OC-19 hardening).");
|
|
}
|
|
return {
|
|
workspaceDir: resolveUserPath(sanitized),
|
|
usedFallback: false,
|
|
agentId,
|
|
agentIdSource,
|
|
};
|
|
}
|
|
}
|
|
|
|
const fallbackReason: WorkspaceFallbackReason =
|
|
requested == null ? "missing" : typeof requested === "string" ? "blank" : "invalid_type";
|
|
const fallbackWorkspace = resolveAgentWorkspaceDir(params.config ?? {}, agentId);
|
|
const sanitizedFallback = sanitizeForPromptLiteral(fallbackWorkspace);
|
|
if (sanitizedFallback !== fallbackWorkspace) {
|
|
logWarn("Control/format characters stripped from fallback workspaceDir (OC-19 hardening).");
|
|
}
|
|
return {
|
|
workspaceDir: resolveUserPath(sanitizedFallback),
|
|
usedFallback: true,
|
|
fallbackReason,
|
|
agentId,
|
|
agentIdSource,
|
|
};
|
|
}
|