mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 01:29:56 +00:00
refactor(prompt): remove unreachable runtime-only system prompt path (#143314)
## What Problem This Solves Remove the audit-found runtime-only system-prompt branch and its unused mutation interface. This is a maintainer-approved refactor, not a Gateway cache fix or a performance improvement. The branch is unreachable through the supported Gateway event ingress paths: completion events receive a nonempty transcript from [`resolveInternalEventTranscriptBody`](31d03f7822/src/agents/internal-events.ts (L372)), selected by [agent preparation](31d03f7822/src/agents/command/prepare.ts (L415)), and room events receive an [attributed transcript line](31d03f7822/src/auto-reply/reply/prompt-prelude.ts (L212)). The removed append required an empty transcript. Persistence suppression also disables runtime-only admission. ## Why This Change Was Made - Remove event-specific system-prompt composition and session mutation from prompt-context assembly. - Remove that stage's unused system-setter callback and update every caller and fixture; preserve the assembly-stage setter used by hooks and model identity. - Remove the unused runtime-event formatter variant and retain one delimiter-only carrier format. - Keep event tail routing, escaping, carrier lifetime, and the byte-stability regression. ## User Impact No user-visible behavior change is expected. The cleanup removes unused mutation paths while preserving supported Gateway event handling. ## Evidence The [real-API comparison](https://github.com/openclaw/openclaw/pull/143314#issuecomment-5632556877) showed no cache regression on main: both main and the original PR head kept instruction bytes equal across normal → completion event → normal, with cached-token counts of 0 → 5,888 → 5,888 in both runs. The regression fixture reaches the removed branch by supplying an empty transcript directly; it is retained as an internal byte-stability guard. All 260 focused runner, context, formatter, truncation, and legacy-stripping tests pass. With the callback-free fixture, the original append implementation fails three event cases by attempting the removed setter; 18 controls pass. All cases pass after the path is removed. Formatting, focused lint, and normal commit hooks pass. This is internal refactor coverage; the live results do not establish a user-visible cache defect. Thanks @zackmsa777-a11y for the original change and review fixes. The follow-up cleanup preserves the contributor's commits and authorship. Related: #143242. Co-authored-by: Ayaan Zaidi <hi@obviy.us>
This commit is contained in:
parent
f50d4ce71e
commit
b97da79299
13 changed files with 54 additions and 89 deletions
|
|
@ -3,4 +3,4 @@
|
|||
# Worker bundle installation no longer injects OPENCLAW_STATE_DIR into a remote npm process.
|
||||
# The internal Node-version check no longer contributes a false OPENCLAW_* name.
|
||||
# The next-turn runtime-context preface constant no longer exists as an OPENCLAW_* name.
|
||||
493
|
||||
492
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ export function usesEscapedRuntimeContext(sessionVersion?: number): boolean {
|
|||
}
|
||||
|
||||
/** The model boundary renders producer facts; transcript content remains untouched. */
|
||||
export function projectRuntimeContextFragments(fragments: RuntimeContextFragment[]): string {
|
||||
function projectRuntimeContextFragments(fragments: RuntimeContextFragment[]): string {
|
||||
return fragments
|
||||
.map(({ kind, text }) => {
|
||||
const escaped = escapeInternalRuntimeContextDelimiters(text);
|
||||
|
|
@ -86,10 +86,9 @@ function projectRuntimeContextMessages(messages: AgentMessage[]): AgentMessage[]
|
|||
if (details.success) {
|
||||
return {
|
||||
...message,
|
||||
content: buildRuntimeContextMessageContent({
|
||||
runtimeContext: projectRuntimeContextFragments(details.data.fragments),
|
||||
kind: "next-turn",
|
||||
}),
|
||||
content: buildRuntimeContextMessageContent(
|
||||
projectRuntimeContextFragments(details.data.fragments),
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ import {
|
|||
} from "../tool-result-truncation.js";
|
||||
import {
|
||||
normalizeCurrentPromptTextForLlmBoundary,
|
||||
projectRuntimeContextFragments,
|
||||
usesEscapedRuntimeContext,
|
||||
normalizeMessagesForCurrentPromptBoundary,
|
||||
} from "./attempt-llm-boundary.js";
|
||||
|
|
@ -70,7 +69,6 @@ import { pruneProcessedHistoryImages } from "./history-image-prune.js";
|
|||
import {
|
||||
buildCurrentInboundPrompt,
|
||||
buildRuntimeContextCustomMessage,
|
||||
buildRuntimeContextMessageContent,
|
||||
resolveRuntimeContextPromptParts,
|
||||
type RuntimeContextCustomMessage,
|
||||
} from "./runtime-context-prompt.js";
|
||||
|
|
@ -405,7 +403,6 @@ export function prepareEmbeddedAttemptPromptContext(input: {
|
|||
prompt: PromptAssemblyContext;
|
||||
replaceSessionMessages: (messages: AgentMessage[]) => void;
|
||||
sessionAgentId: string;
|
||||
setActiveSessionSystemPrompt: (systemPrompt: string) => void;
|
||||
systemPromptReport?: SessionSystemPromptReport;
|
||||
systemPromptText: string;
|
||||
toolResultPromptProjectionState: ToolResultPromptProjectionState;
|
||||
|
|
@ -511,25 +508,7 @@ export function prepareEmbeddedAttemptPromptContext(input: {
|
|||
...(promptForModel !== promptForSession ? { alternateText: promptForModel } : {}),
|
||||
}
|
||||
: undefined;
|
||||
const runtimeSystemContext = promptSubmission.runtimeOnly
|
||||
? buildRuntimeContextMessageContent({
|
||||
runtimeContext: escapedProjection
|
||||
? projectRuntimeContextFragments(eventFragments)
|
||||
: (promptSubmission.runtimeContext ?? ""),
|
||||
kind: "runtime-event",
|
||||
})
|
||||
: undefined;
|
||||
let systemPromptForHook = input.systemPromptText;
|
||||
if (promptSubmission.runtimeOnly && runtimeSystemContext) {
|
||||
const runtimeSystemPrompt = composeSystemPromptWithHookContext({
|
||||
baseSystemPrompt: input.systemPromptText,
|
||||
appendSystemContext: runtimeSystemContext,
|
||||
});
|
||||
if (runtimeSystemPrompt) {
|
||||
systemPromptForHook = runtimeSystemPrompt;
|
||||
input.setActiveSessionSystemPrompt(runtimeSystemPrompt);
|
||||
}
|
||||
}
|
||||
const systemPromptForHook = input.systemPromptText;
|
||||
const runtimeFacts =
|
||||
input.isRawModelRun || attempt.operation === "settled-tool-finalization"
|
||||
? []
|
||||
|
|
@ -541,7 +520,7 @@ export function prepareEmbeddedAttemptPromptContext(input: {
|
|||
agentId: input.sessionAgentId,
|
||||
});
|
||||
const contextFragments = promptSubmission.runtimeOnly
|
||||
? runtimeFacts
|
||||
? [...eventFragments, ...runtimeFacts]
|
||||
: [...fragments, ...runtimeFacts];
|
||||
const runtimeContextForHook =
|
||||
contextFragments
|
||||
|
|
@ -573,9 +552,7 @@ export function prepareEmbeddedAttemptPromptContext(input: {
|
|||
input.systemPromptReport.currentTurn = {
|
||||
...(attempt.currentInboundEventKind ? { kind: attempt.currentInboundEventKind } : {}),
|
||||
promptChars: promptForModel.length,
|
||||
runtimeContextChars:
|
||||
(runtimeContextForHook?.length ?? 0) +
|
||||
(promptSubmission.runtimeOnly ? (runtimeSystemContext?.length ?? 0) : 0),
|
||||
runtimeContextChars: runtimeContextForHook?.length ?? 0,
|
||||
// Hook context reaches only the model, so count the delta beyond the
|
||||
// transcript prompt or downstream context accounting undercounts it.
|
||||
modelOnlyPromptChars: Math.max(0, promptForModel.length - promptForSession.length),
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ function createInput(options?: {
|
|||
report?: SessionSystemPromptReport;
|
||||
}) {
|
||||
const replaceSessionMessages = vi.fn();
|
||||
const setActiveSessionSystemPrompt = vi.fn();
|
||||
const report = options?.report ?? ({} as SessionSystemPromptReport);
|
||||
return {
|
||||
input: {
|
||||
|
|
@ -111,14 +110,12 @@ function createInput(options?: {
|
|||
prompt: options?.prompt ?? createPrompt(),
|
||||
replaceSessionMessages,
|
||||
sessionAgentId: "agent-1",
|
||||
setActiveSessionSystemPrompt,
|
||||
systemPromptReport: report,
|
||||
systemPromptText: "Base system prompt",
|
||||
toolResultPromptProjectionState: projectionState,
|
||||
},
|
||||
replaceSessionMessages,
|
||||
report,
|
||||
setActiveSessionSystemPrompt,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +164,6 @@ describe("prepareEmbeddedAttemptPromptContext", () => {
|
|||
);
|
||||
expect(after.systemPromptForHook).toBe(before.systemPromptForHook);
|
||||
expect(after.promptForSession).toBe(before.promptForSession);
|
||||
expect(fixture.setActiveSessionSystemPrompt).not.toHaveBeenCalled();
|
||||
}));
|
||||
it("carries execution-owned processes in id order without elapsed time or output", () => {
|
||||
const fixture = createInput();
|
||||
|
|
@ -191,7 +187,6 @@ describe("prepareEmbeddedAttemptPromptContext", () => {
|
|||
text: expect.stringContaining("Active exec sessions:"),
|
||||
});
|
||||
expect(active.promptForSession).toBe("Visible request");
|
||||
expect(fixture.setActiveSessionSystemPrompt).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("carries changed subagent status without rewriting the system prompt", () => {
|
||||
|
|
@ -222,7 +217,6 @@ describe("prepareEmbeddedAttemptPromptContext", () => {
|
|||
expect(completed.runtimeContextMessageForCurrentTurn?.content).toContain(
|
||||
"## Active Subagents\nnone",
|
||||
);
|
||||
expect(fixture.setActiveSessionSystemPrompt).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("carries changed media progress without rewriting the system prompt", () => {
|
||||
|
|
@ -248,7 +242,6 @@ describe("prepareEmbeddedAttemptPromptContext", () => {
|
|||
'progress_json="Encoding"',
|
||||
);
|
||||
expect(encoding.runtimeContextMessageForCurrentTurn?.content).not.toContain("Rendering");
|
||||
expect(fixture.setActiveSessionSystemPrompt).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("supersedes retained active facts with explicit empty snapshots", () => {
|
||||
|
|
@ -353,7 +346,6 @@ describe("prepareEmbeddedAttemptPromptContext", () => {
|
|||
modelOnlyPromptChars: 0,
|
||||
});
|
||||
expect(fixture.replaceSessionMessages).not.toHaveBeenCalled();
|
||||
expect(fixture.setActiveSessionSystemPrompt).not.toHaveBeenCalled();
|
||||
expect(hoisted.reconcileToolResultPromptProjectionState).toHaveBeenCalledWith(
|
||||
messages,
|
||||
projectionState,
|
||||
|
|
@ -443,7 +435,7 @@ describe("prepareEmbeddedAttemptPromptContext", () => {
|
|||
});
|
||||
|
||||
it.each([3, 4])(
|
||||
"keeps version %s runtime-only events in system context with current facts",
|
||||
"carries version %s runtime-only events in the message tail carrier without rewriting system prompt",
|
||||
(sessionVersion) => {
|
||||
const fixture = createInput({
|
||||
attempt: createAttempt({
|
||||
|
|
@ -462,7 +454,9 @@ describe("prepareEmbeddedAttemptPromptContext", () => {
|
|||
fixture.input.capabilityToolNames.add("process");
|
||||
const result = prepareEmbeddedAttemptPromptContext({ ...fixture.input, sessionVersion });
|
||||
|
||||
expect(result.systemPromptForHook).toContain("OpenClaw runtime event.");
|
||||
expect(result.systemPromptForHook).toBe("Base system prompt");
|
||||
expect(result.systemPromptForHook).not.toContain("OpenClaw runtime event.");
|
||||
expect(result.systemPromptForHook).not.toContain("Runtime room event");
|
||||
expect(result.promptSubmission.runtimeOnly).toBe(true);
|
||||
expect(result.promptForSession).toBe(
|
||||
"Room conversation data\n\nContinue the OpenClaw runtime event.",
|
||||
|
|
@ -472,18 +466,40 @@ describe("prepareEmbeddedAttemptPromptContext", () => {
|
|||
expect(result.runtimeContextMessageForCurrentTurn?.content).toContain(
|
||||
"Active exec sessions:\nnone",
|
||||
);
|
||||
expect(result.runtimeContextMessageForCurrentTurn?.content).not.toContain(
|
||||
"Runtime room event",
|
||||
);
|
||||
expect(result.systemPromptForHook).toContain("Runtime room event");
|
||||
expect(fixture.setActiveSessionSystemPrompt).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Runtime room event"),
|
||||
);
|
||||
expect(result.runtimeContextMessageForCurrentTurn?.content).toContain("Runtime room event");
|
||||
expect(fixture.report.currentTurn?.kind).toBe("room_event");
|
||||
expect(fixture.report.currentTurn?.runtimeContextChars).toBeGreaterThan(0);
|
||||
},
|
||||
);
|
||||
|
||||
it("preserves identical system prompt bytes across normal turns and runtime-only event turns", () => {
|
||||
const fixture = createInput();
|
||||
const normalTurn = prepareEmbeddedAttemptPromptContext(fixture.input);
|
||||
|
||||
const runtimeEventFixture = createInput({
|
||||
attempt: createAttempt({
|
||||
runtimeContextFragments: [
|
||||
{ kind: "runtime-instruction", text: "Subagent completed task 42" },
|
||||
],
|
||||
currentInboundEventKind: "room_event",
|
||||
}),
|
||||
prompt: createPrompt({
|
||||
effectivePrompt: "",
|
||||
effectiveTranscriptPrompt: "",
|
||||
}),
|
||||
});
|
||||
const runtimeTurn = prepareEmbeddedAttemptPromptContext(runtimeEventFixture.input);
|
||||
|
||||
const normalTurnAfter = prepareEmbeddedAttemptPromptContext(fixture.input);
|
||||
|
||||
expect(normalTurn.systemPromptForHook).toBe("Base system prompt");
|
||||
expect(runtimeTurn.systemPromptForHook).toBe(normalTurn.systemPromptForHook);
|
||||
expect(normalTurnAfter.systemPromptForHook).toBe(normalTurn.systemPromptForHook);
|
||||
expect(runtimeTurn.runtimeContextMessageForCurrentTurn?.content).toContain(
|
||||
"Subagent completed task 42",
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps a pure heartbeat task active while persisting only the poll marker", () => {
|
||||
const taskPrompt = "Check the deployment and report any failures.";
|
||||
const transcriptPrompt = "[OpenClaw heartbeat poll]";
|
||||
|
|
|
|||
|
|
@ -193,7 +193,6 @@ export async function runEmbeddedAttemptPromptPhase(
|
|||
isRawModelRun,
|
||||
...(preparedUserTurnMessage ? { preparedUserTurnMessage } : {}),
|
||||
sessionAgentId,
|
||||
setActiveSessionSystemPrompt,
|
||||
...(systemPromptReport ? { systemPromptReport } : {}),
|
||||
systemPromptText,
|
||||
toolResultPromptProjectionState,
|
||||
|
|
|
|||
|
|
@ -128,7 +128,6 @@ async function createTurnFixture(systemPromptOverride?: string) {
|
|||
includeBoundaryTimestamp: false,
|
||||
isRawModelRun: false,
|
||||
sessionAgentId: "main",
|
||||
setActiveSessionSystemPrompt,
|
||||
systemPromptText,
|
||||
toolResultPromptProjectionState: {
|
||||
replacements: new Map(),
|
||||
|
|
|
|||
|
|
@ -1905,7 +1905,7 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("submits runtime-only context through system prompt without visible prompt", async () => {
|
||||
it("submits runtime-only context through the tail carrier without visible prompt", async () => {
|
||||
hoisted.sessionManager.getHeader.mockReturnValue({ version: 4 });
|
||||
let seenPrompt: string | undefined;
|
||||
let seenModelMessages: unknown[] | undefined;
|
||||
|
|
@ -1963,7 +1963,7 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => {
|
|||
expect(contextCompiled?.data?.prompt).toContain("dynamic hook context");
|
||||
expect(contextCompiled?.data?.prompt).toContain("internal heartbeat event");
|
||||
expect(contextCompiled?.data?.prompt).toContain("dynamic hook tail");
|
||||
expect(contextCompiled?.data?.systemPrompt).toContain("internal heartbeat event");
|
||||
expect(contextCompiled?.data?.systemPrompt).not.toContain("internal heartbeat event");
|
||||
expect(contextCompiled?.data?.systemPrompt).not.toContain("dynamic hook context");
|
||||
expect(contextCompiled?.data?.systemPrompt).not.toContain("dynamic hook tail");
|
||||
});
|
||||
|
|
@ -2061,7 +2061,8 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => {
|
|||
const trajectoryEvents = await readTrajectoryEvents(tempPaths);
|
||||
const contextCompiled = trajectoryEvents.find((event) => event.type === "context.compiled");
|
||||
expect(contextCompiled?.data?.prompt).toContain("Hello from the replied message");
|
||||
expect(contextCompiled?.data?.systemPrompt).toContain("runtime bare mention event");
|
||||
expect(contextCompiled?.data?.prompt).toContain("runtime bare mention event");
|
||||
expect(contextCompiled?.data?.systemPrompt).not.toContain("runtime bare mention event");
|
||||
expect(contextCompiled?.data?.systemPrompt).not.toContain("Hello from the replied message");
|
||||
expect(contextCompiled?.data?.systemPrompt).not.toContain(
|
||||
"Reply target of current user message:",
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ describe("runtime context prompt submission", () => {
|
|||
).toEqual({ prompt: "[OpenClaw heartbeat poll]", modelPrompt: "Check the deployment." });
|
||||
});
|
||||
|
||||
it("requires producer context for runtime-only system context", () => {
|
||||
it("requires producer context for the runtime-only continuation prompt", () => {
|
||||
const fragments = [
|
||||
{ kind: "runtime-instruction" as const, text: "Continue the background task." },
|
||||
];
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ import {
|
|||
INTERNAL_RUNTIME_CONTEXT_BEGIN,
|
||||
INTERNAL_RUNTIME_CONTEXT_END,
|
||||
OPENCLAW_RUNTIME_CONTEXT_CUSTOM_TYPE,
|
||||
OPENCLAW_RUNTIME_CONTEXT_NOTICE,
|
||||
OPENCLAW_RUNTIME_EVENT_HEADER,
|
||||
type RuntimeContextFragment,
|
||||
} from "../../internal-runtime-context.js";
|
||||
import type { CurrentInboundPromptContext } from "./params.js";
|
||||
|
|
@ -89,22 +87,9 @@ export function resolveRuntimeContextPromptParts(params: {
|
|||
};
|
||||
}
|
||||
|
||||
export function buildRuntimeContextMessageContent(params: {
|
||||
runtimeContext: string;
|
||||
kind: "next-turn" | "runtime-event";
|
||||
}): string {
|
||||
// Next-turn carriers carry only the delimited body: the stable system prompt
|
||||
// explains the markers once, and the delimiters are what hasInternalRuntimeContext
|
||||
// and the leak strippers key on. Runtime events keep their preface because the
|
||||
// model receives no user message alongside them.
|
||||
return [
|
||||
...(params.kind === "runtime-event"
|
||||
? [OPENCLAW_RUNTIME_EVENT_HEADER, OPENCLAW_RUNTIME_CONTEXT_NOTICE, ""]
|
||||
: []),
|
||||
INTERNAL_RUNTIME_CONTEXT_BEGIN,
|
||||
params.runtimeContext,
|
||||
INTERNAL_RUNTIME_CONTEXT_END,
|
||||
].join("\n");
|
||||
export function buildRuntimeContextMessageContent(runtimeContext: string): string {
|
||||
// The stable system prompt explains the markers once; leak strippers use the delimiters.
|
||||
return [INTERNAL_RUNTIME_CONTEXT_BEGIN, runtimeContext, INTERNAL_RUNTIME_CONTEXT_END].join("\n");
|
||||
}
|
||||
|
||||
/** Creates a non-displayed custom transcript message for runtime context, if any exists. */
|
||||
|
|
@ -119,10 +104,7 @@ export function buildRuntimeContextCustomMessage(
|
|||
return {
|
||||
role: "custom",
|
||||
customType: OPENCLAW_RUNTIME_CONTEXT_CUSTOM_TYPE,
|
||||
content: buildRuntimeContextMessageContent({
|
||||
runtimeContext: trimmedRuntimeContext,
|
||||
kind: "next-turn",
|
||||
}),
|
||||
content: buildRuntimeContextMessageContent(trimmedRuntimeContext),
|
||||
display: false,
|
||||
details: {
|
||||
source: "openclaw-runtime-context",
|
||||
|
|
@ -148,10 +130,7 @@ export function prependRuntimeContextForModel(
|
|||
const prepend = (text: string) =>
|
||||
text.startsWith(`${INTERNAL_RUNTIME_CONTEXT_BEGIN}\n`)
|
||||
? `${INTERNAL_RUNTIME_CONTEXT_BEGIN}\n${runtimeContext}\n\n${text.slice(INTERNAL_RUNTIME_CONTEXT_BEGIN.length + 1)}`
|
||||
: buildRuntimeContextMessageContent({
|
||||
runtimeContext: [runtimeContext, text].filter(Boolean).join("\n\n"),
|
||||
kind: "next-turn",
|
||||
});
|
||||
: buildRuntimeContextMessageContent([runtimeContext, text].filter(Boolean).join("\n\n"));
|
||||
if (carrier?.role !== "user") {
|
||||
return [
|
||||
...messages,
|
||||
|
|
|
|||
|
|
@ -131,7 +131,6 @@ function preparePromptProjectionStateForTest(params: {
|
|||
},
|
||||
replaceSessionMessages: () => {},
|
||||
sessionAgentId: "main",
|
||||
setActiveSessionSystemPrompt: () => {},
|
||||
systemPromptText: params.raw ? "" : "system",
|
||||
toolResultPromptProjectionState: params.state,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ import {
|
|||
publishCurrentModelGeneration,
|
||||
resetModelGenerationFixtureState,
|
||||
} from "../embedded-agent-runner/model.generation-scope.test-support.js";
|
||||
import { projectRuntimeContextFragments } from "../embedded-agent-runner/run/attempt-llm-boundary.js";
|
||||
import type {
|
||||
EmbeddedRunAttemptParams,
|
||||
EmbeddedRunAttemptResult,
|
||||
|
|
@ -641,7 +640,7 @@ describe("runAgentHarnessAttempt", () => {
|
|||
...currentInboundContext.fragments,
|
||||
{ kind: "heartbeat-outcome", text: expect.stringContaining("ISOLATED_OUTCOME_731") },
|
||||
]);
|
||||
expect(projectRuntimeContextFragments(fragments ?? [])).toContain("ISOLATED_OUTCOME_731");
|
||||
expect(JSON.stringify(fragments)).toContain("ISOLATED_OUTCOME_731");
|
||||
expect(received?.prompt).toBe("hello");
|
||||
expect(params.currentInboundContext).toEqual(currentInboundContext);
|
||||
expect(currentInboundContext.text).toBe("Current quoted reply");
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import {
|
|||
INTERNAL_RUNTIME_CONTEXT_END,
|
||||
OPENCLAW_RUNTIME_CONTEXT_CUSTOM_TYPE,
|
||||
OPENCLAW_RUNTIME_CONTEXT_NOTICE,
|
||||
OPENCLAW_RUNTIME_EVENT_HEADER,
|
||||
relocateCurrentRuntimeContextCarrierToTail,
|
||||
stripInternalRuntimeContext,
|
||||
} from "./internal-runtime-context.js";
|
||||
|
|
@ -126,7 +125,7 @@ describe("internal runtime context codec", () => {
|
|||
"previous current turn",
|
||||
"OpenClaw runtime context for the immediately preceding user message.",
|
||||
],
|
||||
["runtime event", OPENCLAW_RUNTIME_EVENT_HEADER],
|
||||
["runtime event", "OpenClaw runtime event."],
|
||||
])("detects and strips the %s prompt preface", (_name, header) => {
|
||||
const preface = [header, OPENCLAW_RUNTIME_CONTEXT_NOTICE].join("\n");
|
||||
const input = [
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ const ESCAPED_INTERNAL_RUNTIME_CONTEXT_END = "[[OPENCLAW_INTERNAL_CONTEXT_END]]"
|
|||
/** Notice inserted into runtime-generated context blocks. */
|
||||
export const OPENCLAW_RUNTIME_CONTEXT_NOTICE =
|
||||
"This context is runtime-generated, not user-authored. Keep internal details private.";
|
||||
/** Header for runtime events passed as prompt context. */
|
||||
export const OPENCLAW_RUNTIME_EVENT_HEADER = "OpenClaw runtime event.";
|
||||
/** Custom message type used for structured runtime-context messages. */
|
||||
export const OPENCLAW_RUNTIME_CONTEXT_CUSTOM_TYPE = "openclaw.runtime-context";
|
||||
|
||||
|
|
@ -215,7 +213,7 @@ function stripLegacyInternalRuntimeContext(text: string): string {
|
|||
const RUNTIME_CONTEXT_PROMPT_HEADERS: readonly string[] = [
|
||||
"OpenClaw runtime context for the active user request in this turn. Do not reply to or describe this context. Use it to continue answering the active user request now. Do not wait for another message.",
|
||||
"OpenClaw runtime context for the immediately preceding user message.",
|
||||
OPENCLAW_RUNTIME_EVENT_HEADER,
|
||||
"OpenClaw runtime event.",
|
||||
];
|
||||
|
||||
const RUNTIME_CONTEXT_NOTICE_PATTERN = new RegExp(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue