Agents: cover model-aware context engine assembly

This commit is contained in:
Josh Lehman
2026-03-20 07:41:03 -07:00
parent 1eae2fdd32
commit d708ddb222
2 changed files with 37 additions and 4 deletions

View File

@@ -51,6 +51,7 @@ Docs: https://docs.openclaw.ai
- Web tools/Tavily: add Tavily as a bundled web-search provider with dedicated `tavily_search` and `tavily_extract` tools, using canonical plugin-owned config under `plugins.entries.tavily.config.webSearch.*`. (#49200) thanks @lakshyaag-tavily.
- Docs/plugins: add the community DingTalk plugin listing to the docs catalog. (#29913) Thanks @sliverp.
- Docs/plugins: add the community QQbot plugin listing to the docs catalog. (#29898) Thanks @sliverp.
- Plugins/context engines: pass the embedded runner `modelId` into context-engine `assemble()` so plugins can adapt context formatting per model. (#47437) thanks @jscianna.
### Fixes

View File

@@ -39,6 +39,7 @@ const hoisted = vi.hoisted(() => {
contextFiles: [],
}));
const getGlobalHookRunnerMock = vi.fn<() => unknown>(() => undefined);
const initializeGlobalHookRunnerMock = vi.fn();
const sessionManager = {
getLeafEntry: vi.fn(() => null),
branch: vi.fn(),
@@ -55,6 +56,7 @@ const hoisted = vi.hoisted(() => {
acquireSessionWriteLockMock,
resolveBootstrapContextForRunMock,
getGlobalHookRunnerMock,
initializeGlobalHookRunnerMock,
sessionManager,
};
});
@@ -94,6 +96,7 @@ vi.mock("../../pi-embedded-subscribe.js", () => ({
vi.mock("../../../plugins/hook-runner-global.js", () => ({
getGlobalHookRunner: hoisted.getGlobalHookRunnerMock,
initializeGlobalHookRunner: hoisted.initializeGlobalHookRunnerMock,
}));
vi.mock("../../../infra/machine-name.js", () => ({
@@ -216,6 +219,16 @@ vi.mock("../../cache-trace.js", () => ({
createCacheTrace: () => undefined,
}));
vi.mock("../../pi-tools.js", () => ({
createOpenClawCodingTools: () => [],
resolveToolLoopDetectionConfig: () => undefined,
}));
vi.mock("../../../image-generation/runtime.js", () => ({
generateImage: vi.fn(),
listRuntimeImageGenerationProviders: () => [],
}));
vi.mock("../../model-selection.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../model-selection.js")>();
@@ -346,10 +359,12 @@ function createDefaultEmbeddedSession(params?: {
function createContextEngineBootstrapAndAssemble() {
return {
bootstrap: vi.fn(async (_params: { sessionKey?: string }) => ({ bootstrapped: true })),
assemble: vi.fn(async ({ messages }: { messages: AgentMessage[]; sessionKey?: string }) => ({
messages,
estimatedTokens: 1,
})),
assemble: vi.fn(
async ({ messages }: { messages: AgentMessage[]; sessionKey?: string; model?: string }) => ({
messages,
estimatedTokens: 1,
}),
),
};
}
@@ -677,6 +692,7 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => {
sessionKey?: string;
messages: AgentMessage[];
tokenBudget?: number;
model?: string;
}) => Promise<AssembleResult>;
afterTurn?: (params: {
sessionId: string;
@@ -783,6 +799,22 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => {
expectCalledWithSessionKey(afterTurn, sessionKey);
});
it("forwards modelId to assemble", async () => {
const { bootstrap, assemble } = createContextEngineBootstrapAndAssemble();
const result = await runAttemptWithContextEngine({
bootstrap,
assemble,
});
expect(result.promptError).toBeNull();
expect(assemble).toHaveBeenCalledWith(
expect.objectContaining({
model: "gpt-test",
}),
);
});
it("forwards sessionKey to ingestBatch when afterTurn is absent", async () => {
const { bootstrap, assemble } = createContextEngineBootstrapAndAssemble();
const ingestBatch = vi.fn(