fix(agentrun): 收敛 Target 派单输出

This commit is contained in:
Codex
2026-07-13 09:56:58 +02:00
parent 982d45b1bf
commit 49b45ed868
4 changed files with 511 additions and 12 deletions
+202 -1
View File
@@ -1,6 +1,13 @@
import { readFileSync, rmSync } from "node:fs";
import { describe, expect, test } from "bun:test";
import { parseAgentRunClientConfigYaml, resolveAgentRunAuth, runAgentRunCommand, stripAgentRunResourceWrapperArgs } from "./agentrun";
import {
parseAgentRunClientConfigYaml,
parseResourceOptions,
renderMutationSummary,
resolveAgentRunAuth,
runAgentRunCommand,
stripAgentRunResourceWrapperArgs,
} from "./agentrun";
import { resolveAgentRunLaneTarget } from "./agentrun-lanes";
import { agentRunToolCredentialRefs } from "./agentrun/config";
import { autoDispatchTargetTask, targetTaskDispatchDryRunPlan } from "./agentrun/rest-bridge";
@@ -318,6 +325,200 @@ describe("Artificer Target one-command dispatch", () => {
rmSync(tempConfigPath, { force: true });
}
});
test("keeps Target live human, JSON, and YAML output bounded while retaining dispatch identities", () => {
const outputConfig = Bun.YAML.parse(
readFileSync(new URL("../../config/unidesk-cli.yaml", import.meta.url), "utf8"),
) as { output?: { maxStdoutBytes?: number } };
const maxStdoutBytes = outputConfig.output?.maxStdoutBytes;
if (typeof maxStdoutBytes !== "number") throw new Error("expected YAML-first output.maxStdoutBytes");
const hugePrompt = "PROMPT_SHOULD_NOT_BE_RENDERED_".repeat(500);
expect(Buffer.byteLength(hugePrompt, "utf8")).toBeGreaterThan(maxStdoutBytes);
const identity = {
taskId: "qt_compact_target",
taskState: "running",
attemptId: "qat_compact_target",
runId: "run_compact_target",
commandId: "cmd_compact_target",
runnerJobId: "rjob_compact_target",
sessionId: "sess_compact_target",
valuesPrinted: false,
};
const autoDispatch = {
enabled: true,
decision: "dispatched",
mutation: true,
duplicateDispatchPrevented: false,
identity,
valuesPrinted: false,
};
const raw = {
ok: true,
action: "queue-submit-auto-dispatch",
data: {
...identity,
attemptState: "running",
runState: "running",
commandState: "running",
runnerState: "claimed",
sessionState: "active",
mutation: true,
autoDispatch,
task: {
id: identity.taskId,
state: identity.taskState,
prompt: hugePrompt,
payload: { prompt: hugePrompt },
latestAttempt: {
attemptId: identity.attemptId,
state: "running",
runnerJobId: identity.runnerJobId,
runnerState: "claimed",
sessionId: identity.sessionId,
},
},
run: {
id: identity.runId,
state: "running",
sessionRef: { sessionId: identity.sessionId, state: "active" },
},
command: { id: identity.commandId, state: "running", payload: { prompt: hugePrompt } },
latestAttempt: {
attemptId: identity.attemptId,
state: "running",
runId: identity.runId,
commandId: identity.commandId,
runnerJobId: identity.runnerJobId,
runnerState: "claimed",
sessionId: identity.sessionId,
},
session: { id: identity.sessionId, state: "active", prompt: hugePrompt },
valuesPrinted: false,
},
targetTask: {
mdtodoId: "R6.4",
target: "NC01",
targetWorkspace: "/root/.worktrees/unidesk/artificer-compact-output",
targetRoute: "NC01:/root/.worktrees/unidesk/artificer-compact-output",
projectId: "pikasTech/unidesk",
repository: "pikasTech/unidesk",
ref: "fix/artificer-compact-output",
verifiedCommit: "a".repeat(40),
refRelation: "branch-and-head-match-remote-ref",
workspace: {
branch: "fix/artificer-compact-output",
headCommit: "a".repeat(40),
clean: true,
},
prompt: hugePrompt,
},
aipodBinding: {
aipod: "Artificer",
node: "NC01",
lane: "nc01-v02",
namespace: "agentrun-v01",
projectId: "pikasTech/unidesk",
providerId: "NC01",
backendProfile: "sub2api",
workspaceRef: { kind: "opaque", path: ".", valid: true },
resourceBundleRef: {
kind: "gitbundle",
repoUrl: "https://credential-must-be-redacted@github.com/pikasTech/unidesk.git",
ref: "fix/artificer-compact-output",
inheritedFromAipod: true,
credentialRefPresent: true,
},
session: { sessionId: identity.sessionId, identitySource: "task" },
providerCredentials: [{
profile: "sub2api",
secretRef: { namespace: "agentrun-v01", name: "agentrun-provider", keys: ["auth.json"] },
bindingPresent: true,
value: hugePrompt,
}],
toolCredentials: [{
tool: "github",
purpose: "pull-request",
secretRef: { namespace: "agentrun-v01", name: "agentrun-github", keys: ["GH_TOKEN"] },
bindingPresent: true,
value: hugePrompt,
}],
prompt: hugePrompt,
},
autoDispatch,
valuesPrinted: false,
};
expect(Buffer.byteLength(JSON.stringify(raw), "utf8")).toBeGreaterThan(maxStdoutBytes);
const variants = [
{ name: "human", args: [] },
{ name: "json", args: ["-o", "json"] },
{ name: "yaml", args: ["-o", "yaml"] },
];
for (const variant of variants) {
const rendered = renderMutationSummary(
"agentrun queue submit",
raw,
parseResourceOptions(variant.args),
"Queue task submitted",
);
const text = renderedTextOf(rendered);
expect(Buffer.byteLength(text, "utf8"), variant.name).toBeLessThan(maxStdoutBytes);
expect(text).not.toContain("PROMPT_SHOULD_NOT_BE_RENDERED_");
expect(text).not.toContain("credential-must-be-redacted");
for (const value of Object.values(identity).filter((item): item is string => typeof item === "string")) {
expect(text, `${variant.name}:${value}`).toContain(value);
}
expect(text).toContain("R6.4");
expect(text).toContain("dispatched");
}
const jsonText = renderedTextOf(renderMutationSummary(
"agentrun queue submit",
raw,
parseResourceOptions(["-o", "json"]),
"Queue task submitted",
));
const json = JSON.parse(jsonText) as Record<string, unknown>;
const jsonData = json.data as Record<string, unknown>;
const jsonNext = json.next as Record<string, unknown>;
const jsonCredentials = (json.aipodBinding as Record<string, unknown>).credentialRefs as Record<string, unknown>;
expect(jsonData).toMatchObject({
taskId: identity.taskId,
taskState: "running",
attemptId: identity.attemptId,
attemptState: "running",
runId: identity.runId,
runState: "running",
commandId: identity.commandId,
commandState: "running",
runnerJobId: identity.runnerJobId,
runnerState: "claimed",
sessionId: identity.sessionId,
sessionState: "active",
});
expect((json.autoDispatch as Record<string, unknown>).decision).toBe("dispatched");
expect((json.targetTask as Record<string, unknown>).mdtodoId).toBe("R6.4");
expect(jsonCredentials).toMatchObject({ totalCount: 2, allPresent: true });
expect((jsonCredentials.provider as Record<string, unknown>).presentCount).toBe(1);
expect((jsonCredentials.tool as Record<string, unknown>).presentCount).toBe(1);
expect(jsonNext.result).toBe(
`bun scripts/cli.ts agentrun result run/${identity.runId} --command ${identity.commandId} --target NC01 --lane nc01-v02`,
);
expect(jsonNext.logs).toBe(
`bun scripts/cli.ts agentrun logs session/${identity.sessionId} --tail 120 --target NC01 --lane nc01-v02`,
);
const yamlText = renderedTextOf(renderMutationSummary(
"agentrun queue submit",
raw,
parseResourceOptions(["-o", "yaml"]),
"Queue task submitted",
));
const yaml = Bun.YAML.parse(yamlText) as Record<string, unknown>;
expect(yaml.data).toMatchObject(json.data as object);
expect(yaml.next).toMatchObject(json.next as object);
});
});
describe("AgentRun default transport contract", () => {