mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 00:31:24 +00:00
refactor(test): dedupe agent harnesses and routing fixtures
This commit is contained in:
@@ -85,6 +85,42 @@ function makeUser(text: string): AgentMessage {
|
||||
return { role: "user", content: text, timestamp: Date.now() };
|
||||
}
|
||||
|
||||
type ContextPruningSettings = NonNullable<ReturnType<typeof computeEffectiveSettings>>;
|
||||
type PruneArgs = Parameters<typeof pruneContextMessages>[0];
|
||||
type PruneOverrides = Omit<PruneArgs, "messages" | "settings" | "ctx">;
|
||||
|
||||
const CONTEXT_WINDOW_1000 = {
|
||||
model: { contextWindow: 1000 },
|
||||
} as unknown as ExtensionContext;
|
||||
|
||||
function makeAggressiveSettings(
|
||||
overrides: Partial<ContextPruningSettings> = {},
|
||||
): ContextPruningSettings {
|
||||
return {
|
||||
...DEFAULT_CONTEXT_PRUNING_SETTINGS,
|
||||
keepLastAssistants: 0,
|
||||
softTrimRatio: 0,
|
||||
hardClearRatio: 0,
|
||||
minPrunableToolChars: 0,
|
||||
hardClear: { enabled: true, placeholder: "[cleared]" },
|
||||
softTrim: { maxChars: 10, headChars: 3, tailChars: 3 },
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function pruneWithAggressiveDefaults(
|
||||
messages: AgentMessage[],
|
||||
settingsOverrides: Partial<ContextPruningSettings> = {},
|
||||
extra: PruneOverrides = {},
|
||||
): AgentMessage[] {
|
||||
return pruneContextMessages({
|
||||
messages,
|
||||
settings: makeAggressiveSettings(settingsOverrides),
|
||||
ctx: CONTEXT_WINDOW_1000,
|
||||
...extra,
|
||||
});
|
||||
}
|
||||
|
||||
type ContextHandler = (
|
||||
event: { messages: AgentMessage[] },
|
||||
ctx: ExtensionContext,
|
||||
@@ -157,21 +193,7 @@ describe("context-pruning", () => {
|
||||
}),
|
||||
];
|
||||
|
||||
const settings = {
|
||||
...DEFAULT_CONTEXT_PRUNING_SETTINGS,
|
||||
keepLastAssistants: 3,
|
||||
softTrimRatio: 0.0,
|
||||
hardClearRatio: 0.0,
|
||||
minPrunableToolChars: 0,
|
||||
hardClear: { enabled: true, placeholder: "[cleared]" },
|
||||
softTrim: { maxChars: 10, headChars: 3, tailChars: 3 },
|
||||
};
|
||||
|
||||
const ctx = {
|
||||
model: { contextWindow: 1000 },
|
||||
} as unknown as ExtensionContext;
|
||||
|
||||
const next = pruneContextMessages({ messages, settings, ctx });
|
||||
const next = pruneWithAggressiveDefaults(messages, { keepLastAssistants: 3 });
|
||||
|
||||
expect(toolText(findToolResult(next, "t2"))).toContain("y".repeat(20_000));
|
||||
expect(toolText(findToolResult(next, "t3"))).toContain("z".repeat(20_000));
|
||||
@@ -180,16 +202,6 @@ describe("context-pruning", () => {
|
||||
});
|
||||
|
||||
it("never prunes tool results before the first user message", () => {
|
||||
const settings = {
|
||||
...DEFAULT_CONTEXT_PRUNING_SETTINGS,
|
||||
keepLastAssistants: 0,
|
||||
softTrimRatio: 0.0,
|
||||
hardClearRatio: 0.0,
|
||||
minPrunableToolChars: 0,
|
||||
hardClear: { enabled: true, placeholder: "[cleared]" },
|
||||
softTrim: { maxChars: 10, headChars: 3, tailChars: 3 },
|
||||
};
|
||||
|
||||
const messages: AgentMessage[] = [
|
||||
makeAssistant("bootstrap tool calls"),
|
||||
makeToolResult({
|
||||
@@ -206,13 +218,14 @@ describe("context-pruning", () => {
|
||||
}),
|
||||
];
|
||||
|
||||
const next = pruneContextMessages({
|
||||
const next = pruneWithAggressiveDefaults(
|
||||
messages,
|
||||
settings,
|
||||
ctx: { model: { contextWindow: 1000 } } as unknown as ExtensionContext,
|
||||
isToolPrunable: () => true,
|
||||
contextWindowTokensOverride: 1000,
|
||||
});
|
||||
{},
|
||||
{
|
||||
isToolPrunable: () => true,
|
||||
contextWindowTokensOverride: 1000,
|
||||
},
|
||||
);
|
||||
|
||||
expect(toolText(findToolResult(next, "t0"))).toBe("x".repeat(20_000));
|
||||
expect(toolText(findToolResult(next, "t1"))).toBe("[cleared]");
|
||||
@@ -241,19 +254,11 @@ describe("context-pruning", () => {
|
||||
}),
|
||||
];
|
||||
|
||||
const settings = {
|
||||
...DEFAULT_CONTEXT_PRUNING_SETTINGS,
|
||||
const next = pruneWithAggressiveDefaults(messages, {
|
||||
keepLastAssistants: 1,
|
||||
softTrimRatio: 10.0,
|
||||
hardClearRatio: 0.0,
|
||||
minPrunableToolChars: 0,
|
||||
hardClear: { enabled: true, placeholder: "[cleared]" },
|
||||
};
|
||||
|
||||
const ctx = {
|
||||
model: { contextWindow: 1000 },
|
||||
} as unknown as ExtensionContext;
|
||||
const next = pruneContextMessages({ messages, settings, ctx });
|
||||
softTrim: DEFAULT_CONTEXT_PRUNING_SETTINGS.softTrim,
|
||||
});
|
||||
|
||||
expect(toolText(findToolResult(next, "t1"))).toBe("[cleared]");
|
||||
expect(toolText(findToolResult(next, "t2"))).toBe("[cleared]");
|
||||
@@ -273,19 +278,9 @@ describe("context-pruning", () => {
|
||||
makeAssistant("a2"),
|
||||
];
|
||||
|
||||
const settings = {
|
||||
...DEFAULT_CONTEXT_PRUNING_SETTINGS,
|
||||
keepLastAssistants: 0,
|
||||
softTrimRatio: 0,
|
||||
hardClearRatio: 0,
|
||||
minPrunableToolChars: 0,
|
||||
hardClear: { enabled: true, placeholder: "[cleared]" },
|
||||
softTrim: { maxChars: 10, headChars: 3, tailChars: 3 },
|
||||
};
|
||||
|
||||
const next = pruneContextMessages({
|
||||
messages,
|
||||
settings,
|
||||
settings: makeAggressiveSettings(),
|
||||
ctx: { model: undefined } as unknown as ExtensionContext,
|
||||
contextWindowTokensOverride: 1000,
|
||||
});
|
||||
@@ -297,15 +292,7 @@ describe("context-pruning", () => {
|
||||
const sessionManager = {};
|
||||
|
||||
setContextPruningRuntime(sessionManager, {
|
||||
settings: {
|
||||
...DEFAULT_CONTEXT_PRUNING_SETTINGS,
|
||||
keepLastAssistants: 0,
|
||||
softTrimRatio: 0,
|
||||
hardClearRatio: 0,
|
||||
minPrunableToolChars: 0,
|
||||
hardClear: { enabled: true, placeholder: "[cleared]" },
|
||||
softTrim: { maxChars: 10, headChars: 3, tailChars: 3 },
|
||||
},
|
||||
settings: makeAggressiveSettings(),
|
||||
contextWindowTokens: 1000,
|
||||
isToolPrunable: () => true,
|
||||
lastCacheTouchAt: Date.now() - DEFAULT_CONTEXT_PRUNING_SETTINGS.ttlMs - 1000,
|
||||
@@ -336,15 +323,7 @@ describe("context-pruning", () => {
|
||||
const lastTouch = Date.now() - DEFAULT_CONTEXT_PRUNING_SETTINGS.ttlMs - 1000;
|
||||
|
||||
setContextPruningRuntime(sessionManager, {
|
||||
settings: {
|
||||
...DEFAULT_CONTEXT_PRUNING_SETTINGS,
|
||||
keepLastAssistants: 0,
|
||||
softTrimRatio: 0,
|
||||
hardClearRatio: 0,
|
||||
minPrunableToolChars: 0,
|
||||
hardClear: { enabled: true, placeholder: "[cleared]" },
|
||||
softTrim: { maxChars: 10, headChars: 3, tailChars: 3 },
|
||||
},
|
||||
settings: makeAggressiveSettings(),
|
||||
contextWindowTokens: 1000,
|
||||
isToolPrunable: () => true,
|
||||
lastCacheTouchAt: lastTouch,
|
||||
@@ -392,21 +371,9 @@ describe("context-pruning", () => {
|
||||
}),
|
||||
];
|
||||
|
||||
const settings = {
|
||||
...DEFAULT_CONTEXT_PRUNING_SETTINGS,
|
||||
keepLastAssistants: 0,
|
||||
softTrimRatio: 0.0,
|
||||
hardClearRatio: 0.0,
|
||||
minPrunableToolChars: 0,
|
||||
const next = pruneWithAggressiveDefaults(messages, {
|
||||
tools: { allow: ["ex*"], deny: ["exec"] },
|
||||
hardClear: { enabled: true, placeholder: "[cleared]" },
|
||||
softTrim: { maxChars: 10, headChars: 3, tailChars: 3 },
|
||||
};
|
||||
|
||||
const ctx = {
|
||||
model: { contextWindow: 1000 },
|
||||
} as unknown as ExtensionContext;
|
||||
const next = pruneContextMessages({ messages, settings, ctx });
|
||||
});
|
||||
|
||||
// Deny wins => exec is not pruned, even though allow matches.
|
||||
expect(toolText(findToolResult(next, "t1"))).toContain("x".repeat(20_000));
|
||||
@@ -424,20 +391,7 @@ describe("context-pruning", () => {
|
||||
}),
|
||||
];
|
||||
|
||||
const settings = {
|
||||
...DEFAULT_CONTEXT_PRUNING_SETTINGS,
|
||||
keepLastAssistants: 0,
|
||||
softTrimRatio: 0.0,
|
||||
hardClearRatio: 0.0,
|
||||
minPrunableToolChars: 0,
|
||||
hardClear: { enabled: true, placeholder: "[cleared]" },
|
||||
softTrim: { maxChars: 10, headChars: 3, tailChars: 3 },
|
||||
};
|
||||
|
||||
const ctx = {
|
||||
model: { contextWindow: 1000 },
|
||||
} as unknown as ExtensionContext;
|
||||
const next = pruneContextMessages({ messages, settings, ctx });
|
||||
const next = pruneWithAggressiveDefaults(messages);
|
||||
|
||||
const tool = findToolResult(next, "t1");
|
||||
if (!tool || tool.role !== "toolResult") {
|
||||
@@ -463,18 +417,10 @@ describe("context-pruning", () => {
|
||||
} as unknown as AgentMessage,
|
||||
];
|
||||
|
||||
const settings = {
|
||||
...DEFAULT_CONTEXT_PRUNING_SETTINGS,
|
||||
keepLastAssistants: 0,
|
||||
softTrimRatio: 0.0,
|
||||
const next = pruneWithAggressiveDefaults(messages, {
|
||||
hardClearRatio: 10.0,
|
||||
softTrim: { maxChars: 5, headChars: 7, tailChars: 3 },
|
||||
};
|
||||
|
||||
const ctx = {
|
||||
model: { contextWindow: 1000 },
|
||||
} as unknown as ExtensionContext;
|
||||
const next = pruneContextMessages({ messages, settings, ctx });
|
||||
});
|
||||
|
||||
const text = toolText(findToolResult(next, "t1"));
|
||||
expect(text).toContain("AAAAA\nB");
|
||||
@@ -492,20 +438,10 @@ describe("context-pruning", () => {
|
||||
}),
|
||||
];
|
||||
|
||||
const settings = {
|
||||
...DEFAULT_CONTEXT_PRUNING_SETTINGS,
|
||||
keepLastAssistants: 0,
|
||||
softTrimRatio: 0.0,
|
||||
const next = pruneWithAggressiveDefaults(messages, {
|
||||
hardClearRatio: 10.0,
|
||||
minPrunableToolChars: 0,
|
||||
hardClear: { enabled: true, placeholder: "[cleared]" },
|
||||
softTrim: { maxChars: 10, headChars: 6, tailChars: 6 },
|
||||
};
|
||||
|
||||
const ctx = {
|
||||
model: { contextWindow: 1000 },
|
||||
} as unknown as ExtensionContext;
|
||||
const next = pruneContextMessages({ messages, settings, ctx });
|
||||
});
|
||||
|
||||
const tool = findToolResult(next, "t1");
|
||||
const text = toolText(tool);
|
||||
|
||||
Reference in New Issue
Block a user