mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 14:30:45 +00:00
fix: keep reply context out of image scanning (#76659)
This commit is contained in:
@@ -27,6 +27,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Gateway/update: run `doctor --non-interactive --fix` after Control UI global package updates before reporting success, so legacy config is migrated before the gateway restart. Thanks @stevenchouai.
|
||||
- Gateway/cron: stop a lazy cron startup that loses a hot-reload race, preventing the old cron service from starting after reload has already replaced cron state.
|
||||
- CLI/plugins: warn when npm plugin installs remain shadowed by a failing config-selected source and surface the repair path in `plugins doctor`. Thanks @LindalyX-Lee.
|
||||
- Agents/Telegram: preserve explicit reply and quote context in embedded model prompts without letting quoted text drive prompt-local image loading. Fixes #76419. (#76659) Thanks @cheechnd.
|
||||
- Active Memory: apply `setupGraceTimeoutMs` to the embedded recall runner as well as the outer prompt-build watchdog, so very-cold first recalls keep the configured setup grace end-to-end. (#74480) Thanks @volcano303.
|
||||
- CLI/config: keep JSON dry-run patches validating touched channel configuration against bundled channel schemas even when the patch only contains SecretRef objects.
|
||||
- Plugins/tools: keep disabled bundled tool plugins out of explicit runtime allowlist ownership and fall back from loaded-but-empty channel registries to tool-bearing plugin registries, so Active Memory can use bundled `memory-core` search/get tools even when `memory-lancedb` is disabled. Fixes #76603. Thanks @jwong-art.
|
||||
|
||||
@@ -128,6 +128,7 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => {
|
||||
resetEmbeddedAttemptHarness();
|
||||
clearMemoryPluginState();
|
||||
hoisted.runContextEngineMaintenanceMock.mockReset().mockResolvedValue(undefined);
|
||||
hoisted.detectAndLoadPromptImagesMock.mockClear();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -225,7 +226,7 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => {
|
||||
currentTurnContext: {
|
||||
reply: {
|
||||
senderLabel: "Mike",
|
||||
body: "WT daily plan — Sat May 2",
|
||||
body: "WT daily plan - Sat May 2\nSee ./quoted-secret.png and [media attached: media://inbound/quoted.png]",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -241,10 +242,16 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => {
|
||||
expect(seenPrompt).toContain("what does this mean?");
|
||||
expect(seenPrompt).toContain("Replied message (untrusted, for context):");
|
||||
expect(seenPrompt).toContain('"sender_label": "Mike"');
|
||||
expect(seenPrompt).toContain('"body": "WT daily plan — Sat May 2"');
|
||||
expect(seenPrompt).toContain("WT daily plan - Sat May 2");
|
||||
expect(seenPrompt).toContain("./quoted-secret.png");
|
||||
expect(seenPrompt).toContain("media://inbound/quoted.png");
|
||||
expect(seenPrompt).not.toContain("OPENCLAW_INTERNAL_CONTEXT");
|
||||
expect(seenPrompt).not.toContain("secret runtime context");
|
||||
expect(result.finalPromptText).toBe(seenPrompt);
|
||||
expect(hoisted.detectAndLoadPromptImagesMock).toHaveBeenCalledTimes(1);
|
||||
expect(hoisted.detectAndLoadPromptImagesMock.mock.calls[0]?.[0]).toMatchObject({
|
||||
prompt: "what does this mean?",
|
||||
});
|
||||
const trajectoryEvents = (
|
||||
await fs.readFile(path.join(tempPaths[0] ?? "", "session.trajectory.jsonl"), "utf8")
|
||||
)
|
||||
@@ -253,7 +260,7 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => {
|
||||
.map((line) => JSON.parse(line) as TrajectoryEvent);
|
||||
const promptSubmitted = trajectoryEvents.find((event) => event.type === "prompt.submitted");
|
||||
expect(promptSubmitted?.data?.prompt).toBe(seenPrompt);
|
||||
expect(promptSubmitted?.data?.prompt).toContain("WT daily plan — Sat May 2");
|
||||
expect(promptSubmitted?.data?.prompt).toContain("WT daily plan - Sat May 2");
|
||||
expect(promptSubmitted?.data?.prompt).not.toContain("secret runtime context");
|
||||
});
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ type AttemptSpawnWorkspaceHoisted = {
|
||||
getGlobalHookRunnerMock: Mock<() => unknown>;
|
||||
initializeGlobalHookRunnerMock: UnknownMock;
|
||||
runContextEngineMaintenanceMock: AsyncContextEngineMaintenanceMock;
|
||||
detectAndLoadPromptImagesMock: AsyncUnknownMock;
|
||||
getHistoryLimitFromSessionKeyMock: Mock<
|
||||
(sessionKey: string | undefined, config: unknown) => number | undefined
|
||||
>;
|
||||
@@ -148,6 +149,12 @@ const hoisted = vi.hoisted((): AttemptSpawnWorkspaceHoisted => {
|
||||
const getGlobalHookRunnerMock = vi.fn<() => unknown>(() => undefined);
|
||||
const initializeGlobalHookRunnerMock = vi.fn();
|
||||
const runContextEngineMaintenanceMock = vi.fn(async (_params?: unknown) => undefined);
|
||||
const detectAndLoadPromptImagesMock = vi.fn(async () => ({
|
||||
images: [],
|
||||
detectedRefs: [],
|
||||
loadedCount: 0,
|
||||
skippedCount: 0,
|
||||
}));
|
||||
const getHistoryLimitFromSessionKeyMock = vi.fn<
|
||||
(sessionKey: string | undefined, config: unknown) => number | undefined
|
||||
>(() => undefined);
|
||||
@@ -187,6 +194,7 @@ const hoisted = vi.hoisted((): AttemptSpawnWorkspaceHoisted => {
|
||||
getGlobalHookRunnerMock,
|
||||
initializeGlobalHookRunnerMock,
|
||||
runContextEngineMaintenanceMock,
|
||||
detectAndLoadPromptImagesMock,
|
||||
getHistoryLimitFromSessionKeyMock,
|
||||
limitHistoryTurnsMock,
|
||||
preemptiveCompactionCalls,
|
||||
@@ -386,7 +394,8 @@ vi.mock("../runs.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("./images.js", () => ({
|
||||
detectAndLoadPromptImages: async () => ({ images: [] }),
|
||||
detectAndLoadPromptImages: (...args: unknown[]) =>
|
||||
(hoisted.detectAndLoadPromptImagesMock as (...args: unknown[]) => unknown)(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../../system-prompt-params.js", () => ({
|
||||
|
||||
@@ -2811,7 +2811,7 @@ export async function runEmbeddedAttempt(
|
||||
// Detect and load images referenced in the visible prompt for vision-capable models.
|
||||
// Images are prompt-local only (pi-like behavior).
|
||||
const imageResult = await detectAndLoadPromptImages({
|
||||
prompt: promptForModel,
|
||||
prompt: promptSubmission.prompt,
|
||||
workspaceDir: effectiveWorkspace,
|
||||
model: params.model,
|
||||
existingImages: params.images,
|
||||
|
||||
Reference in New Issue
Block a user