openclaw / src /plugins /runtime /runtime-llm-diagnostics.runtime.test.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
4c76b0d verified
Raw
History Blame Contribute Delete
8.78 kB
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import {
onTrustedInternalDiagnosticEvent,
resetDiagnosticEventsForTest,
type DiagnosticEventPayload,
} from "../../infra/diagnostic-events.js";
import { markTrustedOtelDiagnosticListener } from "../../infra/diagnostic-otel-listener-provenance.js";
import { createRuntimeLlm } from "./runtime-llm.runtime.js";
const hoisted = vi.hoisted(() => ({
acquireSimpleCompletionModelForAgent:
vi.fn<
typeof import("../../agents/simple-completion-runtime.js").acquireSimpleCompletionModelForAgent
>(),
completeWithPreparedSimpleCompletionModel: vi.fn(),
resolveSimpleCompletionSelectionForAgent: vi.fn(),
}));
vi.mock("../../agents/simple-completion-runtime.js", () => ({
acquireSimpleCompletionModelForAgent: hoisted.acquireSimpleCompletionModelForAgent,
completeWithPreparedSimpleCompletionModel: hoisted.completeWithPreparedSimpleCompletionModel,
resolveSimpleCompletionSelectionForAgent: hoisted.resolveSimpleCompletionSelectionForAgent,
}));
const cfg = {
agents: {
defaults: {
model: "openai/gpt-5.5",
},
},
} satisfies OpenClawConfig;
const preparedModel = {
async [Symbol.asyncDispose]() {},
selection: {
provider: "openai",
modelId: "gpt-5.5",
agentDir: "/tmp/openclaw-agent",
},
model: {
provider: "openai",
id: "gpt-5.5",
name: "gpt-5.5",
api: "openai",
baseUrl: "https://fixture.invalid/v1",
input: ["text"],
reasoning: false,
contextWindow: 128_000,
maxTokens: 4096,
cost: { input: 1, output: 2, cacheRead: 0.1, cacheWrite: 0.2 },
},
auth: {
apiKey: "test-api-key",
source: "test",
mode: "api-key",
},
} satisfies Extract<
Awaited<ReturnType<typeof hoisted.acquireSimpleCompletionModelForAgent>>,
{ model: unknown }
>;
function captureUsageEvents() {
const events: Array<{
event: Extract<DiagnosticEventPayload, { type: "model.usage" }>;
hostPluginId?: string;
internal?: boolean;
trusted: boolean;
}> = [];
const stop = onTrustedInternalDiagnosticEvent(
markTrustedOtelDiagnosticListener((event, metadata, privateData) => {
if (event.type === "model.usage") {
events.push({
event,
hostPluginId: (privateData as { hostPluginId?: string }).hostPluginId,
internal: metadata.internal,
trusted: metadata.trusted,
});
}
}),
);
return { events, stop };
}
describe("runtime.llm.complete diagnostics", () => {
beforeEach(() => {
resetDiagnosticEventsForTest();
hoisted.acquireSimpleCompletionModelForAgent.mockReset();
hoisted.completeWithPreparedSimpleCompletionModel.mockReset();
hoisted.resolveSimpleCompletionSelectionForAgent.mockReset();
hoisted.acquireSimpleCompletionModelForAgent.mockResolvedValue(preparedModel);
hoisted.resolveSimpleCompletionSelectionForAgent.mockReturnValue(preparedModel.selection);
hoisted.completeWithPreparedSimpleCompletionModel.mockResolvedValue({
content: [{ type: "text", text: "done" }],
usage: {
input: 11,
output: 7,
cacheRead: 5,
cacheWrite: 2,
total: 25,
cost: { total: 0.0042 },
},
stopReason: "stop",
});
});
it("emits one trusted usage event using only host-owned plugin identity", async () => {
const usageEvents = captureUsageEvents();
const llm = createRuntimeLlm({
getConfig: () => cfg,
authority: {
caller: { kind: "host", id: "runtime-test" },
pluginIdForPolicy: "trusted-plugin",
allowComplete: true,
},
});
const result = await llm.complete({
messages: [{ role: "user", content: "Ping" }],
purpose: "test-purpose",
caller: { kind: "plugin", id: "spoofed-plugin" },
pluginId: "spoofed-plugin",
telemetry: { pluginId: "nested-spoofed-plugin" },
} as Parameters<typeof llm.complete>[0] & {
caller: unknown;
pluginId: string;
telemetry: { pluginId: string };
});
usageEvents.stop();
expect(result.execution).toEqual({
mode: "direct-provider",
owner: { kind: "provider", id: "openai" },
});
expect(result.audit).toEqual({
caller: { kind: "host", id: "runtime-test" },
purpose: "test-purpose",
});
expect(usageEvents.events).toEqual([
{
trusted: true,
hostPluginId: "trusted-plugin",
internal: true,
event: expect.objectContaining({
type: "model.usage",
agentId: "main",
provider: "openai",
model: "gpt-5.5",
usage: {
input: 11,
output: 7,
cacheRead: 5,
cacheWrite: 2,
promptTokens: 18,
total: 25,
},
costUsd: 0.0042,
}),
},
]);
});
it.each([
["absent", undefined, true, undefined, undefined],
[
"all-zero",
{ input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
true,
undefined,
undefined,
],
["reasoning-only", { reasoningTokens: 7 }, true, undefined, undefined],
[
"unavailable context usage",
{ contextUsage: { state: "unavailable" } },
true,
undefined,
undefined,
],
[
"input-only",
{ input: 4 },
true,
{ input: 4, output: 0, cacheRead: 0, cacheWrite: 0, promptTokens: 4, total: 4 },
undefined,
],
[
"cache-only",
{ cacheRead: 9 },
true,
{ input: 0, output: 0, cacheRead: 9, cacheWrite: 0, promptTokens: 9, total: 9 },
undefined,
],
[
"positive explicit cost-only",
{ cost: { total: 0.0042 } },
true,
{ input: 0, output: 0, cacheRead: 0, cacheWrite: 0, promptTokens: 0, total: 0 },
0.0042,
],
["zero explicit cost-only", { cost: { total: 0 } }, true, undefined, undefined],
["disabled", { input: 1 }, false, undefined, undefined],
] as const)(
"emits usage only for positive enabled tokens or cost: %s",
async (_name, rawUsage, enabled, expectedEventUsage, expectedCostUsd) => {
hoisted.completeWithPreparedSimpleCompletionModel.mockResolvedValueOnce({
content: [{ type: "text", text: "done" }],
usage: rawUsage,
stopReason: "stop",
});
const usageEvents = captureUsageEvents();
const llm = createRuntimeLlm({
getConfig: () => (enabled ? cfg : { ...cfg, diagnostics: { enabled: false } }),
authority: { allowComplete: true, pluginIdForPolicy: "trusted-plugin" },
});
await llm.complete({ messages: [{ role: "user", content: "Ping" }] });
usageEvents.stop();
if (expectedEventUsage) {
expect(usageEvents.events).toEqual([
{
trusted: true,
hostPluginId: "trusted-plugin",
internal: true,
event: expect.objectContaining({
usage: expectedEventUsage,
...(expectedCostUsd !== undefined ? { costUsd: expectedCostUsd } : {}),
}),
},
]);
} else {
expect(usageEvents.events).toHaveLength(0);
}
},
);
it.each([
["resolved provider error", "error", [{ type: "text", text: "partial" }], "partial"],
["resolved provider abort", "aborted", [{ type: "text", text: "partial" }], "partial"],
["thinking-only completion", "stop", [{ type: "thinking", thinking: "hidden" }], ""],
] as const)("keeps %s usage silent", async (_name, stopReason, content, expectedText) => {
hoisted.completeWithPreparedSimpleCompletionModel.mockResolvedValueOnce({
content,
stopReason,
usage: { input: 11, output: 7, totalTokens: 18 },
});
const usageEvents = captureUsageEvents();
const llm = createRuntimeLlm({
getConfig: () => cfg,
authority: { allowComplete: true, pluginIdForPolicy: "trusted-plugin" },
});
await expect(
llm.complete({ messages: [{ role: "user", content: "Ping" }] }),
).resolves.toMatchObject({ text: expectedText });
usageEvents.stop();
expect(usageEvents.events).toEqual([]);
});
it("emits no usage when the provider fails", async () => {
const usageEvents = captureUsageEvents();
hoisted.completeWithPreparedSimpleCompletionModel.mockRejectedValueOnce(
new Error("provider failed"),
);
const llm = createRuntimeLlm({
getConfig: () => cfg,
authority: { allowComplete: true },
});
await expect(llm.complete({ messages: [{ role: "user", content: "Ping" }] })).rejects.toThrow(
"provider failed",
);
usageEvents.stop();
expect(usageEvents.events).toHaveLength(0);
});
});