mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 13:20:43 +00:00
fix(context-engine): honor assembled prompt authority
This commit is contained in:
@@ -322,6 +322,73 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("uses assembled context as the default precheck authority", async () => {
|
||||
let sawPrompt = false;
|
||||
const hugeHistory = "large raw history ".repeat(25_000);
|
||||
|
||||
const result = await createContextEngineAttemptRunner({
|
||||
contextEngine: createTestContextEngine({
|
||||
assemble: async () => ({
|
||||
messages: [
|
||||
{ role: "user", content: "small assembled context", timestamp: 1 },
|
||||
] as AgentMessage[],
|
||||
estimatedTokens: 8,
|
||||
}),
|
||||
}),
|
||||
sessionKey,
|
||||
tempPaths,
|
||||
sessionMessages: [{ role: "user", content: hugeHistory, timestamp: 1 }] as AgentMessage[],
|
||||
attemptOverrides: {
|
||||
contextTokenBudget: 500,
|
||||
},
|
||||
sessionPrompt: async (session) => {
|
||||
sawPrompt = true;
|
||||
session.messages = [
|
||||
...session.messages,
|
||||
{ role: "assistant", content: "done", timestamp: 2 },
|
||||
];
|
||||
},
|
||||
});
|
||||
|
||||
expect(sawPrompt).toBe(true);
|
||||
expect(result.promptError).toBeNull();
|
||||
expect(result.promptErrorSource).toBeNull();
|
||||
});
|
||||
|
||||
it("honors context engines that opt into preassembly overflow authority", async () => {
|
||||
let sawPrompt = false;
|
||||
const hugeHistory = "large raw history ".repeat(25_000);
|
||||
|
||||
const result = await createContextEngineAttemptRunner({
|
||||
contextEngine: createTestContextEngine({
|
||||
assemble: async () => ({
|
||||
messages: [
|
||||
{ role: "user", content: "small assembled context", timestamp: 1 },
|
||||
] as AgentMessage[],
|
||||
estimatedTokens: 8,
|
||||
promptAuthority: "preassembly_may_overflow",
|
||||
}),
|
||||
}),
|
||||
sessionKey,
|
||||
tempPaths,
|
||||
sessionMessages: [{ role: "user", content: hugeHistory, timestamp: 1 }] as AgentMessage[],
|
||||
attemptOverrides: {
|
||||
contextTokenBudget: 500,
|
||||
},
|
||||
sessionPrompt: async (session) => {
|
||||
sawPrompt = true;
|
||||
session.messages = [
|
||||
...session.messages,
|
||||
{ role: "assistant", content: "done", timestamp: 2 },
|
||||
];
|
||||
},
|
||||
});
|
||||
|
||||
expect(sawPrompt).toBe(false);
|
||||
expect(result.promptErrorSource).toBe("precheck");
|
||||
expect(result.preflightRecovery?.route).toBe("compact_only");
|
||||
});
|
||||
|
||||
it("keeps gateway model runs independent from agent context and session history", async () => {
|
||||
const bootstrap = vi.fn(async () => ({ bootstrapped: true }));
|
||||
const assemble = vi.fn(async ({ messages }: { messages: AgentMessage[] }) => ({
|
||||
|
||||
@@ -1527,6 +1527,7 @@ export async function runEmbeddedAttempt(
|
||||
}
|
||||
let prePromptMessageCount = activeSession.messages.length;
|
||||
let unwindowedContextEngineMessagesForPrecheck: AgentMessage[] | undefined;
|
||||
let contextEnginePromptAuthority: "assembled" | "preassembly_may_overflow" = "assembled";
|
||||
abortSessionForYield = () => {
|
||||
yieldAbortSettled = Promise.resolve(activeSession.abort());
|
||||
};
|
||||
@@ -2089,6 +2090,7 @@ export async function runEmbeddedAttempt(
|
||||
if (assembled.messages !== activeSession.messages) {
|
||||
activeSession.agent.state.messages = assembled.messages;
|
||||
}
|
||||
contextEnginePromptAuthority = assembled.promptAuthority ?? "assembled";
|
||||
if (assembled.systemPromptAddition) {
|
||||
systemPromptText = prependSystemPromptAddition({
|
||||
systemPrompt: systemPromptText,
|
||||
@@ -2760,7 +2762,9 @@ export async function runEmbeddedAttempt(
|
||||
|
||||
const preemptiveCompaction = shouldPreemptivelyCompactBeforePrompt({
|
||||
messages: activeSession.messages,
|
||||
unwindowedMessages: unwindowedContextEngineMessagesForPrecheck,
|
||||
...(contextEnginePromptAuthority === "preassembly_may_overflow"
|
||||
? { unwindowedMessages: unwindowedContextEngineMessagesForPrecheck }
|
||||
: {}),
|
||||
systemPrompt: systemPromptText,
|
||||
prompt: effectivePrompt,
|
||||
contextTokenBudget,
|
||||
|
||||
@@ -93,7 +93,7 @@ describe("preemptive-compaction", () => {
|
||||
expect(result.estimatedPromptTokens).toBeLessThan(result.promptBudgetBeforeReserve);
|
||||
});
|
||||
|
||||
it("uses the larger unwindowed message estimate when context engine assembly windows history", () => {
|
||||
it("uses the larger unwindowed message estimate when explicitly provided", () => {
|
||||
const result = shouldPreemptivelyCompactBeforePrompt({
|
||||
messages: [makeAssistantHistory("small assembled window")],
|
||||
unwindowedMessages: [makeAssistantHistory(verboseHistory.repeat(4))],
|
||||
|
||||
@@ -8,6 +8,11 @@ export type AssembleResult = {
|
||||
messages: AgentMessage[];
|
||||
/** Estimated total tokens in assembled context */
|
||||
estimatedTokens: number;
|
||||
/**
|
||||
* Declares whether the assembled messages are the authoritative prompt for
|
||||
* overflow prechecks. Defaults to "assembled".
|
||||
*/
|
||||
promptAuthority?: "assembled" | "preassembly_may_overflow";
|
||||
/** Optional context-engine-provided instructions prepended to the runtime system prompt */
|
||||
systemPromptAddition?: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user