mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix: prevent agent hatch failure after gateway startup (#122210)
* fix(system-agent): attach hatch TUI to running gateway * test(system-agent): isolate TUI gateway state --------- Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
16540e2b88
commit
2ce420091e
@@ -502,15 +502,19 @@ export async function executeSystemAgentOperation(
|
||||
},
|
||||
});
|
||||
case "open-tui": {
|
||||
const agentId = await resolveTuiAgentId({
|
||||
const overview = await loadOverviewForOperation(opts.deps);
|
||||
const agentId = resolveTuiAgentId({
|
||||
requestedAgentId: operation.agentId,
|
||||
requestedWorkspace: operation.workspace,
|
||||
deps: opts.deps,
|
||||
overview,
|
||||
});
|
||||
const session = agentId ? buildAgentMainSessionKey({ agentId }) : undefined;
|
||||
const runTui = opts.deps?.runTui ?? (await import("../tui/tui.js")).runTui;
|
||||
// A reachable Gateway owns the state lock, so embedded mode would fail during hatch.
|
||||
// Keep embedded mode only as the no-Gateway fallback for standalone sessions.
|
||||
const useEmbeddedTui = !overview.gateway.reachable;
|
||||
const result = await runTui({
|
||||
local: true,
|
||||
local: useEmbeddedTui,
|
||||
session,
|
||||
deliver: false,
|
||||
historyLimit: 200,
|
||||
|
||||
@@ -187,12 +187,12 @@ export function createNoExitRuntime(runtime: RuntimeEnv): RuntimeEnv {
|
||||
};
|
||||
}
|
||||
|
||||
export async function resolveTuiAgentId(params: {
|
||||
export function resolveTuiAgentId(params: {
|
||||
requestedAgentId: string | undefined;
|
||||
requestedWorkspace?: string;
|
||||
deps?: SystemAgentCommandDeps;
|
||||
}): Promise<string | undefined> {
|
||||
const overview = await loadOverviewForOperation(params.deps);
|
||||
overview: SystemAgentOverview;
|
||||
}): string | undefined {
|
||||
const { overview } = params;
|
||||
const workspace = params.requestedWorkspace
|
||||
? resolveUserPath(params.requestedWorkspace)
|
||||
: undefined;
|
||||
|
||||
@@ -4,8 +4,35 @@ import path from "node:path";
|
||||
import { withTempHome } from "openclaw/plugin-sdk/test-env";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { executeSystemAgentOperation, isPersistentSystemAgentOperation } from "./operations.js";
|
||||
import type { SystemAgentOverview } from "./overview.js";
|
||||
import { createSystemAgentTestRuntime } from "./system-agent.runtime.test-support.js";
|
||||
|
||||
function createOverview(gatewayReachable: boolean): SystemAgentOverview {
|
||||
return {
|
||||
config: { path: "/tmp/openclaw.json", exists: true, valid: true, issues: [], hash: null },
|
||||
agents: [
|
||||
{ id: "main", isDefault: true },
|
||||
{ id: "work", isDefault: false },
|
||||
],
|
||||
defaultAgentId: "main",
|
||||
tools: {
|
||||
codex: { command: "codex", found: false },
|
||||
claude: { command: "claude", found: false },
|
||||
gemini: { command: "gemini", found: false },
|
||||
apiKeys: { openai: false, anthropic: false },
|
||||
},
|
||||
gateway: {
|
||||
url: "ws://127.0.0.1:18789",
|
||||
source: "test",
|
||||
reachable: gatewayReachable,
|
||||
},
|
||||
references: {
|
||||
docsUrl: "https://docs.openclaw.ai",
|
||||
sourceUrl: "https://github.com/openclaw/openclaw",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe("system-agent TUI operations", () => {
|
||||
it("refuses doctor repairs before any write or audit", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
@@ -39,7 +66,7 @@ describe("system-agent TUI operations", () => {
|
||||
const result = await executeSystemAgentOperation(
|
||||
{ kind: "open-tui", agentId: "work" },
|
||||
runtime,
|
||||
{ deps: { runTui } },
|
||||
{ deps: { runTui, loadOverview: async () => createOverview(false) } },
|
||||
);
|
||||
|
||||
expect(runTui).toHaveBeenCalledWith({
|
||||
@@ -58,22 +85,38 @@ describe("system-agent TUI operations", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("seeds a fresh hatch into the agent TUI", async () => {
|
||||
it("connects a fresh hatch to the reachable Gateway", async () => {
|
||||
const { runtime } = createSystemAgentTestRuntime();
|
||||
const runTui = vi.fn(async () => ({ exitReason: "exit" as const }));
|
||||
|
||||
await executeSystemAgentOperation(
|
||||
{ kind: "open-tui", agentId: "work", agentDraft: "hatch" },
|
||||
runtime,
|
||||
{ deps: { runTui } },
|
||||
{ deps: { runTui, loadOverview: async () => createOverview(true) } },
|
||||
);
|
||||
|
||||
expect(runTui).toHaveBeenCalledWith({
|
||||
local: false,
|
||||
session: "agent:work:main",
|
||||
deliver: false,
|
||||
historyLimit: 200,
|
||||
message: "Wake up, my friend!",
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps the embedded TUI fallback when the Gateway is unreachable", async () => {
|
||||
const { runtime } = createSystemAgentTestRuntime();
|
||||
const runTui = vi.fn(async () => ({ exitReason: "exit" as const }));
|
||||
|
||||
await executeSystemAgentOperation({ kind: "open-tui", agentId: "work" }, runtime, {
|
||||
deps: { runTui, loadOverview: async () => createOverview(false) },
|
||||
});
|
||||
|
||||
expect(runTui).toHaveBeenCalledWith({
|
||||
local: true,
|
||||
session: "agent:work:main",
|
||||
deliver: false,
|
||||
historyLimit: 200,
|
||||
message: "Wake up, my friend!",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -84,7 +127,7 @@ describe("system-agent TUI operations", () => {
|
||||
}));
|
||||
|
||||
const result = await executeSystemAgentOperation({ kind: "open-tui" }, runtime, {
|
||||
deps: { runTui },
|
||||
deps: { runTui, loadOverview: async () => createOverview(false) },
|
||||
});
|
||||
|
||||
expect(result).toMatchObject({
|
||||
|
||||
Reference in New Issue
Block a user