mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-22 14:41:34 +00:00
Revert "refactor(cli): remove bundled cli text providers"
This reverts commit 05d351c430.
This commit is contained in:
@@ -12,17 +12,25 @@ import { loadConfig } from "../../config/config.js";
|
||||
import { mergeSessionEntry, type SessionEntry, updateSessionStore } from "../../config/sessions.js";
|
||||
import { resolveSessionTranscriptFile } from "../../config/sessions/transcript.js";
|
||||
import { emitAgentEvent } from "../../infra/agent-events.js";
|
||||
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
||||
import { emitSessionTranscriptUpdate } from "../../sessions/transcript-events.js";
|
||||
import { sanitizeForLog } from "../../terminal/ansi.js";
|
||||
import { resolveMessageChannel } from "../../utils/message-channel.js";
|
||||
import { resolveBootstrapWarningSignaturesSeen } from "../bootstrap-budget.js";
|
||||
import { runCliAgent } from "../cli-runner.js";
|
||||
import { clearCliSession, getCliSessionBinding, setCliSessionBinding } from "../cli-session.js";
|
||||
import { FailoverError } from "../failover-error.js";
|
||||
import { formatAgentInternalEventsForPrompt } from "../internal-events.js";
|
||||
import { hasInternalRuntimeContext } from "../internal-runtime-context.js";
|
||||
import { isCliProvider } from "../model-selection.js";
|
||||
import { prepareSessionManagerForRun } from "../pi-embedded-runner/session-manager-init.js";
|
||||
import { runEmbeddedPiAgent } from "../pi-embedded.js";
|
||||
import { buildWorkspaceSkillSnapshot } from "../skills.js";
|
||||
import { resolveAgentRunContext } from "./run-context.js";
|
||||
import type { AgentCommandOpts } from "./types.js";
|
||||
|
||||
const log = createSubsystemLogger("agents/agent-command");
|
||||
|
||||
/** Maximum number of JSONL records to inspect before giving up. */
|
||||
const SESSION_FILE_MAX_RECORDS = 500;
|
||||
|
||||
@@ -337,6 +345,97 @@ export function runAgentAttempt(params: {
|
||||
params.providerOverride === params.authProfileProvider
|
||||
? params.sessionEntry?.authProfileOverride
|
||||
: undefined;
|
||||
if (isCliProvider(params.providerOverride, params.cfg)) {
|
||||
const cliSessionBinding = getCliSessionBinding(params.sessionEntry, params.providerOverride);
|
||||
const runCliWithSession = (nextCliSessionId: string | undefined) =>
|
||||
runCliAgent({
|
||||
sessionId: params.sessionId,
|
||||
sessionKey: params.sessionKey,
|
||||
agentId: params.sessionAgentId,
|
||||
sessionFile: params.sessionFile,
|
||||
workspaceDir: params.workspaceDir,
|
||||
config: params.cfg,
|
||||
prompt: effectivePrompt,
|
||||
provider: params.providerOverride,
|
||||
model: params.modelOverride,
|
||||
thinkLevel: params.resolvedThinkLevel,
|
||||
timeoutMs: params.timeoutMs,
|
||||
runId: params.runId,
|
||||
extraSystemPrompt: params.opts.extraSystemPrompt,
|
||||
cliSessionId: nextCliSessionId,
|
||||
cliSessionBinding:
|
||||
nextCliSessionId === cliSessionBinding?.sessionId ? cliSessionBinding : undefined,
|
||||
authProfileId,
|
||||
bootstrapPromptWarningSignaturesSeen,
|
||||
bootstrapPromptWarningSignature,
|
||||
images: params.isFallbackRetry ? undefined : params.opts.images,
|
||||
imageOrder: params.isFallbackRetry ? undefined : params.opts.imageOrder,
|
||||
streamParams: params.opts.streamParams,
|
||||
messageProvider: params.messageChannel,
|
||||
agentAccountId: params.runContext.accountId,
|
||||
});
|
||||
return runCliWithSession(cliSessionBinding?.sessionId).catch(async (err) => {
|
||||
if (
|
||||
err instanceof FailoverError &&
|
||||
err.reason === "session_expired" &&
|
||||
cliSessionBinding?.sessionId &&
|
||||
params.sessionKey &&
|
||||
params.sessionStore &&
|
||||
params.storePath
|
||||
) {
|
||||
log.warn(
|
||||
`CLI session expired, clearing from session store: provider=${sanitizeForLog(params.providerOverride)} sessionKey=${params.sessionKey}`,
|
||||
);
|
||||
|
||||
const entry = params.sessionStore[params.sessionKey];
|
||||
if (entry) {
|
||||
const updatedEntry = { ...entry };
|
||||
clearCliSession(updatedEntry, params.providerOverride);
|
||||
updatedEntry.updatedAt = Date.now();
|
||||
|
||||
await persistSessionEntry({
|
||||
sessionStore: params.sessionStore,
|
||||
sessionKey: params.sessionKey,
|
||||
storePath: params.storePath,
|
||||
entry: updatedEntry,
|
||||
clearedFields: ["cliSessionBindings", "cliSessionIds", "claudeCliSessionId"],
|
||||
});
|
||||
|
||||
params.sessionEntry = updatedEntry;
|
||||
}
|
||||
|
||||
return runCliWithSession(undefined).then(async (result) => {
|
||||
if (
|
||||
result.meta.agentMeta?.cliSessionBinding?.sessionId &&
|
||||
params.sessionKey &&
|
||||
params.sessionStore &&
|
||||
params.storePath
|
||||
) {
|
||||
const entry = params.sessionStore[params.sessionKey];
|
||||
if (entry) {
|
||||
const updatedEntry = { ...entry };
|
||||
setCliSessionBinding(
|
||||
updatedEntry,
|
||||
params.providerOverride,
|
||||
result.meta.agentMeta.cliSessionBinding,
|
||||
);
|
||||
updatedEntry.updatedAt = Date.now();
|
||||
|
||||
await persistSessionEntry({
|
||||
sessionStore: params.sessionStore,
|
||||
sessionKey: params.sessionKey,
|
||||
storePath: params.storePath,
|
||||
entry: updatedEntry,
|
||||
});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
return runEmbeddedPiAgent({
|
||||
sessionId: params.sessionId,
|
||||
sessionKey: params.sessionKey,
|
||||
|
||||
72
src/agents/command/session-store.test.ts
Normal file
72
src/agents/command/session-store.test.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { loadSessionStore, type SessionEntry } from "../../config/sessions.js";
|
||||
import type { EmbeddedPiRunResult } from "../pi-embedded.js";
|
||||
import { updateSessionStoreAfterAgentRun } from "./session-store.js";
|
||||
|
||||
describe("updateSessionStoreAfterAgentRun", () => {
|
||||
let tmpDir: string;
|
||||
let storePath: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-store-"));
|
||||
storePath = path.join(tmpDir, "sessions.json");
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("persists the runtime provider/model used by the completed run", async () => {
|
||||
const cfg = {
|
||||
agents: {
|
||||
defaults: {
|
||||
cliBackends: {
|
||||
"codex-cli": { command: "codex" },
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
const sessionKey = "agent:main:explicit:test-codex-cli";
|
||||
const sessionId = "test-openclaw-session";
|
||||
const sessionStore: Record<string, SessionEntry> = {
|
||||
[sessionKey]: {
|
||||
sessionId,
|
||||
updatedAt: 1,
|
||||
},
|
||||
};
|
||||
await fs.writeFile(storePath, JSON.stringify(sessionStore, null, 2));
|
||||
|
||||
const result: EmbeddedPiRunResult = {
|
||||
meta: {
|
||||
durationMs: 1,
|
||||
agentMeta: {
|
||||
sessionId: "cli-session-123",
|
||||
provider: "codex-cli",
|
||||
model: "gpt-5.4",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await updateSessionStoreAfterAgentRun({
|
||||
cfg,
|
||||
sessionId,
|
||||
sessionKey,
|
||||
storePath,
|
||||
sessionStore,
|
||||
defaultProvider: "codex-cli",
|
||||
defaultModel: "gpt-5.4",
|
||||
result,
|
||||
});
|
||||
|
||||
expect(sessionStore[sessionKey]?.modelProvider).toBe("codex-cli");
|
||||
expect(sessionStore[sessionKey]?.model).toBe("gpt-5.4");
|
||||
|
||||
const persisted = loadSessionStore(storePath);
|
||||
expect(persisted[sessionKey]?.modelProvider).toBe("codex-cli");
|
||||
expect(persisted[sessionKey]?.model).toBe("gpt-5.4");
|
||||
});
|
||||
});
|
||||
@@ -6,8 +6,10 @@ import {
|
||||
updateSessionStore,
|
||||
} from "../../config/sessions.js";
|
||||
import { estimateUsageCost, resolveModelCostConfig } from "../../utils/usage-format.js";
|
||||
import { setCliSessionBinding, setCliSessionId } from "../cli-session.js";
|
||||
import { resolveContextTokensForModel } from "../context.js";
|
||||
import { DEFAULT_CONTEXT_TOKENS } from "../defaults.js";
|
||||
import { isCliProvider } from "../model-selection.js";
|
||||
import { deriveSessionTotalTokens, hasNonzeroUsage } from "../usage.js";
|
||||
|
||||
type RunResult = Awaited<ReturnType<(typeof import("../pi-embedded.js"))["runEmbeddedPiAgent"]>>;
|
||||
@@ -71,6 +73,17 @@ export async function updateSessionStoreAfterAgentRun(params: {
|
||||
provider: providerUsed,
|
||||
model: modelUsed,
|
||||
});
|
||||
if (isCliProvider(providerUsed, cfg)) {
|
||||
const cliSessionBinding = result.meta.agentMeta?.cliSessionBinding;
|
||||
if (cliSessionBinding?.sessionId?.trim()) {
|
||||
setCliSessionBinding(next, providerUsed, cliSessionBinding);
|
||||
} else {
|
||||
const cliSessionId = result.meta.agentMeta?.sessionId?.trim();
|
||||
if (cliSessionId) {
|
||||
setCliSessionId(next, providerUsed, cliSessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
next.abortedLastRun = result.meta.aborted ?? false;
|
||||
if (result.meta.systemPromptReport) {
|
||||
next.systemPromptReport = result.meta.systemPromptReport;
|
||||
|
||||
Reference in New Issue
Block a user