openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
242 lines (241 loc) • 9.31 kB
JavaScript
import { c as normalizeOptionalString, s as normalizeOptionalLowercaseString } from "./string-coerce-mnp54Vah.js";
import { r as getSessionEntry } from "./store-Qsgtu-0y.js";
import { _ as updateSessionGoalStatus, f as clearSessionGoal, h as getSessionGoal, m as formatSessionGoalStatus, p as createSessionGoal } from "./sessions-D6zZvoxX.js";
import { r as rejectUnauthorizedCommand } from "./command-gates-BPeUVpsw.js";
//#region src/auto-reply/reply/command-session-metadata.ts
const commandSessionMetadataChanges = /* @__PURE__ */ new WeakMap();
function addChange(target, change) {
const changes = commandSessionMetadataChanges.get(target) ?? [];
if (!changes.some((candidate) => candidate.sessionKey === change.sessionKey && candidate.agentId === change.agentId && candidate.reason === change.reason)) changes.push(change);
commandSessionMetadataChanges.set(target, changes);
}
function markCommandSessionMetadataChanged(params) {
const sessionKey = normalizeOptionalString(params.sessionKey);
if (!sessionKey) return;
const change = {
sessionKey,
...params.agentId ? { agentId: params.agentId } : {},
reason: "command-metadata"
};
const targets = /* @__PURE__ */ new Set();
if (params.rootCtx && typeof params.rootCtx === "object") targets.add(params.rootCtx);
if (params.ctx && typeof params.ctx === "object") targets.add(params.ctx);
for (const target of targets) addChange(target, change);
}
function takeCommandSessionMetadataChanges(target) {
const changes = commandSessionMetadataChanges.get(target);
commandSessionMetadataChanges.delete(target);
return changes && changes.length > 0 ? changes : void 0;
}
function takeCommandSessionMetadataChangesFromTargets(targets) {
const changes = [];
const seen = /* @__PURE__ */ new Set();
for (const target of new Set(targets)) for (const change of takeCommandSessionMetadataChanges(target) ?? []) {
const key = JSON.stringify([
change.sessionKey,
change.agentId ?? null,
change.reason
]);
if (seen.has(key)) continue;
seen.add(key);
changes.push(change);
}
return changes.length > 0 ? changes : void 0;
}
//#endregion
//#region src/auto-reply/reply/commands-goal.ts
/** Handles /goal session objective commands and continuation prompt formatting. */
const GOAL_COMMAND_PREFIX = "/goal";
const GOAL_CONTINUATION_PROMPT_PREFIX = "Pursue this goal exactly as written from this JSON string:";
const GOAL_RESUME_NOTE_PROMPT_PREFIX = "Continue pursuing the current goal. Interpret this JSON string as the resume note:";
const GOAL_ACTIONS = new Set([
"block",
"blocked",
"clear",
"complete",
"create",
"done",
"pause",
"resume",
"set",
"start",
"status"
]);
/** Parses /goal action text, defaulting unknown actions to goal creation. */
function parseGoalCommand(raw) {
const trimmed = raw.trim();
const commandEnd = trimmed.search(/\s/);
if (normalizeOptionalLowercaseString(commandEnd === -1 ? trimmed : trimmed.slice(0, commandEnd)) !== GOAL_COMMAND_PREFIX) return null;
const argText = commandEnd === -1 ? "" : trimmed.slice(commandEnd).trim();
if (!argText) return {
action: "status",
text: ""
};
const [actionRaw = "", ...rest] = argText.split(/\s+/);
const action = normalizeOptionalLowercaseString(actionRaw) ?? "status";
if (!GOAL_ACTIONS.has(action)) return {
action: "start",
text: argText
};
return {
action,
text: rest.join(" ").trim()
};
}
function syncGoalSessionEntry(params) {
if (!params.sessionStore || !params.sessionKey) return;
const entry = getSessionEntry({
sessionKey: params.sessionKey,
storePath: params.storePath
});
if (!entry) return;
params.sessionStore[params.sessionKey] = entry;
params.sessionEntry = entry;
}
function goalReply(text) {
return {
shouldContinue: false,
reply: { text }
};
}
function hasCommandLikeGoalText(trimmed) {
return /(?:^|\s)\//.test(trimmed) || trimmed.startsWith("!");
}
function encodeGoalJsonString(trimmed) {
return JSON.stringify(trimmed).replaceAll("/", "\\/");
}
/** Formats the model prompt used to continue a newly started goal. */
function formatGoalContinuationPrompt(objective) {
const trimmed = objective.trim();
return hasCommandLikeGoalText(trimmed) ? `${GOAL_CONTINUATION_PROMPT_PREFIX} ${encodeGoalJsonString(trimmed)}` : trimmed;
}
/** Formats the model prompt used when resuming a paused goal. */
function formatGoalResumeContinuationPrompt(note) {
const trimmed = note.trim();
if (!trimmed) return "Continue pursuing the current goal.";
return hasCommandLikeGoalText(trimmed) ? `${GOAL_RESUME_NOTE_PROMPT_PREFIX} ${encodeGoalJsonString(trimmed)}` : `Continue pursuing the current goal. Note: ${trimmed}`;
}
/** Returns true for internally generated goal continuation prompts. */
function isFormattedGoalContinuationPrompt(message) {
const trimmed = message.trim();
return trimmed.startsWith(GOAL_CONTINUATION_PROMPT_PREFIX) || trimmed.startsWith(GOAL_RESUME_NOTE_PROMPT_PREFIX);
}
function applyGoalPromptToContext(ctx, message) {
const mutableCtx = ctx;
mutableCtx.Body = message;
mutableCtx.RawBody = message;
mutableCtx.CommandBody = message;
mutableCtx.BodyForCommands = message;
mutableCtx.BodyForAgent = message;
mutableCtx.BodyStripped = message;
}
function applyGoalContinuationPrompt(params, message) {
applyGoalPromptToContext(params.ctx, message);
if (params.rootCtx && params.rootCtx !== params.ctx) applyGoalPromptToContext(params.rootCtx, message);
params.command.rawBodyNormalized = message;
params.command.commandBodyNormalized = message;
}
function goalContinuation() {
return { shouldContinue: true };
}
function goalErrorReply(error) {
return goalReply(`Goal error: ${error instanceof Error ? error.message : String(error)}`);
}
/** Command handler for /goal lifecycle commands. */
const handleGoalCommand = async (params, allowTextCommands) => {
if (!allowTextCommands) return null;
const parsed = parseGoalCommand(params.command.commandBodyNormalized);
if (!parsed) return null;
const unauthorized = rejectUnauthorizedCommand(params, "/goal");
if (unauthorized) return unauthorized;
try {
switch (parsed.action) {
case "status": {
const snapshot = await getSessionGoal({
sessionKey: params.sessionKey,
storePath: params.storePath,
fallbackEntry: params.sessionEntry,
persist: false
});
syncGoalSessionEntry(params);
return goalReply(formatSessionGoalStatus(snapshot.goal));
}
case "start":
case "set":
case "create": {
const objective = normalizeOptionalString(parsed.text);
if (!objective) return goalReply("Usage: /goal start <objective>");
const goal = await createSessionGoal({
sessionKey: params.sessionKey,
storePath: params.storePath,
objective,
fallbackEntry: params.sessionEntry
});
syncGoalSessionEntry(params);
markCommandSessionMetadataChanged(params);
applyGoalContinuationPrompt(params, formatGoalContinuationPrompt(goal.objective));
return goalContinuation();
}
case "pause": {
const goal = await updateSessionGoalStatus({
sessionKey: params.sessionKey,
storePath: params.storePath,
status: "paused",
...parsed.text ? { note: parsed.text } : {}
});
syncGoalSessionEntry(params);
markCommandSessionMetadataChanged(params);
return goalReply(`Goal paused: ${goal.objective}`);
}
case "resume":
await updateSessionGoalStatus({
sessionKey: params.sessionKey,
storePath: params.storePath,
status: "active",
...parsed.text ? { note: parsed.text } : {}
});
syncGoalSessionEntry(params);
markCommandSessionMetadataChanged(params);
applyGoalContinuationPrompt(params, formatGoalResumeContinuationPrompt(parsed.text));
return goalContinuation();
case "complete":
case "done": {
const goal = await updateSessionGoalStatus({
sessionKey: params.sessionKey,
storePath: params.storePath,
status: "complete",
...parsed.text ? { note: parsed.text } : {}
});
syncGoalSessionEntry(params);
markCommandSessionMetadataChanged(params);
return goalReply(`Goal complete: ${goal.objective}\nTokens used: ${goal.tokensUsed}`);
}
case "block":
case "blocked": {
const goal = await updateSessionGoalStatus({
sessionKey: params.sessionKey,
storePath: params.storePath,
status: "blocked",
...parsed.text ? { note: parsed.text } : {}
});
syncGoalSessionEntry(params);
markCommandSessionMetadataChanged(params);
return goalReply(`Goal blocked: ${goal.objective}`);
}
case "clear": {
const removed = await clearSessionGoal({
sessionKey: params.sessionKey,
storePath: params.storePath
});
syncGoalSessionEntry(params);
if (removed) markCommandSessionMetadataChanged(params);
return goalReply(removed ? "Goal cleared." : "No goal to clear.");
}
default: return goalReply("Usage: /goal <objective> | /goal [status] | /goal start <objective> | /goal pause|resume|complete|block|clear");
}
} catch (error) {
return goalErrorReply(error);
}
};
//#endregion
export { parseGoalCommand as a, isFormattedGoalContinuationPrompt as i, formatGoalResumeContinuationPrompt as n, takeCommandSessionMetadataChanges as o, handleGoalCommand as r, takeCommandSessionMetadataChangesFromTargets as s, formatGoalContinuationPrompt as t };