fix: pipe AgentRun bridge stdin directly

This commit is contained in:
Codex
2026-06-10 02:10:00 +00:00
parent 0a562eb080
commit 7b869f95a0
2 changed files with 61 additions and 8 deletions
+1 -1
View File
@@ -111,7 +111,7 @@ UniDesk 不能作为以下内容的事实来源:
AgentRun `v0.1` 的指挥官任务面已经按 AgentRun issue #105 完成真实运行面验收,可作为新任务派发、Queue commander、trace/output、steer、turn/reuse、read 和 cancel 的 AgentRun 侧标准路径。长期使用时仍以 AgentRun 仓库自身 SPEC 为能力事实来源;UniDesk 只记录该路径已经通过 G14 `agentrun-v01` 运行面和 `hy` profile + `gpt-5.5` 验证。
UniDesk 指挥官新任务入口固定使用 `bun scripts/cli.ts agentrun v01 queue|sessions`。该入口是 G14 `/root/agentrun-v01` 中官方 `./scripts/agentrun --manager-url auto` CLI 的直接 bridge;本地 `--json-file``--json-stdin``--prompt-file``--prompt-stdin``--runner-json-file``--runner-json-stdin` 只会被 materialize 到 G14 临时文件后传给官方 CLI,不在 UniDesk 内实现 AgentRun queue 协议,也不把任务 double-write 回旧 Code Queue。日常派单、dispatch、turn 和 steer 优先用 heredoc/stdin,避免为了 JSON 或 prompt 输入先落 dump 文件。
UniDesk 指挥官新任务入口固定使用 `bun scripts/cli.ts agentrun v01 queue|sessions`。该入口是 G14 `/root/agentrun-v01` 中官方 `./scripts/agentrun --manager-url auto` CLI 的直接 bridge;本地 `--json-file``--prompt-file``--runner-json-file` 会被 materialize 到 G14 临时文件后传给官方 CLI,`--json-stdin``--prompt-stdin``--runner-json-stdin``--*-file -` 则通过管道直通官方 CLI 的 stdin,不在 UniDesk 内实现 AgentRun queue 协议,也不把任务 double-write 回旧 Code Queue。日常派单、dispatch、turn 和 steer 优先用 heredoc/stdin,避免为了 JSON 或 prompt 输入先落 dump 文件。
AgentRun Queue 任务如果需要调用 UniDesk 维护桥,例如 `trans` / `unidesk-ssh`,长期契约以 AgentRun 仓库 `docs/reference/spec-v01-runtime-assembly.md``docs/reference/spec-v01-secret-distribution.md` 为准:调用方通过 `executionPolicy.secretScope.toolCredentials[].tool=unidesk-ssh` 请求 `UNIDESK_SSH_CLIENT_TOKEN` SecretRef;非敏感 endpoint 由 runner-job `transientEnv` 显式提供,或由 manager 受控默认值自动补齐。UniDesk bridge 提交 Queue payload 时不得在 prompt、payload 或 `transientEnv` 中携带 token,也不得使用 HWLAB runtime Web 入口冒充 UniDesk frontend。若 dispatcher 已正确请求 `unidesk-ssh` 但 trace 的 `runner-job-created.transientEnv.names` 没有 `UNIDESK_MAIN_SERVER_IP``UNIDESK_MAIN_SERVER_HOST``UNIDESK_FRONTEND_URL`,归为 AgentRun assembly 问题;若 endpoint env 已存在但 route denied/timeout,再按 UniDesk frontend/token scope 或 provider session 排查。
+60 -7
View File
@@ -1445,15 +1445,23 @@ interface AgentRunCliMaterializedFile {
base64: string;
}
interface AgentRunCliForwardedStdin {
flag: string;
source: string;
bytes: number;
base64: string;
}
interface PreparedAgentRunCliArgs {
args: string[];
materializedFiles: AgentRunCliMaterializedFile[];
stdinPayload: AgentRunCliForwardedStdin | null;
}
async function runOfficialAgentRunCli(config: UniDeskConfig, group: "queue" | "sessions", args: string[]): Promise<Record<string, unknown>> {
const prepared = prepareOfficialAgentRunCliArgs([group, ...args]);
const command = `agentrun v01 ${prepared.args.join(" ")}`.trim();
const bridge = agentRunQueueBridgeMetadata(prepared.materializedFiles);
const bridge = agentRunQueueBridgeMetadata(prepared.materializedFiles, prepared.stdinPayload);
const script = officialAgentRunCliScript(prepared);
const result = await capture(config, g14SourceRoute, ["script", "--", script]);
const payload = captureJsonPayload(result);
@@ -1489,6 +1497,7 @@ function prepareOfficialAgentRunCliArgs(args: string[]): PreparedAgentRunCliArgs
const materializedFiles: AgentRunCliMaterializedFile[] = [];
const prepared: string[] = [];
let stdinBuffer: Buffer | null = null;
let stdinPayload: AgentRunCliForwardedStdin | null = null;
const stdin = (): Buffer => {
if (stdinBuffer === null) stdinBuffer = readFileSync(0);
@@ -1507,6 +1516,23 @@ function prepareOfficialAgentRunCliArgs(args: string[]): PreparedAgentRunCliArgs
return remotePath;
};
const forwardStdin = (flag: string, source: string, buffer: Buffer): void => {
if (stdinPayload !== null) throw new Error(`${flag} cannot be combined with ${stdinPayload.flag}; pass one stdin payload per AgentRun CLI call`);
stdinPayload = {
flag,
source,
bytes: buffer.length,
base64: buffer.toString("base64"),
};
};
const stdinFlagForFileFlag = (flag: string): string | null => {
if (flag === "--json-file") return "--json-stdin";
if (flag === "--prompt-file") return "--prompt-stdin";
if (flag === "--runner-json-file") return "--runner-json-stdin";
return null;
};
for (let i = 0; i < args.length; i += 1) {
const arg = args[i] ?? "";
const equalsFlag = Array.from(fileFlags).find((flag) => arg.startsWith(`${flag}=`));
@@ -1514,6 +1540,13 @@ function prepareOfficialAgentRunCliArgs(args: string[]): PreparedAgentRunCliArgs
const source = arg.slice(equalsFlag.length + 1);
if (source.length === 0) throw new Error(`${equalsFlag} requires a path`);
const buffer = source === "-" ? stdin() : readFileSync(source);
if (source === "-") {
const stdinFlag = stdinFlagForFileFlag(equalsFlag);
if (!stdinFlag) throw new Error(`${equalsFlag} does not support stdin`);
forwardStdin(stdinFlag, "stdin", buffer);
prepared.push(stdinFlag);
continue;
}
prepared.push(equalsFlag, materialize(equalsFlag, source === "-" ? "stdin" : source, buffer));
continue;
}
@@ -1521,26 +1554,37 @@ function prepareOfficialAgentRunCliArgs(args: string[]): PreparedAgentRunCliArgs
const source = args[i + 1];
if (source === undefined || source.length === 0) throw new Error(`${arg} requires a path`);
const buffer = source === "-" ? stdin() : readFileSync(source);
if (source === "-") {
const stdinFlag = stdinFlagForFileFlag(arg);
if (!stdinFlag) throw new Error(`${arg} does not support stdin`);
forwardStdin(stdinFlag, "stdin", buffer);
prepared.push(stdinFlag);
i += 1;
continue;
}
prepared.push(arg, materialize(arg, source === "-" ? "stdin" : source, buffer));
i += 1;
continue;
}
if (arg === "--prompt-stdin" || arg === "--stdin") {
prepared.push("--prompt-file", materialize("--prompt-stdin", "stdin", stdin()));
forwardStdin("--prompt-stdin", "stdin", stdin());
prepared.push("--prompt-stdin");
continue;
}
if (arg === "--json-stdin") {
prepared.push("--json-file", materialize("--json-stdin", "stdin", stdin()));
forwardStdin("--json-stdin", "stdin", stdin());
prepared.push("--json-stdin");
continue;
}
if (arg === "--runner-json-stdin") {
prepared.push("--runner-json-file", materialize("--runner-json-stdin", "stdin", stdin()));
forwardStdin("--runner-json-stdin", "stdin", stdin());
prepared.push("--runner-json-stdin");
continue;
}
prepared.push(arg);
}
return { args: prepared, materializedFiles };
return { args: prepared, materializedFiles, stdinPayload };
}
function officialAgentRunCliScript(prepared: PreparedAgentRunCliArgs): string {
@@ -1552,11 +1596,15 @@ function officialAgentRunCliScript(prepared: PreparedAgentRunCliArgs): string {
"trap 'rm -rf \"$tmp_dir\"' EXIT",
...prepared.materializedFiles.map((file) => `printf %s ${shQuote(file.base64)} | base64 -d > ${shQuote(file.remotePath)}`),
];
const cliCommand = `./scripts/agentrun --manager-url auto ${prepared.args.map(shQuote).join(" ")}`;
const invocation = prepared.stdinPayload
? `printf %s ${shQuote(prepared.stdinPayload.base64)} | base64 -d | ${cliCommand}`
: cliCommand;
return [
"set -euo pipefail",
...setup,
"cd /root/agentrun-v01",
`./scripts/agentrun --manager-url auto ${prepared.args.map(shQuote).join(" ")}`,
invocation,
].join("\n");
}
@@ -1565,7 +1613,7 @@ function parentDir(pathValue: string): string {
return index > 0 ? pathValue.slice(0, index) : ".";
}
function agentRunQueueBridgeMetadata(materializedFiles: AgentRunCliMaterializedFile[]): Record<string, unknown> {
function agentRunQueueBridgeMetadata(materializedFiles: AgentRunCliMaterializedFile[], stdinPayload: AgentRunCliForwardedStdin | null): Record<string, unknown> {
return {
route: g14SourceRoute,
sourceWorktree: "/root/agentrun-v01",
@@ -1574,6 +1622,11 @@ function agentRunQueueBridgeMetadata(materializedFiles: AgentRunCliMaterializedF
officialCli: "./scripts/agentrun",
mode: "direct-official-cli",
compatibility: "no-code-queue-adapter-no-double-write",
stdinForwarded: stdinPayload ? {
flag: stdinPayload.flag,
source: stdinPayload.source,
bytes: stdinPayload.bytes,
} : null,
fileFlagsMaterialized: materializedFiles.map((file) => ({
flag: file.flag,
source: file.source,