mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-07 10:34:44 +00:00
fix(harness): satisfy lifecycle lint gates
This commit is contained in:
@@ -1101,12 +1101,12 @@ export async function runCodexAppServerAttempt(
|
||||
};
|
||||
};
|
||||
let promptBuild = await buildPromptFromCurrentInputs();
|
||||
const decorateCodexTurnPromptText = (promptBuild: {
|
||||
const decorateCodexTurnPromptText = (promptBuildResult: {
|
||||
prompt: string;
|
||||
promptInputRange?: { start: number; end: number };
|
||||
}) => {
|
||||
const turnPromptText = prependCodexOpenClawPromptContext(
|
||||
promptBuild.prompt,
|
||||
promptBuildResult.prompt,
|
||||
openClawPromptContext,
|
||||
{
|
||||
preservePromptWithoutContext:
|
||||
@@ -1115,19 +1115,19 @@ export async function runCodexAppServerAttempt(
|
||||
},
|
||||
);
|
||||
const projectedRanges = resolveShiftedPromptContextRange(
|
||||
promptBuild.prompt,
|
||||
promptBuild.promptInputRange,
|
||||
promptBuildResult.prompt,
|
||||
promptBuildResult.promptInputRange,
|
||||
turnPromptText,
|
||||
);
|
||||
const preservedRange =
|
||||
resolveShiftedPromptInputRange(
|
||||
promptBuild.prompt,
|
||||
promptBuild.promptInputRange,
|
||||
promptBuildResult.prompt,
|
||||
promptBuildResult.promptInputRange,
|
||||
turnPromptText,
|
||||
) ??
|
||||
resolveCodexDeliveryHintPreservedInputRange({
|
||||
prompt: promptBuild.prompt,
|
||||
promptInputRange: promptBuild.promptInputRange,
|
||||
prompt: promptBuildResult.prompt,
|
||||
promptInputRange: promptBuildResult.promptInputRange,
|
||||
decoratedPrompt: turnPromptText,
|
||||
});
|
||||
return fitCodexProjectedContextForTurnStart({
|
||||
|
||||
@@ -1540,7 +1540,7 @@ describe("createCopilotAgentHarness", () => {
|
||||
await harness.runAttempt(makeCompactParams());
|
||||
const result = await harness.compact?.(makeCompactParams());
|
||||
|
||||
expect(pool.acquire).not.toHaveBeenCalled();
|
||||
expect(pool.acquire.mock.calls).toHaveLength(0);
|
||||
expect(result).toEqual({
|
||||
ok: false,
|
||||
compacted: false,
|
||||
|
||||
@@ -642,10 +642,10 @@ export function createCopilotAgentHarness(
|
||||
cleanup: Promise<DeferredCompactionCleanupOutcome>;
|
||||
sdkSessionId: string;
|
||||
}) => {
|
||||
const tracked = trackedSessions.get(openclawSessionId);
|
||||
const stored = lookupStoredBinding(options?.sessionStore, openclawSessionId);
|
||||
const ownsTrackedSession = tracked?.sdkSessionId === sdkSessionId;
|
||||
const ownsStoredSession = stored?.sdkSessionId === sdkSessionId;
|
||||
const trackedBinding = trackedSessions.get(openclawSessionId);
|
||||
const storedBinding = lookupStoredBinding(options?.sessionStore, openclawSessionId);
|
||||
const ownsTrackedSession = trackedBinding?.sdkSessionId === sdkSessionId;
|
||||
const ownsStoredSession = storedBinding?.sdkSessionId === sdkSessionId;
|
||||
if (!ownsTrackedSession && !ownsStoredSession) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -108,6 +108,12 @@ function flushAsync() {
|
||||
return tick().then(tick).then(tick);
|
||||
}
|
||||
|
||||
function waitForEventLoopTurn(): Promise<void> {
|
||||
return new Promise<void>((resolve) => {
|
||||
setImmediate(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function getPromptErrorCode(result: AgentHarnessAttemptResult): string | undefined {
|
||||
return (result.promptError as { code?: string } | undefined)?.code;
|
||||
}
|
||||
@@ -343,7 +349,7 @@ describe("runCopilotAttempt", () => {
|
||||
createToolBridge,
|
||||
pool: makeFakePool(sdk),
|
||||
});
|
||||
await new Promise<void>((resolve) => setImmediate(resolve));
|
||||
await waitForEventLoopTurn();
|
||||
|
||||
expect(beforePromptBuild).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ prompt: "hello" }),
|
||||
@@ -499,7 +505,7 @@ describe("runCopilotAttempt", () => {
|
||||
expect(sdk.sessions[0]?.rpc.history.cancelBackgroundCompaction).toHaveBeenCalledTimes(1);
|
||||
expect(sdk.sessions[0]?.disconnect).toHaveBeenCalledTimes(1);
|
||||
expect(sdk.client.deleteSession).toHaveBeenCalledWith("sess-1");
|
||||
expect(pool.release).toHaveBeenCalledTimes(1);
|
||||
expect(pool.release.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("cancels retained compaction when the caller aborts after a turn result", async () => {
|
||||
@@ -602,7 +608,7 @@ describe("runCopilotAttempt", () => {
|
||||
await runCopilotAttempt(makeParams({ hooksConfig: { onUserPromptSubmitted } } as never), {
|
||||
pool: makeFakePool(sdk),
|
||||
});
|
||||
await new Promise<void>((resolve) => setImmediate(resolve));
|
||||
await waitForEventLoopTurn();
|
||||
|
||||
expect(onUserPromptSubmitted).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ prompt: "hello" }),
|
||||
@@ -668,7 +674,7 @@ describe("runCopilotAttempt", () => {
|
||||
pool: makeFakePool(sdk),
|
||||
},
|
||||
);
|
||||
await new Promise<void>((resolve) => setImmediate(resolve));
|
||||
await waitForEventLoopTurn();
|
||||
|
||||
expect(result.aborted).toBe(true);
|
||||
expect(sdk.sessions[0]?.sendAndWait).not.toHaveBeenCalled();
|
||||
@@ -695,7 +701,7 @@ describe("runCopilotAttempt", () => {
|
||||
settled = true;
|
||||
return result;
|
||||
});
|
||||
await new Promise<void>((resolve) => setImmediate(resolve));
|
||||
await waitForEventLoopTurn();
|
||||
|
||||
expect(agentEnd).toHaveBeenCalledTimes(1);
|
||||
expect(settled).toBe(false);
|
||||
@@ -1935,7 +1941,7 @@ describe("runCopilotAttempt", () => {
|
||||
expect(sdk.sessions[0]?.rpc.history.cancelBackgroundCompaction).toHaveBeenCalledTimes(1);
|
||||
expect(sdk.sessions[0]?.disconnect).toHaveBeenCalledTimes(1);
|
||||
expect(sdk.client.deleteSession).toHaveBeenCalledWith("sess-1");
|
||||
expect(pool.release).toHaveBeenCalledTimes(1);
|
||||
expect(pool.release.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("cancels deferred cleanup when the timed-out caller aborts", async () => {
|
||||
|
||||
@@ -723,22 +723,22 @@ export async function runCopilotAttempt(
|
||||
}
|
||||
bridge = attachEventBridge(session, {
|
||||
onAssistantDelta: input.onAssistantDelta,
|
||||
onCompactionStart: () => {
|
||||
onCompactionStart: async () => {
|
||||
const sessionFile = readString(input.sessionFile);
|
||||
if (!sessionFile) {
|
||||
return;
|
||||
}
|
||||
return runAgentHarnessBeforeCompactionHook({
|
||||
await runAgentHarnessBeforeCompactionHook({
|
||||
sessionFile,
|
||||
ctx: hookContext,
|
||||
});
|
||||
},
|
||||
onCompactionComplete: ({ messagesRemoved, success }) => {
|
||||
onCompactionComplete: async ({ messagesRemoved, success }) => {
|
||||
const sessionFile = readString(input.sessionFile);
|
||||
if (!success || !sessionFile) {
|
||||
return;
|
||||
}
|
||||
return runAgentHarnessAfterCompactionHook({
|
||||
await runAgentHarnessAfterCompactionHook({
|
||||
sessionFile,
|
||||
compactedCount: messagesRemoved ?? -1,
|
||||
ctx: hookContext,
|
||||
|
||||
@@ -263,12 +263,7 @@ export function attachEventBridge(
|
||||
return compactionChain;
|
||||
},
|
||||
async awaitCompactionCompletion() {
|
||||
// Background compaction can outlive session.idle. Keep the observer
|
||||
// attached until its completion callback has run before releasing the session.
|
||||
while (activeCompactionCount > 0) {
|
||||
await compactionIdle;
|
||||
}
|
||||
await compactionChain;
|
||||
await awaitStableCompaction();
|
||||
},
|
||||
awaitSessionIdle() {
|
||||
return observedSessionIdle ? Promise.resolve() : sessionIdle;
|
||||
@@ -338,6 +333,20 @@ export function attachEventBridge(
|
||||
const queued = compactionChain.then(callback, callback);
|
||||
compactionChain = queued.catch(() => undefined);
|
||||
}
|
||||
|
||||
async function awaitStableCompaction(): Promise<void> {
|
||||
const idle = activeCompactionCount > 0 ? compactionIdle : undefined;
|
||||
if (idle) {
|
||||
await idle;
|
||||
}
|
||||
const callbacks = compactionChain;
|
||||
await callbacks;
|
||||
// Compaction events can arrive while an earlier hook callback settles.
|
||||
// Recheck both queues before teardown so the root observer stays attached.
|
||||
if (activeCompactionCount > 0 || compactionChain !== callbacks) {
|
||||
await awaitStableCompaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildAssistantMessage(params: {
|
||||
|
||||
@@ -424,7 +424,7 @@ export function convertOpenClawToolToSdkTool(
|
||||
};
|
||||
const notifyToolCompleted = (completion: CopilotToolCompletion) => {
|
||||
try {
|
||||
void Promise.resolve(ctx.onToolCompleted?.(completion)).catch((error) => {
|
||||
void Promise.resolve(ctx.onToolCompleted?.(completion)).catch((error: unknown) => {
|
||||
console.warn("[copilot-tool-bridge] onToolCompleted handler threw; continuing", error);
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user