feat(tui): infer workspace agent when launching TUI (#39591)

Merged via squash.

Prepared head SHA: 23533e24c4
Co-authored-by: arceus77-7 <261276524+arceus77-7@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
This commit is contained in:
arceus77-7
2026-03-08 06:31:11 -04:00
committed by GitHub
parent f4c4856254
commit 492fe679a7
6 changed files with 231 additions and 3 deletions

View File

@@ -1,4 +1,5 @@
import { describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { getSlashCommands, parseCommand } from "./commands.js";
import {
createBackspaceDeduper,
@@ -6,6 +7,7 @@ import {
resolveCtrlCAction,
resolveFinalAssistantText,
resolveGatewayDisconnectState,
resolveInitialTuiAgentId,
resolveTuiSessionKey,
stopTuiSafely,
} from "./tui.js";
@@ -107,6 +109,50 @@ describe("resolveTuiSessionKey", () => {
});
});
describe("resolveInitialTuiAgentId", () => {
const cfg: OpenClawConfig = {
agents: {
list: [
{ id: "main", workspace: "/tmp/openclaw" },
{ id: "ops", workspace: "/tmp/openclaw/projects/ops" },
],
},
};
it("infers agent from cwd when session is not agent-prefixed", () => {
expect(
resolveInitialTuiAgentId({
cfg,
fallbackAgentId: "main",
initialSessionInput: "",
cwd: "/tmp/openclaw/projects/ops/src",
}),
).toBe("ops");
});
it("keeps explicit agent prefix from --session", () => {
expect(
resolveInitialTuiAgentId({
cfg,
fallbackAgentId: "main",
initialSessionInput: "agent:main:incident",
cwd: "/tmp/openclaw/projects/ops/src",
}),
).toBe("main");
});
it("falls back when cwd has no matching workspace", () => {
expect(
resolveInitialTuiAgentId({
cfg,
fallbackAgentId: "main",
initialSessionInput: "",
cwd: "/var/tmp/unrelated",
}),
).toBe("main");
});
});
describe("resolveGatewayDisconnectState", () => {
it("returns pairing recovery guidance when disconnect reason requires pairing", () => {
const state = resolveGatewayDisconnectState("gateway closed (1008): pairing required");

View File

@@ -8,8 +8,8 @@ import {
Text,
TUI,
} from "@mariozechner/pi-tui";
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
import { loadConfig } from "../config/config.js";
import { resolveAgentIdByWorkspacePath, resolveDefaultAgentId } from "../agents/agent-scope.js";
import { loadConfig, type OpenClawConfig } from "../config/config.js";
import {
buildAgentMainSessionKey,
normalizeAgentId,
@@ -208,6 +208,28 @@ export function resolveTuiSessionKey(params: {
return `agent:${params.currentAgentId}:${trimmed.toLowerCase()}`;
}
export function resolveInitialTuiAgentId(params: {
cfg: OpenClawConfig;
fallbackAgentId: string;
initialSessionInput?: string;
cwd?: string;
}) {
const parsed = parseAgentSessionKey((params.initialSessionInput ?? "").trim());
if (parsed?.agentId) {
return normalizeAgentId(parsed.agentId);
}
const inferredFromWorkspace = resolveAgentIdByWorkspacePath(
params.cfg,
params.cwd ?? process.cwd(),
);
if (inferredFromWorkspace) {
return inferredFromWorkspace;
}
return normalizeAgentId(params.fallbackAgentId);
}
export function resolveGatewayDisconnectState(reason?: string): {
connectionStatus: string;
activityStatus: string;
@@ -303,7 +325,12 @@ export async function runTui(opts: TuiOptions) {
let sessionScope: SessionScope = (config.session?.scope ?? "per-sender") as SessionScope;
let sessionMainKey = normalizeMainKey(config.session?.mainKey);
let agentDefaultId = resolveDefaultAgentId(config);
let currentAgentId = agentDefaultId;
let currentAgentId = resolveInitialTuiAgentId({
cfg: config,
fallbackAgentId: agentDefaultId,
initialSessionInput,
cwd: process.cwd(),
});
let agents: AgentSummary[] = [];
const agentNames = new Map<string, string>();
let currentSessionKey = "";