mirror of
https://fastgit.cc/github.com/openclaw/openclaw
synced 2026-05-01 06:36:23 +08:00
Fix workspace bootstrap prompt routing
This commit is contained in:
@@ -107,6 +107,18 @@ describe("resolveBootstrapContextForRun", () => {
|
||||
expect(extra?.content).toBe("extra");
|
||||
});
|
||||
|
||||
it("keeps BOOTSTRAP.md available in shared injected context for non-attempt consumers", async () => {
|
||||
const workspaceDir = await makeTempWorkspace("openclaw-bootstrap-");
|
||||
await fs.writeFile(path.join(workspaceDir, "BOOTSTRAP.md"), "ritual", "utf8");
|
||||
await fs.writeFile(path.join(workspaceDir, "AGENTS.md"), "rules", "utf8");
|
||||
|
||||
const result = await resolveBootstrapContextForRun({ workspaceDir });
|
||||
|
||||
expect(result.bootstrapFiles.some((file) => file.name === "BOOTSTRAP.md")).toBe(true);
|
||||
expect(result.contextFiles.some((file) => file.path.endsWith("BOOTSTRAP.md"))).toBe(true);
|
||||
expect(result.contextFiles.some((file) => file.path.endsWith("AGENTS.md"))).toBe(true);
|
||||
});
|
||||
|
||||
it("uses heartbeat-only bootstrap files in lightweight heartbeat mode", async () => {
|
||||
const workspaceDir = await makeTempWorkspace("openclaw-bootstrap-");
|
||||
await fs.writeFile(path.join(workspaceDir, "HEARTBEAT.md"), "check inbox", "utf8");
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
import {
|
||||
DEFAULT_HEARTBEAT_FILENAME,
|
||||
filterBootstrapFilesForSession,
|
||||
isWorkspaceBootstrapPending,
|
||||
loadWorkspaceBootstrapFiles,
|
||||
type WorkspaceBootstrapFile,
|
||||
} from "./workspace.js";
|
||||
@@ -272,3 +273,5 @@ export async function resolveBootstrapContextForRun(params: {
|
||||
});
|
||||
return { bootstrapFiles, contextFiles };
|
||||
}
|
||||
|
||||
export { isWorkspaceBootstrapPending };
|
||||
|
||||
@@ -19,6 +19,7 @@ export async function resolveAttemptBootstrapContext<
|
||||
contextInjectionMode: "always" | "continuation-skip";
|
||||
bootstrapContextMode?: string;
|
||||
bootstrapContextRunKind?: string;
|
||||
workspaceBootstrapPending?: boolean;
|
||||
sessionFile: string;
|
||||
hasCompletedBootstrapTurn: (sessionFile: string) => Promise<boolean>;
|
||||
resolveBootstrapContextForRun: () => Promise<TContext>;
|
||||
@@ -29,6 +30,7 @@ export async function resolveAttemptBootstrapContext<
|
||||
}
|
||||
> {
|
||||
const isContinuationTurn =
|
||||
!params.workspaceBootstrapPending &&
|
||||
params.contextInjectionMode === "continuation-skip" &&
|
||||
params.bootstrapContextRunKind !== "heartbeat" &&
|
||||
(await params.hasCompletedBootstrapTurn(params.sessionFile));
|
||||
|
||||
@@ -15,6 +15,7 @@ async function resolveBootstrapContext(params: {
|
||||
contextInjectionMode?: "always" | "continuation-skip";
|
||||
bootstrapContextMode?: string;
|
||||
bootstrapContextRunKind?: string;
|
||||
workspaceBootstrapPending?: boolean;
|
||||
completed?: boolean;
|
||||
resolver?: () => Promise<{ bootstrapFiles: unknown[]; contextFiles: unknown[] }>;
|
||||
}) {
|
||||
@@ -30,6 +31,7 @@ async function resolveBootstrapContext(params: {
|
||||
contextInjectionMode: params.contextInjectionMode ?? "always",
|
||||
bootstrapContextMode: params.bootstrapContextMode ?? "full",
|
||||
bootstrapContextRunKind: params.bootstrapContextRunKind ?? "default",
|
||||
workspaceBootstrapPending: params.workspaceBootstrapPending ?? false,
|
||||
sessionFile: "/tmp/session.jsonl",
|
||||
hasCompletedBootstrapTurn,
|
||||
resolveBootstrapContextForRun,
|
||||
@@ -75,6 +77,25 @@ describe("embedded attempt context injection", () => {
|
||||
expect(resolver).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("does not let stale session markers suppress pending workspace bootstrap", async () => {
|
||||
const resolver = vi.fn(async () => ({
|
||||
bootstrapFiles: [{ name: "AGENTS.md" }, { name: "BOOTSTRAP.md" }],
|
||||
contextFiles: [{ path: "AGENTS.md" }],
|
||||
}));
|
||||
|
||||
const { result, hasCompletedBootstrapTurn } = await resolveBootstrapContext({
|
||||
contextInjectionMode: "continuation-skip",
|
||||
workspaceBootstrapPending: true,
|
||||
completed: true,
|
||||
resolver,
|
||||
});
|
||||
|
||||
expect(result.isContinuationTurn).toBe(false);
|
||||
expect(hasCompletedBootstrapTurn).not.toHaveBeenCalled();
|
||||
expect(result.bootstrapFiles).toEqual([{ name: "AGENTS.md" }, { name: "BOOTSTRAP.md" }]);
|
||||
expect(resolver).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("forwards senderIsOwner into embedded message-action discovery", async () => {
|
||||
const input = buildEmbeddedMessageActionDiscoveryInput({
|
||||
cfg: {},
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
import {
|
||||
FULL_BOOTSTRAP_COMPLETED_CUSTOM_TYPE,
|
||||
hasCompletedBootstrapTurn,
|
||||
isWorkspaceBootstrapPending,
|
||||
makeBootstrapWarn,
|
||||
resolveBootstrapContextForRun,
|
||||
resolveContextInjectionMode,
|
||||
@@ -441,14 +442,16 @@ export async function runEmbeddedAttempt(
|
||||
|
||||
const sessionLabel = params.sessionKey ?? params.sessionId;
|
||||
const contextInjectionMode = resolveContextInjectionMode(params.config);
|
||||
const workspaceBootstrapPending = await isWorkspaceBootstrapPending(effectiveWorkspace);
|
||||
const {
|
||||
bootstrapFiles: hookAdjustedBootstrapFiles,
|
||||
contextFiles,
|
||||
contextFiles: resolvedContextFiles,
|
||||
shouldRecordCompletedBootstrapTurn,
|
||||
} = await resolveAttemptBootstrapContext({
|
||||
contextInjectionMode,
|
||||
bootstrapContextMode: params.bootstrapContextMode,
|
||||
bootstrapContextRunKind: params.bootstrapContextRunKind,
|
||||
workspaceBootstrapPending,
|
||||
sessionFile: params.sessionFile,
|
||||
hasCompletedBootstrapTurn,
|
||||
resolveBootstrapContextForRun: async () =>
|
||||
@@ -466,11 +469,17 @@ export async function runEmbeddedAttempt(
|
||||
runKind: params.bootstrapContextRunKind,
|
||||
}),
|
||||
});
|
||||
const contextFiles = resolvedContextFiles.filter(
|
||||
(file) => !/(^|[\\/])BOOTSTRAP\.md$/iu.test(file.path.trim()),
|
||||
);
|
||||
const bootstrapFilesForInjectionStats = hookAdjustedBootstrapFiles.filter(
|
||||
(file) => file.name !== DEFAULT_BOOTSTRAP_FILENAME,
|
||||
);
|
||||
const bootstrapMaxChars = resolveBootstrapMaxChars(params.config);
|
||||
const bootstrapTotalMaxChars = resolveBootstrapTotalMaxChars(params.config);
|
||||
const bootstrapAnalysis = analyzeBootstrapBudget({
|
||||
files: buildBootstrapInjectionStats({
|
||||
bootstrapFiles: hookAdjustedBootstrapFiles,
|
||||
bootstrapFiles: bootstrapFilesForInjectionStats,
|
||||
injectedFiles: contextFiles,
|
||||
}),
|
||||
bootstrapMaxChars,
|
||||
@@ -869,6 +878,7 @@ export async function runEmbeddedAttempt(
|
||||
toolNames: effectiveTools.map((tool) => tool.name),
|
||||
memoryCitationsMode: params.config?.memory?.citations,
|
||||
contextFiles,
|
||||
bootstrapPending: workspaceBootstrapPending,
|
||||
routing: promptChannelRouting,
|
||||
});
|
||||
const privilegedPromptState: {
|
||||
|
||||
@@ -74,6 +74,31 @@ describe("buildAgentSystemPrompt", () => {
|
||||
expect(promptPrefix).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps bootstrap instructions out of the privileged prompt when bootstrap is pending", () => {
|
||||
const channels = buildAgentPromptChannels({
|
||||
workspaceDir: "/tmp/openclaw",
|
||||
bootstrapPending: true,
|
||||
});
|
||||
|
||||
expect(channels.systemPrompt).not.toContain("## Bootstrap");
|
||||
expect(channels.systemPrompt).not.toContain("Bootstrap is pending for this workspace.");
|
||||
});
|
||||
|
||||
it("adds bootstrap-specific prelude text to the user prompt prefix when bootstrap is pending", () => {
|
||||
const promptPrefix = buildAgentUserPromptPrefix({ bootstrapPending: true });
|
||||
|
||||
expect(promptPrefix).toContain("[Bootstrap pending]");
|
||||
expect(promptPrefix).toContain(
|
||||
"Before producing any user-visible reply, you MUST read BOOTSTRAP.md from the workspace",
|
||||
);
|
||||
expect(promptPrefix).toContain(
|
||||
"Do not greet the user, offer help, answer the message, or reply normally",
|
||||
);
|
||||
expect(promptPrefix).toContain(
|
||||
"Your first user-visible reply for a bootstrap-pending workspace must follow BOOTSTRAP.md",
|
||||
);
|
||||
});
|
||||
|
||||
it("routes developer and user context when a routing contribution is applied", () => {
|
||||
registerMemoryPromptSection(() => ["## Memory Recall", "Use memory carefully.", ""]);
|
||||
const channels = buildAgentPromptChannels({
|
||||
|
||||
@@ -258,6 +258,7 @@ export function buildAgentUserPromptPrefix(params: {
|
||||
toolNames?: string[];
|
||||
memoryCitationsMode?: MemoryCitationsMode;
|
||||
contextFiles?: EmbeddedContextFile[];
|
||||
bootstrapPending?: boolean;
|
||||
routing?: PromptChannelRoutingResult;
|
||||
}): string | undefined {
|
||||
const promptMode = params.promptMode ?? "full";
|
||||
@@ -279,6 +280,15 @@ export function buildAgentUserPromptPrefix(params: {
|
||||
(file) => routeMap[normalizeContextFilePath(file.path)] === "user",
|
||||
);
|
||||
const text = [
|
||||
...(params.bootstrapPending
|
||||
? [
|
||||
"[Bootstrap pending]",
|
||||
"Before producing any user-visible reply, you MUST read BOOTSTRAP.md from the workspace and follow it.",
|
||||
"Do not greet the user, offer help, answer the message, or reply normally until after you have read and are following BOOTSTRAP.md.",
|
||||
"Your first user-visible reply for a bootstrap-pending workspace must follow BOOTSTRAP.md, not a generic greeting.",
|
||||
"",
|
||||
]
|
||||
: []),
|
||||
...splitPromptAdditionLines(params.routing?.userAdditions),
|
||||
...memorySection,
|
||||
...buildUserContextSection(userContextFiles),
|
||||
|
||||
@@ -14,7 +14,9 @@ import {
|
||||
DEFAULT_USER_FILENAME,
|
||||
ensureAgentWorkspace,
|
||||
filterBootstrapFilesForSession,
|
||||
isWorkspaceBootstrapPending,
|
||||
loadWorkspaceBootstrapFiles,
|
||||
resolveWorkspaceBootstrapStatus,
|
||||
resolveDefaultAgentWorkspaceDir,
|
||||
type WorkspaceBootstrapFile,
|
||||
} from "./workspace.js";
|
||||
@@ -174,6 +176,50 @@ describe("ensureAgentWorkspace", () => {
|
||||
expect(persisted).toContain('"setupCompletedAt": "2026-03-15T02:30:00.000Z"');
|
||||
});
|
||||
|
||||
it("reports bootstrap pending while BOOTSTRAP.md exists and completion is unset", async () => {
|
||||
const tempDir = await makeTempWorkspace("openclaw-workspace-");
|
||||
|
||||
await ensureAgentWorkspace({ dir: tempDir, ensureBootstrapFiles: true });
|
||||
|
||||
await expect(isWorkspaceBootstrapPending(tempDir)).resolves.toBe(true);
|
||||
await expect(resolveWorkspaceBootstrapStatus(tempDir)).resolves.toMatchObject({
|
||||
phase: "pending",
|
||||
bootstrapExists: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("reports bootstrap complete after BOOTSTRAP.md deletion sets setupCompletedAt", async () => {
|
||||
const tempDir = await makeTempWorkspace("openclaw-workspace-");
|
||||
|
||||
await ensureAgentWorkspace({ dir: tempDir, ensureBootstrapFiles: true });
|
||||
await fs.unlink(path.join(tempDir, DEFAULT_BOOTSTRAP_FILENAME));
|
||||
await ensureAgentWorkspace({ dir: tempDir, ensureBootstrapFiles: true });
|
||||
|
||||
await expect(isWorkspaceBootstrapPending(tempDir)).resolves.toBe(false);
|
||||
await expect(resolveWorkspaceBootstrapStatus(tempDir)).resolves.toMatchObject({
|
||||
phase: "complete",
|
||||
bootstrapExists: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not reopen bootstrap when BOOTSTRAP.md is restored after completion", async () => {
|
||||
const tempDir = await makeTempWorkspace("openclaw-workspace-");
|
||||
|
||||
await ensureAgentWorkspace({ dir: tempDir, ensureBootstrapFiles: true });
|
||||
await fs.unlink(path.join(tempDir, DEFAULT_BOOTSTRAP_FILENAME));
|
||||
await ensureAgentWorkspace({ dir: tempDir, ensureBootstrapFiles: true });
|
||||
await writeWorkspaceFile({
|
||||
dir: tempDir,
|
||||
name: DEFAULT_BOOTSTRAP_FILENAME,
|
||||
content: "# restored bootstrap",
|
||||
});
|
||||
|
||||
await expect(resolveWorkspaceBootstrapStatus(tempDir)).resolves.toMatchObject({
|
||||
phase: "complete",
|
||||
bootstrapExists: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("writes the current fenced HEARTBEAT template body into new workspaces", async () => {
|
||||
const tempDir = await makeTempWorkspace("openclaw-workspace-");
|
||||
|
||||
|
||||
@@ -166,6 +166,15 @@ type WorkspaceSetupState = {
|
||||
setupCompletedAt?: string;
|
||||
};
|
||||
|
||||
export type WorkspaceBootstrapPhase = "pending" | "complete";
|
||||
|
||||
export type WorkspaceBootstrapStatus = {
|
||||
phase: WorkspaceBootstrapPhase;
|
||||
bootstrapExists: boolean;
|
||||
bootstrapSeededAt?: string;
|
||||
setupCompletedAt?: string;
|
||||
};
|
||||
|
||||
/** Set of recognized bootstrap filenames for runtime validation */
|
||||
const VALID_BOOTSTRAP_NAMES: ReadonlySet<string> = new Set([
|
||||
DEFAULT_AGENTS_FILENAME,
|
||||
@@ -263,6 +272,30 @@ export async function isWorkspaceSetupCompleted(dir: string): Promise<boolean> {
|
||||
return typeof state.setupCompletedAt === "string" && state.setupCompletedAt.trim().length > 0;
|
||||
}
|
||||
|
||||
export async function resolveWorkspaceBootstrapStatus(
|
||||
dir: string,
|
||||
): Promise<WorkspaceBootstrapStatus> {
|
||||
const resolvedDir = resolveUserPath(dir);
|
||||
const [state, bootstrapExists] = await Promise.all([
|
||||
readWorkspaceSetupStateForDir(resolvedDir),
|
||||
fileExists(path.join(resolvedDir, DEFAULT_BOOTSTRAP_FILENAME)),
|
||||
]);
|
||||
const setupCompletedAt =
|
||||
typeof state.setupCompletedAt === "string" && state.setupCompletedAt.trim().length > 0
|
||||
? state.setupCompletedAt
|
||||
: undefined;
|
||||
return {
|
||||
phase: setupCompletedAt ? "complete" : bootstrapExists ? "pending" : "complete",
|
||||
bootstrapExists,
|
||||
bootstrapSeededAt: state.bootstrapSeededAt,
|
||||
setupCompletedAt,
|
||||
};
|
||||
}
|
||||
|
||||
export async function isWorkspaceBootstrapPending(dir: string): Promise<boolean> {
|
||||
return (await resolveWorkspaceBootstrapStatus(dir)).phase === "pending";
|
||||
}
|
||||
|
||||
async function writeWorkspaceSetupState(
|
||||
statePath: string,
|
||||
state: WorkspaceSetupState,
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { ExecToolDefaults } from "../../agents/bash-tools.js";
|
||||
import { resolveFastModeState } from "../../agents/fast-mode.js";
|
||||
import { resolveEmbeddedFullAccessState } from "../../agents/pi-embedded-runner/sandbox-info.js";
|
||||
import type { EmbeddedFullAccessBlockedReason } from "../../agents/pi-embedded-runner/types.js";
|
||||
import { isWorkspaceBootstrapPending } from "../../agents/workspace.js";
|
||||
import { resolveGroupSessionKey } from "../../config/sessions/group.js";
|
||||
import {
|
||||
resolveSessionFilePath,
|
||||
@@ -43,7 +44,10 @@ import { resolveOriginMessageProvider } from "./origin-routing.js";
|
||||
import { buildReplyPromptBodies } from "./prompt-prelude.js";
|
||||
import { resolveActiveRunQueueAction } from "./queue-policy.js";
|
||||
import { resolveQueueSettings } from "./queue/settings-runtime.js";
|
||||
import { buildBareSessionResetPrompt } from "./session-reset-prompt.js";
|
||||
import {
|
||||
buildBareSessionResetBootstrapPendingPrompt,
|
||||
buildBareSessionResetPrompt,
|
||||
} from "./session-reset-prompt.js";
|
||||
import { drainFormattedSystemEvents } from "./session-system-events.js";
|
||||
import { buildSessionStartupContextPrelude, shouldApplyStartupContext } from "./startup-context.js";
|
||||
import { resolveTypingMode } from "./typing-mode.js";
|
||||
@@ -320,15 +324,23 @@ export async function runPreparedReply(
|
||||
isNewSession &&
|
||||
((baseBodyTrimmedRaw.length === 0 && rawBodyTrimmed.length > 0) || isBareNewOrReset);
|
||||
const startupAction = /^\/reset(?:\s|$)/.test(normalizedCommandBody) ? "reset" : "new";
|
||||
const workspaceBootstrapPending =
|
||||
isBareSessionReset || isFirstTurnInSession
|
||||
? await isWorkspaceBootstrapPending(workspaceDir)
|
||||
: false;
|
||||
const startupContextPrelude =
|
||||
isBareSessionReset && shouldApplyStartupContext({ cfg, action: startupAction })
|
||||
isBareSessionReset &&
|
||||
!workspaceBootstrapPending &&
|
||||
shouldApplyStartupContext({ cfg, action: startupAction })
|
||||
? await buildSessionStartupContextPrelude({
|
||||
workspaceDir,
|
||||
cfg,
|
||||
})
|
||||
: null;
|
||||
const baseBodyFinal = isBareSessionReset
|
||||
? buildBareSessionResetPrompt(cfg)
|
||||
? workspaceBootstrapPending
|
||||
? buildBareSessionResetBootstrapPendingPrompt(cfg)
|
||||
: buildBareSessionResetPrompt(cfg)
|
||||
: stripPromptThinkingDirectives(baseBody);
|
||||
const envelopeOptions = resolveEnvelopeFormatOptions(cfg);
|
||||
const inboundUserContext = buildInboundUserContextPrefix(
|
||||
|
||||
@@ -1,19 +1,34 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { buildBareSessionResetPrompt } from "./session-reset-prompt.js";
|
||||
import {
|
||||
buildBareSessionResetBootstrapPendingPrompt,
|
||||
buildBareSessionResetPrompt,
|
||||
} from "./session-reset-prompt.js";
|
||||
|
||||
describe("buildBareSessionResetPrompt", () => {
|
||||
it("includes the explicit Session Startup instruction for bare /new and /reset", () => {
|
||||
const prompt = buildBareSessionResetPrompt();
|
||||
expect(prompt).toContain("Execute your Session Startup sequence now");
|
||||
expect(prompt).toContain("read the required files before responding to the user");
|
||||
expect(prompt).toContain("If BOOTSTRAP.md exists in the provided Project Context");
|
||||
expect(prompt).toContain("read it and follow its instructions first");
|
||||
expect(prompt).toContain("If bootstrap is still pending for this workspace");
|
||||
expect(prompt).toContain("read BOOTSTRAP.md from the workspace");
|
||||
expect(prompt).not.toContain(
|
||||
"If runtime-provided startup context is included for this first turn",
|
||||
);
|
||||
});
|
||||
|
||||
it("builds a bootstrap-pending reset prompt that suppresses the normal first greeting", () => {
|
||||
const prompt = buildBareSessionResetBootstrapPendingPrompt();
|
||||
expect(prompt).toContain("while bootstrap is still pending for this workspace");
|
||||
expect(prompt).toContain(
|
||||
"Before producing any user-visible reply, you MUST read BOOTSTRAP.md from the workspace now",
|
||||
);
|
||||
expect(prompt).toContain(
|
||||
"Do not greet the user, offer help, answer the message, or reply normally",
|
||||
);
|
||||
expect(prompt).toContain("Your first user-visible reply must follow BOOTSTRAP.md");
|
||||
});
|
||||
|
||||
it("appends current time line so agents know the date", () => {
|
||||
const cfg = {
|
||||
agents: { defaults: { userTimezone: "America/New_York", timeFormat: "12" } },
|
||||
|
||||
@@ -2,7 +2,10 @@ import { appendCronStyleCurrentTimeLine } from "../../agents/current-time.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
|
||||
const BARE_SESSION_RESET_PROMPT_BASE =
|
||||
"A new session was started via /new or /reset. Execute your Session Startup sequence now - read the required files before responding to the user. If BOOTSTRAP.md exists in the provided Project Context, read it and follow its instructions first. Then greet the user in your configured persona, if one is provided. Be yourself - use your defined voice, mannerisms, and mood. Keep it to 1-3 sentences and ask what they want to do. If the runtime model differs from default_model in the system prompt, mention the default model. Do not mention internal steps, files, tools, or reasoning.";
|
||||
"A new session was started via /new or /reset. Execute your Session Startup sequence now - read the required files before responding to the user. If bootstrap is still pending for this workspace, then before producing any user-visible reply you MUST read BOOTSTRAP.md from the workspace and follow it. Do not greet the user, offer help, answer the message, or reply normally until after you have read and are following BOOTSTRAP.md. Only once bootstrap is complete should you greet the user in your configured persona, if one is provided. Be yourself - use your defined voice, mannerisms, and mood. Keep it to 1-3 sentences and ask what they want to do. If the runtime model differs from default_model in the system prompt, mention the default model. Do not mention internal steps, files, tools, or reasoning.";
|
||||
|
||||
const BARE_SESSION_RESET_BOOTSTRAP_PENDING_PROMPT_BASE =
|
||||
"A new session was started via /new or /reset while bootstrap is still pending for this workspace. Before producing any user-visible reply, you MUST read BOOTSTRAP.md from the workspace now and follow it. Do not greet the user, offer help, answer the message, or reply normally until after you have read and are following BOOTSTRAP.md. Your first user-visible reply must follow BOOTSTRAP.md, not a generic greeting. If the runtime model differs from default_model in the system prompt, mention the default model only after following BOOTSTRAP.md. Do not mention internal steps, files, tools, or reasoning.";
|
||||
|
||||
/**
|
||||
* Build the bare session reset prompt, appending the current date/time so agents
|
||||
@@ -17,5 +20,16 @@ export function buildBareSessionResetPrompt(cfg?: OpenClawConfig, nowMs?: number
|
||||
);
|
||||
}
|
||||
|
||||
export function buildBareSessionResetBootstrapPendingPrompt(
|
||||
cfg?: OpenClawConfig,
|
||||
nowMs?: number,
|
||||
): string {
|
||||
return appendCronStyleCurrentTimeLine(
|
||||
BARE_SESSION_RESET_BOOTSTRAP_PENDING_PROMPT_BASE,
|
||||
cfg ?? {},
|
||||
nowMs ?? Date.now(),
|
||||
);
|
||||
}
|
||||
|
||||
/** @deprecated Use buildBareSessionResetPrompt(cfg) instead */
|
||||
export const BARE_SESSION_RESET_PROMPT = BARE_SESSION_RESET_PROMPT_BASE;
|
||||
|
||||
Reference in New Issue
Block a user