mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
refactor: remove dead split facades (#114726)
* refactor: remove dead split facades * fix: update facade ownership references
This commit is contained in:
committed by
GitHub
parent
3b008b061d
commit
f275db6974
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"));
|
||||
});
|
||||
|
||||
@@ -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 = (
|
||||
|
||||
@@ -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();
|
||||
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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,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 {
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" });
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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-" });
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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[];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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"));
|
||||
({
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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";
|
||||
Reference in New Issue
Block a user