From 3f8b85cbafba365b67c7d32fe444d8cdd1922e77 Mon Sep 17 00:00:00 2001
From: Waishnav <86405648+Waishnav@users.noreply.github.com>
Date: Mon, 31 Aug 2026 03:46:18 +0530
Subject: [PATCH] feat(agents): emit compact XML fragments by default
---
src/cli.test.ts | 35 +++++++++++++++-
src/cli.ts | 71 ++++++++++++++++++++++-----------
src/local-agent-presentation.ts | 57 +++++++++++++++++++-------
3 files changed, 124 insertions(+), 39 deletions(-)
diff --git a/src/cli.test.ts b/src/cli.test.ts
index 0983417c3..2caa5ae2a 100644
--- a/src/cli.test.ts
+++ b/src/cli.test.ts
@@ -150,7 +150,10 @@ try {
},
});
- assert.equal(output.trim(), `${current.id} completed reviewer`);
+ assert.equal(
+ output.trim(),
+ ``,
+ );
const { stdout: jsonOutput } = await execFileAsync(
"node",
@@ -217,6 +220,31 @@ try {
assert.equal(payload.error.retryable, false);
assert.equal(payload.error.target, "missing");
+ let xmlCommandFailure: unknown;
+ try {
+ await execFileAsync(
+ "node",
+ ["--import", "tsx", "src/cli.ts", "agents", "run", "missing", "inspect"],
+ {
+ cwd: process.cwd(),
+ encoding: "utf8",
+ env: {
+ ...process.env,
+ ...cliConfigEnv,
+ DEVSPACE_WORKSPACE_ID: "ws_current",
+ DEVSPACE_WORKSPACE_ROOT: projectRoot,
+ },
+ },
+ );
+ } catch (error) {
+ xmlCommandFailure = error;
+ }
+ assert.ok(xmlCommandFailure, "XML CLI errors should exit non-zero");
+ assert.equal(
+ (xmlCommandFailure as { stderr?: string }).stderr,
+ 'Unknown subagent profile or provider: missing.\n',
+ );
+
await assert.rejects(
execFileAsync(
"node",
@@ -243,7 +271,10 @@ try {
},
),
(error: unknown) => {
- assert.match((error as { stderr?: string }).stderr ?? "", /Unknown option: --unknown/);
+ assert.equal(
+ (error as { stderr?: string }).stderr,
+ 'Unknown option: --unknown. Use -- before prompt text that starts with a dash.\n',
+ );
return true;
},
);
diff --git a/src/cli.ts b/src/cli.ts
index b521556a3..d18b488cc 100644
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -25,6 +25,7 @@ import {
import { createLocalAgentClient } from "./local-agent-client.js";
import { toAgentErrorPayload, type LocalAgentError } from "./local-agent-errors.js";
import {
+ formatAgentCommandError,
formatAgentObservation,
formatAgentReceipt,
formatAgentSummary,
@@ -447,19 +448,19 @@ async function runAgentsCommand(args: string[]): Promise {
switch (subcommand) {
case "ls":
case "list":
- await runAgentsList(commandArgs, json);
+ await runAgentWorkflowCommand(json, () => runAgentsList(commandArgs, json));
return;
case "run":
- await runAgentsRun(commandArgs, json);
+ await runAgentWorkflowCommand(json, () => runAgentsRun(commandArgs, json));
return;
case "continue":
- await runAgentsContinue(commandArgs, json);
+ await runAgentWorkflowCommand(json, () => runAgentsContinue(commandArgs, json));
return;
case "show":
- await runAgentsShow(commandArgs, json);
+ await runAgentWorkflowCommand(json, () => runAgentsShow(commandArgs, json));
return;
case "targets":
- await runAgentsTargets(commandArgs, json);
+ await runAgentWorkflowCommand(json, () => runAgentsTargets(commandArgs, json));
return;
case "daemon":
await runAgentsDaemon(commandArgs, json);
@@ -471,7 +472,7 @@ async function runAgentsCommand(args: string[]): Promise {
printAgentsHelp();
return;
default:
- throw new Error(`Unknown agents command: ${subcommand}`);
+ writeAgentWorkflowError(`Unknown agents command: ${subcommand}`, json);
}
}
@@ -487,7 +488,7 @@ async function runAgentsTargets(args: string[], json: boolean): Promise {
const catalog = buildLocalAgentCatalog(config.subagents, profiles, providers);
const output = presentAgentTargetCatalog(catalog);
if (json) printJson(output);
- else console.log(formatAgentTargetCatalog(output));
+ else printAgentXml(formatAgentTargetCatalog(output));
}
async function runAgentsList(args: string[], json: boolean): Promise {
@@ -495,7 +496,7 @@ async function runAgentsList(args: string[], json: boolean): Promise {
const config = loadConfig();
const client = createLocalAgentClient(config);
const result = await client.list(resolveCliWorkspaceContext(config.allowedRoots));
- const agents = presentAgentResult(result, json);
+ const agents = presentAgentWorkflowResult(result, json);
if (!agents) return;
const summaries = agents.map(presentAgentSummary);
@@ -504,14 +505,7 @@ async function runAgentsList(args: string[], json: boolean): Promise {
return;
}
- if (agents.length === 0) {
- console.log("No subagent sessions found for this workspace.");
- return;
- }
-
- for (const summary of summaries) {
- console.log(formatAgentSummary(summary));
- }
+ printAgentXml(summaries.map(formatAgentSummary).join("\n"));
}
async function runAgentsRun(args: string[], json: boolean): Promise {
@@ -527,14 +521,14 @@ async function runAgentsRun(args: string[], json: boolean): Promise {
model: parsed.model,
effort: parsed.effort,
});
- const record = presentAgentResult(result, json);
+ const record = presentAgentWorkflowResult(result, json);
if (!record) return;
const receipt = presentAgentReceipt(record);
if (json) {
printJson(receipt);
return;
}
- console.log(formatAgentReceipt(receipt));
+ printAgentXml(formatAgentReceipt(receipt));
}
async function runAgentsContinue(args: string[], json: boolean): Promise {
@@ -546,14 +540,14 @@ async function runAgentsContinue(args: string[], json: boolean): Promise {
model: parsed.model,
effort: parsed.effort,
}, scope);
- const record = presentAgentResult(result, json);
+ const record = presentAgentWorkflowResult(result, json);
if (!record) return;
const receipt = presentAgentReceipt(record);
if (json) {
printJson(receipt);
return;
}
- console.log(formatAgentReceipt(receipt));
+ printAgentXml(formatAgentReceipt(receipt));
}
async function runAgentsShow(args: string[], json: boolean): Promise {
@@ -564,20 +558,20 @@ async function runAgentsShow(args: string[], json: boolean): Promise {
const client = createLocalAgentClient(config);
const scope = resolveCliWorkspaceContext(config.allowedRoots);
const initial = await client.get(id, scope);
- let record = presentAgentResult(initial, json);
+ let record = presentAgentWorkflowResult(initial, json);
if (!record) return;
const deadline = Date.now() + 15_000;
while ((record.status === "starting" || record.status === "running") && Date.now() < deadline) {
await sleep(500);
- const refreshed = presentAgentResult(await client.get(id, scope), json);
+ const refreshed = presentAgentWorkflowResult(await client.get(id, scope), json);
if (!refreshed) return;
record = refreshed;
}
const observation = presentAgentObservation(record);
if (json) printJson(observation);
- else console.log(formatAgentObservation(observation));
+ else printAgentXml(formatAgentObservation(observation));
}
async function runAgentsDaemon(args: string[], json: boolean): Promise {
@@ -643,6 +637,37 @@ function presentAgentResult(
throw new Error(result.error.message);
}
+function presentAgentWorkflowResult(
+ result: BetterResult,
+ json: boolean,
+): T | undefined {
+ if (result.isOk()) return result.value;
+ const error = toAgentErrorPayload(result.error);
+ if (json) printJson({ error });
+ else console.error(formatAgentCommandError(error));
+ process.exitCode = 1;
+ return undefined;
+}
+
+async function runAgentWorkflowCommand(json: boolean, command: () => Promise): Promise {
+ try {
+ await command();
+ } catch (error) {
+ writeAgentWorkflowError(error instanceof Error ? error.message : String(error), json);
+ }
+}
+
+function writeAgentWorkflowError(message: string, json: boolean): void {
+ const error = { code: "AGENT_COMMAND_ERROR", message, retryable: false };
+ if (json) printJson({ error });
+ else console.error(formatAgentCommandError(error));
+ process.exitCode = 1;
+}
+
+function printAgentXml(fragment: string): void {
+ if (fragment) console.log(fragment);
+}
+
function printJson(value: unknown): void {
console.log(JSON.stringify(value));
}
diff --git a/src/local-agent-presentation.ts b/src/local-agent-presentation.ts
index 21916afa5..9def4d39f 100644
--- a/src/local-agent-presentation.ts
+++ b/src/local-agent-presentation.ts
@@ -38,6 +38,13 @@ export interface AgentFailureOutput {
retryable: boolean;
}
+export interface AgentCommandErrorOutput {
+ code: string;
+ message: string;
+ retryable?: boolean;
+ agentId?: string;
+}
+
export type AgentObservationOutput =
| { id: string; status: "running" }
| { id: string; status: "completed"; response?: string }
@@ -98,37 +105,59 @@ export function presentAgentObservation(record: LocalAgentRecord): AgentObservat
}
export function formatAgentTargetCatalog(catalog: AgentTargetCatalogOutput): string {
- if (catalog.targets.length === 0) return "No usable subagent targets.";
return catalog.targets.map((target) => {
- const settings = [
- target.model ? `model=${target.model}` : undefined,
- target.effort ? `effort=${target.effort}` : undefined,
- ].filter(Boolean).join(" ");
+ const settings = xmlAttributes({ model: target.model, effort: target.effort });
if (target.kind === "provider") {
- return `${target.name} [provider]${settings ? ` ${settings}` : ""}`;
+ return ``;
}
- return `${target.name} [profile, ${target.provider}]${settings ? ` ${settings}` : ""} - ${target.description}`;
+ return `${escapeXmlText(target.description)}`;
}).join("\n");
}
export function formatAgentReceipt(receipt: AgentReceiptOutput): string {
- return `${receipt.id} ${receipt.status}`;
+ return ``;
}
export function formatAgentSummary(summary: AgentSummaryOutput): string {
- return `${formatAgentReceipt(summary)} ${summary.target}`;
+ return ``;
}
export function formatAgentObservation(observation: AgentObservationOutput): string {
- const line = formatAgentReceipt(observation);
if (observation.status === "completed" && observation.response !== undefined) {
- return `${line}\n\n${observation.response}`;
+ return `${escapeXmlText(observation.response)}`;
}
if ((observation.status === "failed" || observation.status === "stopped") && observation.error) {
- const retryable = observation.error.retryable ? " [retryable]" : "";
- return `${line} ${observation.error.code}: ${observation.error.message}${retryable}`;
+ return `${escapeXmlText(observation.error.message)}`;
}
- return line;
+ return formatAgentReceipt(observation);
+}
+
+export function formatAgentCommandError(error: AgentCommandErrorOutput): string {
+ const agentId = error.agentId ? ` agent-id="${escapeXmlAttribute(error.agentId)}"` : "";
+ return `${escapeXmlText(error.message)}`;
+}
+
+function xmlAttributes(values: Record): string {
+ return Object.entries(values)
+ .filter((entry): entry is [string, string] => entry[1] !== undefined)
+ .map(([name, value]) => ` ${name}="${escapeXmlAttribute(value)}"`)
+ .join("");
+}
+
+function escapeXmlAttribute(value: string): string {
+ return escapeXml(value).replaceAll('"', """).replaceAll("'", "'");
+}
+
+function escapeXmlText(value: string): string {
+ return escapeXml(value);
+}
+
+function escapeXml(value: string): string {
+ return value
+ .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\uFFFE\uFFFF]/g, "\uFFFD")
+ .replaceAll("&", "&")
+ .replaceAll("<", "<")
+ .replaceAll(">", ">");
}
function presentAgentStatus(status: LocalAgentStatus): AgentCommandStatus {