refactor: remove dead split facades (#114726)

* refactor: remove dead split facades

* fix: update facade ownership references
This commit is contained in:
Peter Steinberger
2026-07-27 16:32:52 -04:00
committed by GitHub
parent 3b008b061d
commit f275db6974
70 changed files with 165 additions and 277 deletions
@@ -4,9 +4,9 @@ cbf4e2c3088f8886a7c9ea91325a66e0f0846cea21f0b2891f36399b4811306c module/account
8e985f345f21a1c9a2b0e94304aaaad6a326bec1c1ce3b26027d2862804a366e module/account-resolution
e5e67ddf3cab38fcbf9220bc3160715897e2709d9a9ff6ff36f1ecc9453c2367 module/agent-config-primitives
74daa746deb548379d3f0d6eac3c4d082df1034c4360cc03bf51fee0f10a2e4d module/agent-harness
d3e25a2954f140ec892394123e9543878c00bd0fc99d09865d7bad2b264b289b module/agent-harness-runtime
060517a859a6354894bad581ca4a3e138b9a69c8cf8bae4656e0893c549df77b module/agent-harness-runtime
5168648cd946abad8a92822889f13ceacc87ed502314a66190d0b1eb8ebe76ea module/agent-media-payload
8b406b7a50b0b4f088be869ea6a899c0d33229a5c73d3f82bda76ce0be0941b0 module/agent-runtime
2dcb4d62d90e5d71594f6b843c97534509a154784e378fb1c75bd86b5122b710 module/agent-runtime
56b6d5fb6af3d95af1200065aca2e7d4f59e5fa59740505fe6ff433077ef6646 module/allow-from
55cea5390d68839ca7768b4a0cc570b17b65fa0fa3bc4d76130ef0f16cb79ede module/allowlist-config-edit
7ddd81bd5f55de9adf64bf4d92d012f24b37b6da0a72805a3a220d8feff24ca3 module/approval-auth-runtime
+1 -1
View File
@@ -14,7 +14,7 @@ const outputPath = path.join(
);
const toolSources = [
path.join(repoRoot, "src/agents/apply-patch.ts"),
path.join(repoRoot, "src/agents/bash-tools.exec.ts"),
path.join(repoRoot, "src/agents/bash-tools.exec-run.ts"),
path.join(repoRoot, "src/agents/bash-tools.process.ts"),
path.join(repoRoot, "src/auto-reply/reply/acp-projector.ts"),
];
@@ -142,7 +142,7 @@ vi.mock("./exec-defaults.js", () => ({
resolveNodeExecEligibility: () => ({ canExec: false }),
}));
vi.mock("./model-fallback.js", () => ({
vi.mock("./model-fallback-runner.js", () => ({
runWithModelFallback: async (params: {
provider: string;
model: string;
@@ -110,7 +110,7 @@ const state = vi.hoisted(() => ({
trajectoryRecorderParamsMock: vi.fn(),
}));
vi.mock("./model-fallback.js", () => ({
vi.mock("./model-fallback-runner.js", () => ({
runWithModelFallback: (params: unknown) => state.runWithModelFallbackMock(params),
}));
@@ -17,7 +17,7 @@ import {
toToolDefinitions,
} from "./agent-tool-definition-adapter.js";
import { wrapToolWithBeforeToolCallHook } from "./agent-tools.before-tool-call.js";
import { createExecTool } from "./bash-tools.exec.js";
import { createExecTool } from "./bash-tools.exec-run.js";
import type { ClientToolDefinition } from "./embedded-agent-runner/run/params.js";
type ToolExecute = ReturnType<typeof toToolDefinitions>[number]["execute"];
@@ -12,7 +12,7 @@ import type { ProcessSupervisor } from "../process/supervisor/index.js";
import type { SpawnInput } from "../process/supervisor/types.js";
import { captureEnv } from "../test-utils/env.js";
import { resetProcessRegistryForTests } from "./bash-process-registry.test-support.js";
import { createExecTool } from "./bash-tools.exec.js";
import { createExecTool } from "./bash-tools.exec-run.js";
import type { BashSandboxConfig } from "./bash-tools.shared.js";
import { getBashShellConfig } from "./shell-utils.js";
@@ -19,8 +19,8 @@ import {
import { captureEnv, setTestEnvValue } from "../test-utils/env.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
import { withTimeout } from "../utils/with-timeout.js";
import { createExecTool } from "./bash-tools.exec-run.js";
import type { ExecApprovalFollowupOutcome } from "./bash-tools.exec-types.js";
import { createExecTool } from "./bash-tools.exec.js";
const TEST_ENV_KEYS = [
"HOME",
+3
View File
@@ -668,3 +668,6 @@ export function createExecTool(
},
};
}
/** Default exec tool instance used by agent tool registries. */
export const execTool = createExecTool();
@@ -7,7 +7,7 @@ const taskTracking = vi.hoisted(() => ({
vi.mock("./bash-tools.exec-task-tracking.js", () => taskTracking);
import { createExecTool } from "./bash-tools.exec.js";
import { createExecTool } from "./bash-tools.exec-run.js";
describe("exec background task wiring", () => {
beforeEach(() => {
@@ -17,7 +17,7 @@ import { sendMessage } from "../infra/outbound/message.js";
import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js";
import { captureEnv, deleteTestEnvValue, setTestEnvValue } from "../test-utils/env.js";
import { buildSystemRunPreparePayload } from "../test-utils/system-run-prepare-payload.js";
import { createExecTool as createExecToolImpl } from "./bash-tools.exec.js";
import { createExecTool as createExecToolImpl } from "./bash-tools.exec-run.js";
import { callGatewayTool } from "./tools/gateway.js";
const createExecTool = (
@@ -96,7 +96,7 @@ const TEST_EXEC_DEFAULTS = {
ask: "off" as const,
};
let createExecTool: typeof import("./bash-tools.exec.js").createExecTool;
let createExecTool: typeof import("./bash-tools.exec-run.js").createExecTool;
let getFinishedSession: typeof import("./bash-process-registry.js").getFinishedSession;
let getSession: typeof import("./bash-process-registry.js").getSession;
let resetProcessRegistryForTests: typeof import("./bash-process-registry.test-support.js").resetProcessRegistryForTests;
@@ -107,7 +107,7 @@ const createTestExecTool = (
): ReturnType<typeof createExecTool> => createExecTool({ ...TEST_EXEC_DEFAULTS, ...defaults });
beforeAll(async () => {
({ createExecTool } = await import("./bash-tools.exec.js"));
({ createExecTool } = await import("./bash-tools.exec-run.js"));
({ getFinishedSession, getSession } = await import("./bash-process-registry.js"));
({ resetProcessRegistryForTests } = await import("./bash-process-registry.test-support.js"));
});
+2 -2
View File
@@ -115,7 +115,7 @@ vi.mock("../process/supervisor/index.js", () => ({
}),
}));
let createExecTool: typeof import("./bash-tools.exec.js").createExecTool;
let createExecTool: typeof import("./bash-tools.exec-run.js").createExecTool;
function createExecApprovals(): ExecApprovalsResolved {
return {
@@ -175,7 +175,7 @@ describe("exec PATH login shell merge", () => {
let envSnapshot: ReturnType<typeof captureEnv>;
beforeAll(async () => {
({ createExecTool } = await import("./bash-tools.exec.js"));
({ createExecTool } = await import("./bash-tools.exec-run.js"));
});
afterAll(() => {
@@ -115,7 +115,7 @@ vi.mock("../process/supervisor/index.js", () => ({
}),
}));
let createExecTool: typeof import("./bash-tools.exec.js").createExecTool;
let createExecTool: typeof import("./bash-tools.exec-run.js").createExecTool;
let toToolDefinitions: typeof import("./agent-tool-definition-adapter.js").toToolDefinitions;
let createOpenClawCodingTools: typeof import("./agent-tools.js").createOpenClawCodingTools;
const testExtensionContext = {} as ExtensionContext;
@@ -129,7 +129,7 @@ function installResolveExecEnvHook(result: Record<string, string>) {
describe("exec resolve_exec_env hook wiring", () => {
beforeAll(async () => {
({ createExecTool } = await import("./bash-tools.exec.js"));
({ createExecTool } = await import("./bash-tools.exec-run.js"));
({ toToolDefinitions } = await import("./agent-tool-definition-adapter.js"));
({ createOpenClawCodingTools } = await import("./agent-tools.js"));
});
@@ -10,7 +10,7 @@ import { __setFsSafeTestHooksForTest } from "@openclaw/fs-safe/test-hooks";
import { afterEach, describe, expect, it, vi } from "vitest";
import { detectUnsafeExecControlShellCommand } from "../infra/exec-control-command-guard.js";
import { withTempDir } from "../test-utils/temp-dir.js";
import { createExecTool } from "./bash-tools.exec.js";
import { createExecTool } from "./bash-tools.exec-run.js";
vi.mock("./bash-tools.exec-host-gateway.js", () => ({
processGatewayAllowlist: async () => ({ allowWithoutEnforcedCommand: true }),
@@ -12,7 +12,7 @@ import type { ExecAutoReviewer } from "../infra/exec-auto-review.js";
import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js";
import { captureEnv, deleteTestEnvValue, setTestEnvValue } from "../test-utils/env.js";
import { resetProcessRegistryForTests } from "./bash-process-registry.test-support.js";
import { createExecTool as createExecToolImpl } from "./bash-tools.exec.js";
import { createExecTool as createExecToolImpl } from "./bash-tools.exec-run.js";
import { callGatewayTool } from "./tools/gateway.js";
const createExecTool = (
-13
View File
@@ -1,13 +0,0 @@
/** Public facade for the exec tool factory and default instance. */
import { createExecTool } from "./bash-tools.exec-run.js";
export type { BashSandboxConfig } from "./bash-tools.shared.js";
export type {
ExecElevatedDefaults,
ExecToolDefaults,
ExecToolDetails,
} from "./bash-tools.exec-types.js";
export { createExecTool };
/** Default exec tool instance used by agent tool registries. */
export const execTool = createExecTool();
+3 -3
View File
@@ -4,12 +4,12 @@
* modules to keep host policy seams local.
*/
export type {
BashSandboxConfig,
ExecElevatedDefaults,
ExecToolDefaults,
ExecToolDetails,
} from "./bash-tools.exec.js";
} from "./bash-tools.exec-types.js";
export type { BashSandboxConfig } from "./bash-tools.shared.js";
export { describeExecTool, describeProcessTool } from "./bash-tools.descriptions.js";
export { createExecTool, execTool } from "./bash-tools.exec.js";
export { createExecTool, execTool } from "./bash-tools.exec-run.js";
export type { ProcessToolDefaults } from "./bash-tools.process.js";
export { createProcessTool, processTool } from "./bash-tools.process.js";
@@ -1,16 +1,22 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
vi.mock("../model-fallback.js", () => ({
vi.mock("../model-fallback-candidates.js", () => ({
resolveModelCandidateChain: (params: { provider: string; model: string }) => [
{ provider: params.provider, model: params.model },
],
}));
vi.mock("../model-fallback-runner.js", () => ({
runWithModelFallback: vi.fn(async (params: Record<string, unknown>) => ({
result: { ok: true, compacted: false, reason: "no-op" },
provider: params.provider,
model: params.model,
attempts: [],
})),
}));
vi.mock("../model-fallback-attempt.js", () => ({
isFallbackSummaryError: () => false,
}));
@@ -36,7 +42,7 @@ vi.mock("../prepared-model-runtime.js", () => ({
),
}));
import { runWithModelFallback } from "../model-fallback.js";
import { runWithModelFallback } from "../model-fallback-runner.js";
import { compactEmbeddedAgentSessionDirect } from "./compact.js";
const runMock = vi.mocked(runWithModelFallback);
+3 -5
View File
@@ -16,11 +16,9 @@ import { hasMeaningfulConversationContent } from "../compaction-real-conversatio
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../defaults.js";
import { coerceToFailoverError } from "../failover-error.js";
import { ensureSelectedAgentHarnessPlugin } from "../harness/runtime-plugin.js";
import {
isFallbackSummaryError,
resolveModelCandidateChain,
runWithModelFallback,
} from "../model-fallback.js";
import { isFallbackSummaryError } from "../model-fallback-attempt.js";
import { resolveModelCandidateChain } from "../model-fallback-candidates.js";
import { runWithModelFallback } from "../model-fallback-runner.js";
import { acquireAgentRunPreparedModelRuntime } from "../prepared-model-runtime.js";
import {
applyAgentRunSessionTargetIdentity,
@@ -6,7 +6,7 @@ import { isSilentReplyPayloadText } from "../../auto-reply/tokens.js";
import { classifyFailoverReason } from "../embedded-agent-helpers/errors.js";
import type { FailoverReason } from "../embedded-agent-helpers/types.js";
import { isGpt5ModelId } from "../gpt5-prompt-overlay.js";
import type { ModelFallbackResultClassification } from "../model-fallback.js";
import type { ModelFallbackResultClassification } from "../model-fallback-attempt.js";
import {
hasCommittedOutboundDeliveryEvidence,
hasVisibleAgentPayload,
@@ -38,7 +38,7 @@ const state = vi.hoisted(() => ({
ensureSelectedAgentHarnessPlugin: vi.fn(async (_params: unknown) => undefined),
}));
vi.mock("../model-fallback.js", () => ({
vi.mock("../model-fallback-runner.js", () => ({
runWithModelFallback: (params: FallbackRunnerParams) => state.runWithModelFallback(params),
}));
@@ -1,8 +1,9 @@
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { buildAgentRunTerminalOutcome } from "../agent-run-terminal-outcome.js";
import { ensureSelectedAgentHarnessPlugin } from "../harness/runtime-plugin.js";
import type { ModelFallbackResultClassification } from "../model-fallback-attempt.js";
import type { ModelFallbackStepFields } from "../model-fallback-observation.js";
import { runWithModelFallback, type ModelFallbackResultClassification } from "../model-fallback.js";
import { runWithModelFallback } from "../model-fallback-runner.js";
import type { FallbackAttempt, ModelFallbackRouteResolution } from "../model-fallback.types.js";
import type { ModelManifestNormalizationContext } from "../model-ref-shared.js";
import { resolveAgentRunAbortLifecycleFields } from "../run-termination.js";
+3 -43
View File
@@ -1,17 +1,4 @@
/**
* Shared model-auth facade. Implementation lives in responsibility-focused modules.
*/
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { AuthProfileStore } from "./auth-profiles.js";
import {
resolveModelAuthMode as resolveModelAuthModeImpl,
type ModelAuthMode,
} from "./model-auth-model.js";
import {
resolveApiKeyForProvider as resolveApiKeyForProviderImpl,
type ProviderCredentialPrecedence,
} from "./model-auth-provider.js";
import type { ResolvedProviderAuth } from "./model-auth-runtime-shared.js";
/** Shared model-auth facade for runtime, Plugin SDK, and test import boundaries. */
export {
ensureAuthProfileStore,
@@ -27,6 +14,7 @@ export {
applySecretRefHeaderSentinels,
getApiKeyForModel,
hasAvailableAuthForProvider,
resolveModelAuthMode,
} from "./model-auth-model.js";
export type { ModelAuthMode } from "./model-auth-model.js";
export {
@@ -39,6 +27,7 @@ export {
shouldPreferExplicitConfigApiKeyAuth,
} from "./model-auth-provider-config.js";
export type { ProviderEntryApiKeyBindingResolution } from "./model-auth-provider-config.js";
export { resolveApiKeyForProvider } from "./model-auth-provider.js";
export type { ProviderCredentialPrecedence } from "./model-auth-provider.js";
export {
createRuntimeProviderAuthLookup,
@@ -56,32 +45,3 @@ export {
resolveAwsSdkEnvVarName,
} from "./model-auth-runtime-shared.js";
export type { ResolvedProviderAuth } from "./model-auth-runtime-shared.js";
export async function resolveApiKeyForProvider(params: {
provider: string;
cfg?: OpenClawConfig;
profileId?: string;
preferredProfile?: string;
store?: AuthProfileStore;
agentDir?: string;
workspaceDir?: string;
lockedProfile?: boolean;
forceRefresh?: boolean;
credentialPrecedence?: ProviderCredentialPrecedence;
allowAuthProfileFallback?: boolean;
skipSetupProviderFallback?: boolean;
modelId?: string;
modelApi?: string;
secretSentinels?: boolean;
}): Promise<ResolvedProviderAuth> {
return resolveApiKeyForProviderImpl(params);
}
export function resolveModelAuthMode(
provider?: string,
cfg?: OpenClawConfig,
store?: AuthProfileStore,
options?: { workspaceDir?: string },
): ModelAuthMode | undefined {
return resolveModelAuthModeImpl(provider, cfg, store, options);
}
+2 -2
View File
@@ -111,7 +111,7 @@ type AuthProfilesSourceCheckModule = typeof import("./auth-profiles/source-check
type AuthProfilesUsageModule = typeof import("./auth-profiles/usage.js");
type AuthProfilesOrderModule = typeof import("./auth-profiles/order.js");
type ModelFallbackCooldownModule = typeof import("./model-fallback-cooldown.js");
type ModelFallbackModule = typeof import("./model-fallback.js");
type ModelFallbackModule = typeof import("./model-fallback-runner.js");
type LoggerModule = typeof import("../logging/logger.js");
let mockedEnsureAuthProfileStore: ReturnType<
@@ -149,7 +149,7 @@ async function loadModelFallbackProbeModules() {
const authProfilesOrderModule = await import("./auth-profiles/order.js");
const loggerModule = await import("../logging/logger.js");
const modelFallbackCooldownModule = await import("./model-fallback-cooldown.js");
const modelFallbackModule = await import("./model-fallback.js");
const modelFallbackModule = await import("./model-fallback-runner.js");
const modelFallbackTestSupport = await import("./model-fallback.test-support.js");
mockedEnsureAuthProfileStore = vi.mocked(authProfilesStoreModule.ensureAuthProfileStore);
mockedHasAnyAuthProfileStoreSource = vi.mocked(
@@ -63,13 +63,13 @@ const installRunEmbeddedMocks = () => {
};
let runEmbeddedAgent: typeof import("./embedded-agent-runner/run.js").runEmbeddedAgent;
let runWithModelFallback: typeof import("./model-fallback.js").runWithModelFallback;
let runWithModelFallback: typeof import("./model-fallback-runner.js").runWithModelFallback;
beforeAll(async () => {
vi.resetModules();
installRunEmbeddedMocks();
({ runEmbeddedAgent } = await import("./embedded-agent-runner/run.js"));
({ runWithModelFallback } = await import("./model-fallback.js"));
({ runWithModelFallback } = await import("./model-fallback-runner.js"));
});
beforeEach(() => {
+2 -47
View File
@@ -1,47 +1,2 @@
import type { AuthProfileStore } from "./auth-profiles/types.js";
import type { FailoverReason } from "./embedded-agent-helpers/types.js";
import type { ModelCandidate } from "./model-fallback.types.js";
import "./model-fallback.js";
type CooldownDecision =
| { type: "skip"; reason: FailoverReason; error: string }
| { type: "attempt"; reason: FailoverReason; markProbe: boolean }
| { type: "suspend_lanes"; reason: FailoverReason; leaderCandidate?: ModelCandidate };
type ModelFallbackTestApi = {
resolveCooldownDecision(params: {
candidate: ModelCandidate;
isPrimary: boolean;
requestedModel: boolean;
hasFallbackCandidates: boolean;
now: number;
probeThrottleKey: string;
authRuntime: typeof import("./auth-profiles.runtime.js");
authStore: AuthProfileStore;
profileIds: string[];
}): CooldownDecision;
shouldDiscardDeferredSessionSuspension(params: {
error: unknown;
abortSignal?: AbortSignal;
}): boolean;
};
function getTestApi(): ModelFallbackTestApi {
const api = (globalThis as Record<PropertyKey, unknown>)[
Symbol.for("openclaw.modelFallbackTestApi")
];
if (!api) {
throw new Error("model fallback test API is unavailable");
}
return api as ModelFallbackTestApi;
}
export const resolveCooldownDecision: ModelFallbackTestApi["resolveCooldownDecision"] = (params) =>
getTestApi().resolveCooldownDecision(params);
export function shouldDiscardDeferredSessionSuspension(params: {
error: unknown;
abortSignal?: AbortSignal;
}): boolean {
return getTestApi().shouldDiscardDeferredSessionSuspension(params);
}
export { shouldDiscardDeferredSessionSuspension } from "./model-fallback-attempt.js";
export { resolveCooldownDecision } from "./model-fallback-cooldown.js";
+4 -6
View File
@@ -33,12 +33,10 @@ import {
import { clearAgentHarnesses, registerAgentHarness } from "./harness/registry.js";
import type { AgentHarness } from "./harness/types.js";
import { LiveSessionModelSwitchError } from "./live-model-switch-error.js";
import {
isFallbackSummaryError,
resolveModelCandidateChain,
runWithImageModelFallback,
runWithModelFallback as runWithModelFallbackBase,
} from "./model-fallback.js";
import { isFallbackSummaryError } from "./model-fallback-attempt.js";
import { resolveModelCandidateChain } from "./model-fallback-candidates.js";
import { runWithImageModelFallback } from "./model-fallback-image.js";
import { runWithModelFallback as runWithModelFallbackBase } from "./model-fallback-runner.js";
import { shouldDiscardDeferredSessionSuspension } from "./model-fallback.test-support.js";
import {
createAgentRunDirectAbortError,
-21
View File
@@ -1,21 +0,0 @@
import { shouldDiscardDeferredSessionSuspension } from "./model-fallback-attempt.js";
import { resolveCooldownDecision } from "./model-fallback-cooldown.js";
export {
resolveImageFallbackCandidates,
resolveImageFallbackDefaultProvider,
resolveModelCandidateChain,
} from "./model-fallback-candidates.js";
export {
isFallbackSummaryError,
type ModelFallbackResultClassification,
} from "./model-fallback-attempt.js";
export { runWithModelFallback } from "./model-fallback-runner.js";
export { runWithImageModelFallback } from "./model-fallback-image.js";
if (process.env.VITEST || process.env.NODE_ENV === "test") {
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw.modelFallbackTestApi")] = {
resolveCooldownDecision,
shouldDiscardDeferredSessionSuspension,
};
}
@@ -10,7 +10,7 @@ import {
classifyEmbeddedAgentRunResultForModelFallback,
mergeEmbeddedAgentRunResultForModelFallbackExhaustion,
} from "./embedded-agent-runner/result-fallback-classifier.js";
import { runWithModelFallback } from "./model-fallback.js";
import { runWithModelFallback } from "./model-fallback-runner.js";
vi.mock("./auth-profiles/source-check.js", () => ({
hasAnyAuthProfileStoreSource: () => false,
+1 -1
View File
@@ -45,7 +45,7 @@ import { isMinimaxVlmProvider } from "../minimax-vlm.js";
import {
resolveImageFallbackCandidates,
resolveImageFallbackDefaultProvider,
} from "../model-fallback.js";
} from "../model-fallback-candidates.js";
import type { PreparedModelRuntimeSnapshot } from "../prepared-model-runtime.js";
import { optionalFiniteNumberSchema, optionalPositiveIntegerSchema } from "../schema/typebox.js";
import { readFiniteNumberParam, readPositiveIntegerParam } from "./common.js";
+1 -1
View File
@@ -5,7 +5,7 @@
* sandbox media paths, or workspace helpers without depending on broad agent barrels.
*/
export { getApiKeyForModel, requireApiKey } from "../model-auth.js";
export { runWithImageModelFallback } from "../model-fallback.js";
export { runWithImageModelFallback } from "../model-fallback-image.js";
export {
createSandboxBridgeReadFile,
resolveSandboxedBridgeMediaPath,
@@ -15,7 +15,7 @@ import {
import { sanitizeUserFacingText } from "../../agents/embedded-agent-helpers/sanitize-user-facing-text.js";
import { isFailoverError } from "../../agents/failover-error.js";
import { LiveSessionModelSwitchError } from "../../agents/live-model-switch-error.js";
import { isFallbackSummaryError } from "../../agents/model-fallback.js";
import { isFallbackSummaryError } from "../../agents/model-fallback-attempt.js";
import {
AGENT_RUN_RESTART_ABORT_STOP_REASON,
resolveAgentRunErrorLifecycleFields,
@@ -81,8 +81,11 @@ vi.mock("../../agents/cli-runner.js", () => ({
runCliAgent: (params: unknown) => state.runCliAgentMock(params),
}));
vi.mock("../../agents/model-fallback.js", () => ({
vi.mock("../../agents/model-fallback-runner.js", () => ({
runWithModelFallback: (params: unknown) => state.runWithModelFallbackMock(params),
}));
vi.mock("../../agents/model-fallback-attempt.js", () => ({
isFallbackSummaryError: (err: unknown) =>
err instanceof Error &&
err.name === "FallbackSummaryError" &&
@@ -24,7 +24,7 @@ import {
isFailoverError,
} from "../../agents/failover-error.js";
import { isMissingProviderAuthError } from "../../agents/model-auth.js";
import { isFallbackSummaryError } from "../../agents/model-fallback.js";
import { isFallbackSummaryError } from "../../agents/model-fallback-attempt.js";
import { resolveSilentReplyPolicy } from "../../config/silent-reply.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { formatErrorMessage } from "../../infra/errors.js";
@@ -40,12 +40,15 @@ const resolveCommandSecretRefsViaGatewayMock = vi.fn();
const resolveOutboundAttachmentFromUrlMock = vi.fn();
const createReplyMediaContextRuntimeMock = vi.fn();
vi.mock("../../agents/model-fallback.js", () => ({
vi.mock("../../agents/model-fallback-runner.js", () => ({
runWithModelFallback: (params: {
provider: string;
model: string;
run: (provider: string, model: string) => Promise<unknown>;
}) => runWithModelFallbackMock(params),
}));
vi.mock("../../agents/model-fallback-attempt.js", () => ({
isFallbackSummaryError: (err: unknown) =>
err instanceof Error &&
err.name === "FallbackSummaryError" &&
@@ -87,12 +87,15 @@ const compactState = vi.hoisted(() => ({
compactEmbeddedAgentSessionMock: vi.fn(),
}));
vi.mock("../../agents/model-fallback.js", () => ({
vi.mock("../../agents/model-fallback-runner.js", () => ({
runWithModelFallback: (params: {
provider: string;
model: string;
run: (provider: string, model: string) => Promise<unknown>;
}) => runWithModelFallbackMock(params),
}));
vi.mock("../../agents/model-fallback-attempt.js", () => ({
isFallbackSummaryError: (err: unknown) =>
err instanceof Error &&
err.name === "FallbackSummaryError" &&
@@ -125,7 +125,7 @@ async function readStoredMainSession(storePath: string): Promise<SessionEntry> {
return requireStoredSessionEntry(storePath);
}
let modelFallbackModule: typeof import("../../agents/model-fallback.js");
let modelFallbackModule: typeof import("../../agents/model-fallback-runner.js");
let onAgentEvent: typeof import("../../infra/agent-events.js").onAgentEvent;
let runReplyAgentPromise:
@@ -139,7 +139,7 @@ async function getRunReplyAgent() {
return await runReplyAgentPromise;
}
vi.mock("../../agents/model-fallback.js", () => ({
vi.mock("../../agents/model-fallback-runner.js", () => ({
runWithModelFallback: async ({
provider,
model,
@@ -155,6 +155,9 @@ vi.mock("../../agents/model-fallback.js", () => ({
model,
attempts: [],
}),
}));
vi.mock("../../agents/model-fallback-attempt.js", () => ({
isFallbackSummaryError: (err: unknown) =>
err instanceof Error &&
err.name === "FallbackSummaryError" &&
@@ -221,7 +224,7 @@ vi.mock("./queue.js", async (importOriginal) => ({
beforeAll(async () => {
// Avoid attributing the initial agent-runner import cost to the first test case.
modelFallbackModule = await import("../../agents/model-fallback.js");
modelFallbackModule = await import("../../agents/model-fallback-runner.js");
({ onAgentEvent } = await import("../../infra/agent-events.js"));
await getRunReplyAgent();
});
+1 -1
View File
@@ -12,7 +12,7 @@ import {
loadManifestModelCatalog,
loadPreparedModelCatalog as loadModelCatalogLocal,
} from "../../agents/model-catalog.runtime.js";
import { resolveModelCandidateChain } from "../../agents/model-fallback.js";
import { resolveModelCandidateChain } from "../../agents/model-fallback-candidates.js";
import type { OpenClawConfig } from "../../config/config.js";
import type { SessionEntry } from "../../config/sessions.js";
import { loadSessionEntry, replaceSessionEntry } from "../../config/sessions/session-accessor.js";
@@ -1,4 +1,4 @@
import { isFallbackSummaryError } from "../../agents/model-fallback.js";
import { isFallbackSummaryError } from "../../agents/model-fallback-attempt.js";
import { isAgentRunRestartAbortReason } from "../../agents/run-termination.js";
import { CommandLaneClearedError, GatewayDrainingError } from "../../process/command-queue.js";
import type { ReplyOperation } from "./reply-run-registry.js";
+1 -1
View File
@@ -6,7 +6,7 @@ import {
} from "@openclaw/normalization-core/string-coerce";
import type { Command } from "commander";
import { resolveAgentDir, resolveDefaultAgentId } from "../../agents/agent-scope.js";
import { runWithImageModelFallback } from "../../agents/model-fallback.js";
import { runWithImageModelFallback } from "../../agents/model-fallback-image.js";
import { getRuntimeConfig } from "../../config/config.js";
import { resolveAgentModelPrimaryValue } from "../../config/model-input.js";
import {
@@ -3,7 +3,7 @@ import { expectDefined } from "@openclaw/normalization-core";
import { Command } from "commander";
import { afterEach, describe, expect, it, vi } from "vitest";
import { createMockCronStateForJobs } from "../../cron/service.test-harness.js";
import { listPage } from "../../cron/service/ops.js";
import { listPage } from "../../cron/service/ops-read.js";
import type { CronJob } from "../../cron/types.js";
import { cronHandlers } from "../../gateway/server-methods/cron.js";
+2 -2
View File
@@ -41,7 +41,7 @@ function readLegacyCronStorePath(cfg: OpenClawConfig): string | undefined {
// The scheduler sets this while a run is active and clears it on completion, so a
// leftover marker (gateway killed mid-run) makes `cron list` show the job as
// `running` while nothing executes it. Startup marks exactly these runs interrupted
// (`src/cron/service/ops.ts` `start`), so doctor only reports the count here.
// (`src/cron/service/ops-lifecycle.ts` `start`), so doctor only reports the count here.
function countInFlightCronJobs(jobs: Array<Record<string, unknown>>): number {
return jobs.filter((job) => {
const state = job.state;
@@ -60,7 +60,7 @@ const CHRONIC_FAILURE_MIN_CONSECUTIVE_ERRORS = 3;
// Count enabled jobs stuck in repeated run failures. `state.consecutiveErrors`
// resets to 0 on the next successful run and also increments for runs interrupted
// by a gateway restart (startup marks in-flight runs failed, `src/cron/service/ops.ts`),
// by a gateway restart (startup marks in-flight runs failed, `src/cron/service/ops-lifecycle.ts`),
// so a streak can mean task failures, interrupted runs, or a mix — the note says so.
// Failure alerts are opt-in, so by default nothing else surfaces the streak.
// Disabled jobs no longer re-fire (e.g. the scheduler disables exhausted
+1 -1
View File
@@ -1,7 +1,7 @@
// Regression: upstream commit 7d1575b5df (#60310, 2026-04-04) introduced
// activeJobIds + markCronJobActive/clearCronJobActive but only wired the pair
// into the scheduled due-job path. The manual-run path (cron.run() →
// prepareManualRun + finishPreparedManualRun in src/cron/service/ops.ts) was
// prepareManualRun + finishPreparedManualRun in src/cron/service/ops-run.ts) was
// left without the mark/clear pair, so task-registry.maintenance.ts
// hasBackingSession (cron branch under isRuntimeAuthoritative()=true)
// returns false during manual-run executions and reconciles them as `lost`
@@ -7,7 +7,7 @@ export { resolveBootstrapWarningSignaturesSeen } from "../../agents/bootstrap-bu
export { resolveCronAgentLane } from "../../agents/lanes.js";
export { ensureSelectedAgentHarnessPlugin } from "../../agents/harness/runtime-plugin.js";
export { LiveSessionModelSwitchError } from "../../agents/live-model-switch-error.js";
export { runWithModelFallback } from "../../agents/model-fallback.js";
export { runWithModelFallback } from "../../agents/model-fallback-runner.js";
export { resolveCandidateThinkingLevel } from "../../agents/thinking-runtime.js";
export {
classifyEmbeddedAgentRunResultForModelFallback,
@@ -1,5 +1,5 @@
/** Resolves model fallback chains for isolated cron runs and preflight. */
import { resolveModelCandidateChain } from "../../agents/model-fallback.js";
import { resolveModelCandidateChain } from "../../agents/model-fallback-candidates.js";
import type { ModelCandidate } from "../../agents/model-fallback.types.js";
import { resolveAgentModelFallbackValues } from "../../config/model-input.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
@@ -4,7 +4,7 @@ import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { createMockCronStateForJobs } from "./service.test-harness.js";
import { listPage } from "./service/ops.js";
import { listPage } from "./service/ops-read.js";
import type { CronJob } from "./types.js";
function createBaseJob(overrides?: Partial<CronJob>): CronJob {
+2 -1
View File
@@ -1,7 +1,8 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { resetGatewayWorkAdmission } from "../process/gateway-work-admission.js";
import { setupCronServiceSuite } from "./service.test-harness.js";
import { list, run } from "./service/ops.js";
import { list } from "./service/ops-read.js";
import { run } from "./service/ops-run.js";
import { createCronServiceState, type CronEvent, type CronServiceState } from "./service/state.js";
import { ensureLoaded } from "./service/store.js";
import { runMissedJobs } from "./service/timer.js";
@@ -1,6 +1,7 @@
import { describe, expect, it, vi } from "vitest";
import { setupCronServiceSuite } from "./service.test-harness.js";
import { start, status } from "./service/ops.js";
import { start } from "./service/ops-lifecycle.js";
import { status } from "./service/ops-read.js";
import { createCronServiceState } from "./service/state.js";
import { onTimer } from "./service/timer.test-support.js";
import { saveCronStore } from "./store.js";
+27 -24
View File
@@ -5,7 +5,10 @@ import type {
CronServiceRunResult,
} from "./service-contract.js";
import type { CronListPageOptions } from "./service/list-page-types.js";
import * as ops from "./service/ops.js";
import * as lifecycleOps from "./service/ops-lifecycle.js";
import * as mutationOps from "./service/ops-mutations.js";
import * as readOps from "./service/ops-read.js";
import * as runOps from "./service/ops-run.js";
import {
type CronAddOptions,
type CronServiceDeps,
@@ -62,9 +65,9 @@ export class CronService implements CronServiceContract {
this.startInProgress += 1;
this.state.schedulerStarted = false;
try {
await ops.start(this.state);
await lifecycleOps.start(this.state);
if (generation !== this.lifecycleGeneration) {
ops.stop(this.state);
lifecycleOps.stop(this.state);
return;
}
this.state.schedulerStarted = !this.state.stopped;
@@ -75,15 +78,15 @@ export class CronService implements CronServiceContract {
stop() {
this.lifecycleGeneration += 1;
ops.stop(this.state);
lifecycleOps.stop(this.state);
}
pauseScheduling() {
ops.pauseScheduling(this.state);
lifecycleOps.pauseScheduling(this.state);
}
resumeScheduling() {
ops.resumeScheduling(this.state);
lifecycleOps.resumeScheduling(this.state);
}
getSuspensionBlockerCount() {
@@ -91,23 +94,23 @@ export class CronService implements CronServiceContract {
}
async status() {
return await ops.status(this.state);
return await readOps.status(this.state);
}
async list(opts?: { includeDisabled?: boolean }) {
return await ops.list(this.state, opts);
return await readOps.list(this.state, opts);
}
async listPage(opts?: CronListPageOptions) {
return await ops.listPage(this.state, opts);
return await readOps.listPage(this.state, opts);
}
async add(input: CronJobCreate, opts?: CronAddOptions) {
return await ops.add(this.state, input, opts);
return await mutationOps.add(this.state, input, opts);
}
async update(id: string, patch: CronJobPatch, opts?: CronUpdateOptions) {
return await ops.update(this.state, id, patch, opts);
return await mutationOps.update(this.state, id, patch, opts);
}
async updateWithPrecondition(
@@ -116,15 +119,15 @@ export class CronService implements CronServiceContract {
precondition: CronUpdatePrecondition,
opts?: CronUpdateOptions,
) {
return await ops.updateWithPrecondition(this.state, id, patch, precondition, opts);
return await mutationOps.updateWithPrecondition(this.state, id, patch, precondition, opts);
}
async remove(id: string, opts?: { systemOwned?: boolean }) {
return await ops.remove(this.state, id, opts);
return await mutationOps.remove(this.state, id, opts);
}
async removeAgentJobsTransactional<T>(agentId: string, commit: () => Promise<T>): Promise<T> {
return await ops.removeAgentJobsTransactional(this.state, agentId, commit);
return await mutationOps.removeAgentJobsTransactional(this.state, agentId, commit);
}
async run(
@@ -132,11 +135,11 @@ export class CronService implements CronServiceContract {
mode?: "due" | "force",
opts?: CronServiceRunOptions,
): Promise<CronServiceRunResult> {
return await ops.run(this.state, id, mode, opts);
return await runOps.run(this.state, id, mode, opts);
}
async enqueueRun(id: string, mode?: "due" | "force"): Promise<CronServiceRunResult> {
const result = await ops.enqueueRun(this.state, id, mode);
const result = await runOps.enqueueRun(this.state, id, mode);
if (result.ok && "runnable" in result) {
// ops.enqueueRun resolves runnable dispositions before crossing the
// public facade; leaking one would expose an internal scheduler detail.
@@ -155,18 +158,18 @@ export class CronService implements CronServiceContract {
}
async readJob(id: string): Promise<CronJob | undefined> {
return await ops.readJob(this.state, id);
return await readOps.readJob(this.state, id);
}
async readScratch(id: string) {
return await ops.readScratch(this.state, id);
return await readOps.readScratch(this.state, id);
}
async writeScratch(
id: string,
params: { content: string | null; expectedRevision?: number; sourceSha256?: string },
) {
return await ops.writeScratch(this.state, id, params);
return await readOps.writeScratch(this.state, id, params);
}
async recordExternalFailure(
@@ -175,7 +178,7 @@ export class CronService implements CronServiceContract {
statePatch: Partial<CronJob["state"]>,
source?: { scheduleKey: string; identity: string },
): Promise<void> {
await ops.recordExternalFailure(this.state, id, error, statePatch, source);
await readOps.recordExternalFailure(this.state, id, error, statePatch, source);
}
async updateExternalState(
@@ -184,7 +187,7 @@ export class CronService implements CronServiceContract {
streamSourceIdentity: string,
statePatch: Partial<CronJob["state"]>,
): Promise<boolean> {
return await ops.updateExternalState(
return await readOps.updateExternalState(
this.state,
id,
streamScheduleKey,
@@ -198,7 +201,7 @@ export class CronService implements CronServiceContract {
streamScheduleKey: string,
streamSourceIdentity: string,
): Promise<string | undefined> {
return await ops.retireExternalStreamSource(
return await readOps.retireExternalStreamSource(
this.state,
id,
streamScheduleKey,
@@ -210,7 +213,7 @@ export class CronService implements CronServiceContract {
id: string,
counters: Pick<CronJob["state"], "streamDroppedBatches" | "streamCoalescedBatches">,
): Promise<void> {
await ops.updateExternalCounters(this.state, id, counters);
await readOps.updateExternalCounters(this.state, id, counters);
}
getDefaultAgentId(): string | undefined {
@@ -218,6 +221,6 @@ export class CronService implements CronServiceContract {
}
wake(opts: { mode: CronWakeMode; text: string; sessionKey?: string; agentId?: string }) {
return ops.wakeNow(this.state, opts);
return runOps.wakeNow(this.state, opts);
}
}
+1 -1
View File
@@ -3,7 +3,7 @@ import { describe, expect, it, vi } from "vitest";
import { withEnvAsync } from "../../test-utils/env.js";
import { setupCronServiceSuite } from "../service.test-harness.js";
import type { CronJobCreate, CronJobPatch, CronPacing } from "../types.js";
import { add, update } from "./ops.js";
import { add, update } from "./ops-mutations.js";
import { createCronServiceState } from "./state.js";
const { logger, makeStorePath } = setupCronServiceSuite({ prefix: "cron-pacing-ops" });
+3 -1
View File
@@ -25,7 +25,9 @@ import {
import { CommandLane } from "../../process/lanes.js";
import { isCronJobActive } from "../active-jobs.js";
import { loadCronStore, saveCronStore } from "../store.js";
import { enqueueRun, remove, run, start, update } from "./ops.js";
import { start } from "./ops-lifecycle.js";
import { remove, update } from "./ops-mutations.js";
import { enqueueRun, run } from "./ops-run.js";
import type { CronEvent } from "./state.js";
import { createCronServiceState } from "./state.js";
import { ensureLoaded } from "./store.js";
@@ -7,7 +7,8 @@ import {
} from "../../../test/helpers/cron/service-regression-fixtures.js";
import * as cronStoreModule from "../store.js";
import { loadCronStore, saveCronStore } from "../store.js";
import { run, stop } from "./ops.js";
import { stop } from "./ops-lifecycle.js";
import { run } from "./ops-run.js";
import { createCronServiceState } from "./state.js";
import { runMissedJobs } from "./timer.js";
import { onTimer } from "./timer.test-support.js";
+4 -1
View File
@@ -18,7 +18,10 @@ import * as cronStoreModule from "../store.js";
import { loadCronStore, saveCronStore } from "../store.js";
import { cronStreamScheduleKey } from "../stream-schedule.js";
import { recomputeNextRunsForMaintenance } from "./jobs.js";
import { enqueueRun, list, run, stop, update } from "./ops.js";
import { stop } from "./ops-lifecycle.js";
import { update } from "./ops-mutations.js";
import { list } from "./ops-read.js";
import { enqueueRun, run } from "./ops-run.js";
import { createCronServiceState } from "./state.js";
import { onTimer } from "./timer.test-support.js";
+4 -1
View File
@@ -13,7 +13,10 @@ import { setupCronServiceSuite, writeCronStoreSnapshot } from "../service.test-h
import * as cronStoreModule from "../store.js";
import { loadCronJobsStoreWithConfigJobs, loadCronStore } from "../store.js";
import type { CronJob } from "../types.js";
import { add, list, remove, run, start, stop, update } from "./ops.js";
import { start, stop } from "./ops-lifecycle.js";
import { add, remove, update } from "./ops-mutations.js";
import { list } from "./ops-read.js";
import { run } from "./ops-run.js";
import { createCronServiceState, type CronEvent } from "./state.js";
import { tryCreateCronTaskRun, tryFinishCronTaskRun } from "./task-runs.js";
import { runMissedJobs } from "./timer.js";
-22
View File
@@ -1,22 +0,0 @@
/** Stable public facade for cron service operations. */
export { pauseScheduling, resumeScheduling, start, stop } from "./ops-lifecycle.js";
export {
list,
listPage,
readJob,
readScratch,
recordExternalFailure,
retireExternalStreamSource,
status,
updateExternalCounters,
updateExternalState,
writeScratch,
} from "./ops-read.js";
export {
add,
remove,
removeAgentJobsTransactional,
update,
updateWithPrecondition,
} from "./ops-mutations.js";
export { enqueueRun, run, wakeNow } from "./ops-run.js";
@@ -3,7 +3,8 @@ import {
noopLogger,
setupCronRegressionFixtures,
} from "../../../test/helpers/cron/service-regression-fixtures.js";
import { add, list, update } from "./ops.js";
import { add, update } from "./ops-mutations.js";
import { list } from "./ops-read.js";
import { createCronServiceState } from "./state.js";
const fixtures = setupCronRegressionFixtures({ prefix: "cron-disable-list-" });
+2 -1
View File
@@ -38,7 +38,8 @@ import type {
import { cancelActiveCronTaskRun } from "./active-run-cancellation.js";
import { resetActiveCronTaskRunsForTests } from "./active-run-cancellation.test-support.js";
import { computeJobNextRunAtMs, recomputeNextRunsForMaintenance } from "./jobs.js";
import { run as runManualCronJob, stop } from "./ops.js";
import { stop } from "./ops-lifecycle.js";
import { run as runManualCronJob } from "./ops-run.js";
import { createCronServiceState as createBaseCronServiceState, type CronEvent } from "./state.js";
import { applyJobResult, executeJobCoreWithTimeout, runMissedJobs } from "./timer.js";
import { executeJobCore, onTimer } from "./timer.test-support.js";
@@ -173,7 +173,7 @@ const modelFallbackMocks = getSharedMocks("openclaw.trigger-handling.model-fallb
}));
const installModelFallbackMock = () =>
vi.doMock("../../../src/agents/model-fallback.js", () => modelFallbackMocks);
vi.doMock("../../../src/agents/model-fallback-runner.js", () => modelFallbackMocks);
installModelFallbackMock();
+4 -2
View File
@@ -10,7 +10,7 @@ describe("audit-seams cron seam classification", () => {
it("detects cron agent handoff and outbound delivery boundaries", () => {
const source = `
import { runCliAgent } from "../../agents/cli-runner.js";
import { runWithModelFallback } from "../../agents/model-fallback.js";
import { runWithModelFallback } from "../../agents/model-fallback-runner.js";
import { registerAgentRunContext } from "../../infra/agent-events.js";
import { deliverOutboundPayloads } from "../../infra/outbound/deliver.js";
import { buildOutboundSessionContext } from "../../infra/outbound/session-context.js";
@@ -45,7 +45,9 @@ describe("audit-seams cron seam classification", () => {
}
`;
expect(describeSeamKinds("src/cron/service/ops.ts", source)).toContain("cron-scheduler-state");
expect(describeSeamKinds("src/cron/service/ops-lifecycle.ts", source)).toContain(
"cron-scheduler-state",
);
});
});
+1 -1
View File
@@ -15,7 +15,7 @@ import { createStorageMock } from "../../test-helpers/storage.ts";
import type { SessionObserverDigest } from "./chat-pane-deps.ts";
import "./chat-pane.ts";
import type { ResolvedBoardView } from "./chat-pane-shared.ts";
import type { ChatPageHost } from "./chat-state.ts";
import type { ChatPageHost } from "./chat-state-host.ts";
import {
detachPanelToColumn,
mergePanelIntoColumn,
+8 -6
View File
@@ -194,15 +194,18 @@ export {
switchChatModel,
switchChatThinkingLevel,
} from "./chat-session.ts";
export { ChatStateController } from "./chat-state-controller.ts";
export { handlePageGatewayEvent } from "./chat-state-events.ts";
export type { ChatPageHost } from "./chat-state-host.ts";
export { createPageState } from "./chat-state-page.ts";
export {
canCreateChatSession,
ChatStateController,
createPageState,
handlePageGatewayEvent,
refreshChatCommands,
refreshChatMetadata,
refreshChatModelAuthStatus,
refreshPageChat,
} from "./chat-state-refresh.ts";
export {
canCreateChatSession,
refreshRouteSessionOptions,
resetChatStateForRouteSession,
retryChatComposerMemoryFallback,
@@ -210,8 +213,7 @@ export {
resolveChatAvatarUrl,
selectedChatSessionRow,
saveRouteSessionSettings,
type ChatPageHost,
} from "./chat-state.ts";
} from "./chat-state-route.ts";
export { resetChatViewState } from "./chat-view-state.ts";
export { renderChat, type ChatProps } from "./chat-view.ts";
export {
+1 -1
View File
@@ -7,7 +7,7 @@ import type { ApplicationContext } from "../../app/context.ts";
import type { SessionCapability } from "../../lib/sessions/index.ts";
import "./chat-pane.ts";
import { loadChatHistory } from "./chat-history.ts";
import type { ChatPageHost } from "./chat-state.ts";
import type { ChatPageHost } from "./chat-state-host.ts";
type TestChatPane = HTMLElement & {
catalogMessages: unknown[];
+1 -1
View File
@@ -4,7 +4,7 @@ import { describe, expect, it } from "vitest";
import type { GatewayBrowserClient } from "../../api/gateway.ts";
import type { SessionCapability } from "../../lib/sessions/index.ts";
import { createTestChatPane } from "./chat-pane.test-support.ts";
import type { ChatPageHost } from "./chat-state.ts";
import type { ChatPageHost } from "./chat-state-host.ts";
describe("chat pane assistant identity snapshots", () => {
it("keeps a session-specific assistant identity across ordinary gateway snapshots", () => {
@@ -14,7 +14,7 @@ import type { ApplicationContext } from "../../app/context.ts";
import { createInitialUserMessageHandoff } from "../../app/initial-user-message-handoff.ts";
import type { SessionCapability } from "../../lib/sessions/index.ts";
import { createTestChatPane, type TestChatPane } from "./chat-pane.test-support.ts";
import type { ChatPageHost } from "./chat-state.ts";
import type { ChatPageHost } from "./chat-state-host.ts";
import {
dismissConfirmedActionPopovers,
openChatRewindConfirmation,
@@ -3,7 +3,7 @@ import type { GatewayBrowserClient } from "../../api/gateway.ts";
import type { ApplicationContext } from "../../app/context.ts";
import type { SessionCapability } from "../../lib/sessions/index.ts";
import "./chat-pane.ts";
import type { ChatPageHost } from "./chat-state.ts";
import type { ChatPageHost } from "./chat-state-host.ts";
type TestChatPane = HTMLElement & {
connectedClient: GatewayBrowserClient | null;
+1 -1
View File
@@ -17,7 +17,7 @@ import { createInitialUserMessageHandoff } from "../../app/initial-user-message-
import type { CatalogSessionKey } from "../../lib/sessions/catalog-key.ts";
import type { SessionCapability } from "../../lib/sessions/index.ts";
import "./chat-pane.ts";
import type { ChatPageHost } from "./chat-state.ts";
import type { ChatPageHost } from "./chat-state-host.ts";
import { createBackgroundTasksProps } from "./components/chat-background-tasks.ts";
import { createSessionWorkspaceProps } from "./components/chat-session-workspace.ts";
import type { ChatMessageCache } from "./session-message-cache.ts";
+1 -1
View File
@@ -22,7 +22,7 @@ import {
createTestChatPane,
type TestChatPane,
} from "./chat-pane.test-support.ts";
import type { ChatPageHost } from "./chat-state.ts";
import type { ChatPageHost } from "./chat-state-host.ts";
import { createBackgroundTasksProps } from "./components/chat-background-tasks.ts";
import { createSessionWorkspaceProps } from "./components/chat-session-workspace.ts";
import type { SidebarContent } from "./components/chat-sidebar.ts";
+5 -6
View File
@@ -24,7 +24,7 @@ import {
switchChatThinkingLevel,
} from "./chat-session.ts";
import { patchChatSessionSettings } from "./chat-settings-patches.ts";
import type { ChatPageHost } from "./chat-state.ts";
import type { ChatPageHost } from "./chat-state-host.ts";
import {
admitStoredChatComposerQueueItem,
listStoredChatOutboxes,
@@ -158,7 +158,7 @@ let handleSendChat: typeof import("./chat-send-submit.ts").handleSendChat;
let steerQueuedChatMessage: typeof import("./chat-send-actions.ts").steerQueuedChatMessage;
let handleAbortChat: typeof import("./run-lifecycle.ts").handleAbortChat;
let hasAbortableSessionRun: typeof import("./run-lifecycle.ts").hasAbortableSessionRun;
let handlePageGatewayEvent: typeof import("./chat-state.ts").handlePageGatewayEvent;
let handlePageGatewayEvent: typeof import("./chat-state-events.ts").handlePageGatewayEvent;
let loadChatBranches: typeof import("./chat-history.ts").loadChatBranches;
let loadChatHistory: typeof import("./chat-history.ts").loadChatHistory;
let clearPendingQueueItemsForRun: typeof import("./chat-queue.ts").clearPendingQueueItemsForRun;
@@ -173,7 +173,7 @@ let flushChatQueueForEvent: typeof import("./chat-send-actions.ts").flushChatQue
let retryReconnectableQueuedChatSends: typeof import("./chat-send-actions.ts").retryReconnectableQueuedChatSends;
let retryQueuedChatMessage: typeof import("./chat-send-actions.ts").retryQueuedChatMessage;
let recordChatSendServerTiming: typeof import("./chat-send-timing.ts").recordChatSendServerTiming;
let refreshPageChat: typeof import("./chat-state.ts").refreshPageChat;
let refreshPageChat: typeof import("./chat-state-refresh.ts").refreshPageChat;
async function loadChatHelpers(): Promise<void> {
({
@@ -184,9 +184,8 @@ async function loadChatHelpers(): Promise<void> {
} = await import("./chat-send-actions.ts"));
({ handleSendChat } = await import("./chat-send-submit.ts"));
({ recordChatSendServerTiming } = await import("./chat-send-timing.ts"));
const chatState = await import("./chat-state.ts");
handlePageGatewayEvent = chatState.handlePageGatewayEvent;
refreshPageChat = chatState.refreshPageChat;
({ handlePageGatewayEvent } = await import("./chat-state-events.ts"));
({ refreshPageChat } = await import("./chat-state-refresh.ts"));
({ loadChatBranches, loadChatHistory } = await import("./chat-history.ts"));
({ handleAbortChat, hasAbortableSessionRun } = await import("./run-lifecycle.ts"));
({
+6 -6
View File
@@ -17,17 +17,17 @@ import {
subscribeChatOutboxProjection,
updateQueuedMessageForSession,
} from "./chat-queue.ts";
import { ChatStateController } from "./chat-state-controller.ts";
import { handlePageGatewayEvent } from "./chat-state-events.ts";
import type { ChatPageHost } from "./chat-state-host.ts";
import { createPageState } from "./chat-state-page.ts";
import { refreshChatMetadata } from "./chat-state-refresh.ts";
import {
ChatStateController,
createPageState,
handlePageGatewayEvent,
refreshChatMetadata,
resetChatStateForRouteSession,
retryChatComposerMemoryFallback,
resolveChatAvatarUrl,
selectedChatSessionRow,
type ChatPageHost,
} from "./chat-state.ts";
} from "./chat-state-route.ts";
import {
admitStoredChatComposerQueueItem,
ChatComposerPersistence,
-8
View File
@@ -1,8 +0,0 @@
// Control UI chat state facade. Keep the public surface stable while ownership
// lives in focused route, refresh, event, page, and lifecycle modules.
export * from "./chat-state-controller.ts";
export * from "./chat-state-events.ts";
export type { ChatPageHost } from "./chat-state-host.ts";
export { createPageState } from "./chat-state-page.ts";
export * from "./chat-state-refresh.ts";
export * from "./chat-state-route.ts";