oc-e35: restore explicit multi-agent UI ownership (#122889)

This commit is contained in:
Josh Lehman
2026-08-12 20:17:13 -07:00
committed by GitHub
parent aba94bbe0b
commit edb941a508
15 changed files with 198 additions and 30 deletions
@@ -37,6 +37,7 @@ function ingressDiagnosticChannel(opts: AgentCommandIngressOpts): string {
export function emitIngressModelUsageDiagnostic(
result: AgentCommandResult,
opts: AgentCommandIngressOpts,
agentDir: string,
): void {
const cfg = getRuntimeConfig();
if (!isDiagnosticsEnabled(cfg)) {
@@ -65,6 +66,7 @@ export function emitIngressModelUsageDiagnostic(
provider: providerUsed,
model: modelUsed,
config: cfg,
agentDir,
});
const costUsd = hasBillableUsageBuckets
? estimateUsageCost({ usage, cost: costConfig })
+1
View File
@@ -146,6 +146,7 @@ export async function finalizeEmbeddedAgentCommand(params: {
const { updateSessionStoreAfterAgentRun } = await loadSessionStoreRuntime();
await updateSessionStoreAfterAgentRun({
cfg,
agentDir,
contextTokensOverride: agentCfg?.contextTokens,
sessionId: effectiveSessionId,
sessionKey,
+74 -2
View File
@@ -19,7 +19,7 @@ import {
persistCliSessionForkSuccessorInStore,
restoreCliSessionForkInStore,
recordCliCompactionInStore,
updateSessionStoreAfterAgentRun,
updateSessionStoreAfterAgentRun as updateSessionStoreAfterAgentRunBase,
} from "./session-store.js";
import { resolveSession } from "./session.js";
@@ -60,7 +60,16 @@ vi.mock("../../utils/usage-format.js", () => ({
}
return total / 1e6;
},
resolveModelCostConfig: (params: { provider?: string; model?: string; config?: unknown }) => {
resolveModelCostConfig: (params: {
provider?: string;
model?: string;
config?: unknown;
agentDir?: string;
}) => {
const agents = (params.config as OpenClawConfig | undefined)?.agents?.list ?? [];
if (agents.length > 1 && !params.agentDir) {
throw new Error("multi-agent cost resolution requires an explicit agent directory");
}
const providers = (params.config as MockUsageFormatConfig | undefined)?.models?.providers;
if (!providers) {
return undefined;
@@ -126,7 +135,70 @@ afterEach(() => {
closeOpenClawAgentDatabasesForTest();
});
type SessionStoreUpdateParams = Parameters<typeof updateSessionStoreAfterAgentRunBase>[0];
async function updateSessionStoreAfterAgentRun(
params: Omit<SessionStoreUpdateParams, "agentDir"> & { agentDir?: string },
) {
await updateSessionStoreAfterAgentRunBase({
...params,
agentDir: params.agentDir ?? "/tmp/openclaw-session-store-test-agent",
});
}
describe("updateSessionStoreAfterAgentRun", () => {
it("uses the prepared agent directory for multi-agent cost accounting", async () => {
await withTempSessionStore(async ({ dir, storePath }) => {
const sessionKey = "agent:marie:dashboard:cost-accounting";
const sessionId = "cost-accounting-session";
const sessionStore: Record<string, SessionEntry> = {};
await updateSessionStoreAfterAgentRun({
cfg: {
agents: { list: [{ id: "main" }, { id: "marie" }] },
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
models: [
{
id: "gpt-5.5",
name: "GPT-5.5",
reasoning: true,
input: ["text"],
cost: { input: 2, output: 4, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128_000,
maxTokens: 8_192,
},
],
},
},
},
} satisfies OpenClawConfig,
agentDir: path.join(dir, "agents", "marie", "agent"),
sessionId,
sessionKey,
storePath,
sessionStore,
defaultProvider: "openai",
defaultModel: "gpt-5.5",
result: {
meta: {
durationMs: 1,
agentMeta: {
sessionId,
provider: "openai",
model: "gpt-5.5",
usage: { input: 1_000_000, output: 1_000_000 },
},
},
},
});
expect(sessionStore[sessionKey]?.estimatedCostUsd).toBe(6);
});
});
it("clears the durable replay-safe recovery guard after the recovery run terminates", async () => {
await withTempSessionStore(async ({ storePath }) => {
const sessionKey = "agent:main:explicit:restart-recovery";
+2
View File
@@ -47,6 +47,7 @@ function resolvePositiveInteger(value: number | undefined): number | undefined {
/** Applies run result metadata, usage, and CLI bindings to a session entry. */
export async function updateSessionStoreAfterAgentRun(params: {
cfg: OpenClawConfig;
agentDir: string;
contextTokensOverride?: number;
sessionId: string;
sessionKey: string;
@@ -218,6 +219,7 @@ export async function updateSessionStoreAfterAgentRun(params: {
provider: providerUsed,
model: modelUsed,
config: cfg,
agentDir: params.agentDir,
}),
}),
);