fix: align hwlab cli agent send with web short submit
This commit is contained in:
@@ -244,7 +244,7 @@ test("hwlab-cli client gateway pressure reports byte/truncation visibility", asy
|
||||
assert.match(result.payload.results.find((item: any) => item.name === "large-stdout").stdoutSha256, /^[a-f0-9]{64}$/u);
|
||||
});
|
||||
|
||||
test("hwlab-cli client agent send submits async and polls result", async () => {
|
||||
test("hwlab-cli client agent send submits async and returns trace without waiting by default", async () => {
|
||||
const calls: any[] = [];
|
||||
const result = await runHwlabCli([
|
||||
"client",
|
||||
@@ -259,11 +259,7 @@ test("hwlab-cli client agent send submits async and polls result", async () => {
|
||||
"--trace-id",
|
||||
"trc_test",
|
||||
"--conversation-id",
|
||||
"cnv_test",
|
||||
"--poll-interval-ms",
|
||||
"1",
|
||||
"--timeout-ms",
|
||||
"1000"
|
||||
"cnv_test"
|
||||
], {
|
||||
fetchImpl: async (url, init) => {
|
||||
calls.push({ url: String(url), init, body: init?.body ? JSON.parse(String(init.body)) : null });
|
||||
@@ -273,9 +269,6 @@ test("hwlab-cli client agent send submits async and polls result", async () => {
|
||||
if (String(url).endsWith("/v1/agent/chat")) {
|
||||
return new Response(JSON.stringify({ accepted: true, status: "running", traceId: "trc_test", resultUrl: "/v1/agent/chat/result/trc_test" }), { status: 202 });
|
||||
}
|
||||
if (String(url).endsWith("/v1/workbench/workspace/wsp_test")) {
|
||||
return new Response(JSON.stringify({ ok: true, workspace: { workspaceId: "wsp_test", revision: 5, selectedConversationId: "cnv_test", selectedAgentSessionId: "ses_test", workspace: { threadId: "thread-test", sessionStatus: "completed" } } }), { status: 200 });
|
||||
}
|
||||
return new Response(JSON.stringify({ status: "completed", traceId: "trc_test", conversationId: "cnv_test", reply: { role: "assistant", content: "hi" } }), { status: 200 });
|
||||
},
|
||||
sleep: async () => {}
|
||||
@@ -290,11 +283,58 @@ test("hwlab-cli client agent send submits async and polls result", async () => {
|
||||
assert.equal(calls[1].body.expectedWorkspaceRevision, 3);
|
||||
assert.equal(calls[1].body.sessionId, "ses_test");
|
||||
assert.equal(calls[1].body.threadId, "thread-test");
|
||||
assert.equal(calls[2].url, "http://web.test/v1/agent/chat/result/trc_test");
|
||||
assert.equal(calls[3].url, "http://web.test/v1/workbench/workspace/wsp_test");
|
||||
assert.equal(calls.length, 2);
|
||||
assert.equal(result.payload.traceId, "trc_test");
|
||||
assert.equal(result.payload.waited, false);
|
||||
assert.equal(result.payload.waitPolicy.defaultWait, false);
|
||||
assert.equal(result.payload.waitPolicy.webEquivalent, true);
|
||||
assert.ok(result.payload.waitPolicy.nextCommands.some((command: string) => command.includes("agent result trc_test")));
|
||||
});
|
||||
|
||||
test("hwlab-cli client agent send waits only when --wait is explicit", async () => {
|
||||
const calls: any[] = [];
|
||||
const result = await runHwlabCli([
|
||||
"client",
|
||||
"agent",
|
||||
"send",
|
||||
"--base-url",
|
||||
"http://web.test",
|
||||
"--cookie",
|
||||
"hwlab_session=session-a",
|
||||
"--message",
|
||||
"hello",
|
||||
"--trace-id",
|
||||
"trc_wait",
|
||||
"--conversation-id",
|
||||
"cnv_wait",
|
||||
"--wait",
|
||||
"--poll-interval-ms",
|
||||
"1",
|
||||
"--timeout-ms",
|
||||
"1000"
|
||||
], {
|
||||
fetchImpl: async (url, init) => {
|
||||
calls.push({ url: String(url), init, body: init?.body ? JSON.parse(String(init.body)) : null });
|
||||
if (String(url).endsWith("/v1/workbench/workspace?projectId=prj_device_pod_workbench")) {
|
||||
return new Response(JSON.stringify({ ok: true, workspace: { workspaceId: "wsp_wait", revision: 3, selectedConversationId: "cnv_wait", selectedAgentSessionId: "ses_wait", workspace: { threadId: "thread-wait" } } }), { status: 200 });
|
||||
}
|
||||
if (String(url).endsWith("/v1/agent/chat")) {
|
||||
return new Response(JSON.stringify({ accepted: true, status: "running", traceId: "trc_wait", resultUrl: "/v1/agent/chat/result/trc_wait" }), { status: 202 });
|
||||
}
|
||||
if (String(url).endsWith("/v1/workbench/workspace/wsp_wait")) {
|
||||
return new Response(JSON.stringify({ ok: true, workspace: { workspaceId: "wsp_wait", revision: 5, selectedConversationId: "cnv_wait", selectedAgentSessionId: "ses_wait", workspace: { threadId: "thread-wait", sessionStatus: "completed" } } }), { status: 200 });
|
||||
}
|
||||
return new Response(JSON.stringify({ status: "completed", traceId: "trc_wait", conversationId: "cnv_wait", reply: { role: "assistant", content: "hi" } }), { status: 200 });
|
||||
},
|
||||
sleep: async () => {}
|
||||
});
|
||||
|
||||
assert.equal(result.exitCode, 0);
|
||||
assert.equal(calls[2].url, "http://web.test/v1/agent/chat/result/trc_wait");
|
||||
assert.equal(calls[3].url, "http://web.test/v1/workbench/workspace/wsp_wait");
|
||||
assert.equal(Object.hasOwn(calls[3].body, "activeTraceId"), true);
|
||||
assert.equal(calls[3].body.activeTraceId, null);
|
||||
assert.equal(result.payload.traceId, "trc_test");
|
||||
assert.equal(result.payload.traceId, "trc_wait");
|
||||
assert.equal(result.payload.result.body.status, "completed");
|
||||
assert.equal(result.payload.result.body.assistantText, "hi");
|
||||
assert.equal(result.payload.result.body.reply.content, "hi");
|
||||
@@ -323,8 +363,7 @@ test("hwlab-cli client agent send preserves Web continuation fields", async () =
|
||||
"--thread-id",
|
||||
"019e8078-db67-7750-a5d9-1a99f3abd445",
|
||||
"--retry-of",
|
||||
"trc_previous",
|
||||
"--no-wait"
|
||||
"trc_previous"
|
||||
], {
|
||||
cwd,
|
||||
fetchImpl: async (url, init) => {
|
||||
@@ -367,8 +406,7 @@ test("hwlab-cli client agent send can replay continuation from an existing trace
|
||||
"--from-trace",
|
||||
"trc_source_web",
|
||||
"--trace-id",
|
||||
"trc_replay_web",
|
||||
"--no-wait"
|
||||
"trc_replay_web"
|
||||
], {
|
||||
fetchImpl: async (url, init) => {
|
||||
calls.push({ url: String(url), init, body: init?.body ? JSON.parse(String(init.body)) : null });
|
||||
@@ -438,9 +476,9 @@ test("hwlab-cli client agent trace can render with the Web trace row path", asyn
|
||||
assert.equal(result.payload.body.render, "web");
|
||||
assert.equal(result.payload.body.renderer, "web/hwlab-cloud-web/app-trace:traceDisplayRows");
|
||||
assert.equal(result.payload.body.sourceEventCount, 3);
|
||||
assert.ok(result.payload.body.renderedRowCount >= 2);
|
||||
assert.ok(result.payload.body.rows.some((row: any) => /请求接受/u.test(row.header)));
|
||||
assert.ok(result.payload.body.renderedRowCount >= 1);
|
||||
assert.ok(result.payload.body.rows.some((row: any) => /助手最后一条消息/u.test(row.header)));
|
||||
assert.equal(JSON.stringify(result.payload.body.rows).includes("session:reused"), false);
|
||||
});
|
||||
|
||||
test("hwlab-cli Web trace render reports suppressed noise and command tool details", async () => {
|
||||
|
||||
@@ -119,7 +119,8 @@ function help() {
|
||||
"hwlab-cli client workbench reset --profile NAME --confirm",
|
||||
"hwlab-cli client request GET /v1/access/status [--full]",
|
||||
"hwlab-cli client rpc system.health [--full]",
|
||||
"hwlab-cli client agent send --message TEXT|--message-file PATH [--from-trace TRACE] [--conversation-id ID] [--session-id ID] [--thread-id ID] [--retry-of TRACE] --provider-profile deepseek --timeout-ms 120000",
|
||||
"hwlab-cli client agent send --message TEXT|--message-file PATH [--from-trace TRACE] [--conversation-id ID] [--session-id ID] [--thread-id ID] [--retry-of TRACE] --provider-profile deepseek",
|
||||
"hwlab-cli client agent send --message TEXT --wait --timeout-ms 50000",
|
||||
"hwlab-cli client agent result TRACE_ID",
|
||||
"hwlab-cli client agent trace TRACE_ID [--render web]",
|
||||
"hwlab-cli client agent inspect --trace-id TRACE_ID",
|
||||
@@ -614,7 +615,8 @@ function agentHelp() {
|
||||
serviceRuntime: false,
|
||||
imagePublished: false,
|
||||
commands: [
|
||||
"send --message TEXT|--message-file PATH [--from-trace TRACE] [--conversation-id ID] [--session-id ID] [--thread-id ID] [--retry-of TRACE] [--no-wait]",
|
||||
"send --message TEXT|--message-file PATH [--from-trace TRACE] [--conversation-id ID] [--session-id ID] [--thread-id ID] [--retry-of TRACE] [default: short return]",
|
||||
"send --message TEXT --wait [--timeout-ms N] [--poll-interval-ms N]",
|
||||
"result TRACE_ID [--full]",
|
||||
"trace TRACE_ID [--render web] [--limit N] [--full]",
|
||||
"inspect --trace-id TRACE_ID|--conversation-id ID|--session-id ID|--thread-id ID",
|
||||
@@ -923,8 +925,8 @@ async function agentSend(context: any) {
|
||||
return responsePayload("client.agent.send", accepted, context, { route: route("POST", "/v1/agent/chat"), traceId, conversationId, continuation, replay: replay.summary });
|
||||
}
|
||||
await saveAcceptedAgentWorkspaceState(context, accepted.body, { traceId, conversationId, sessionId, threadId, providerProfile: requestBody.providerProfile });
|
||||
if (parsed.noWait === true) {
|
||||
return responsePayload("client.agent.send", accepted, context, { route: route("POST", "/v1/agent/chat"), traceId, conversationId, continuation, replay: replay.summary, workspace: workspaceSummaryFromSession(await loadStoredState({ parsed, env: context.env, cwd: context.cwd ?? process.cwd() })), waited: false });
|
||||
if (parsed.wait !== true) {
|
||||
return responsePayload("client.agent.send", accepted, context, { route: route("POST", "/v1/agent/chat"), traceId, conversationId, continuation, replay: replay.summary, workspace: workspaceSummaryFromSession(await loadStoredState({ parsed, env: context.env, cwd: context.cwd ?? process.cwd() })), waited: false, waitPolicy: agentSendWaitPolicy(traceId) });
|
||||
}
|
||||
const result = await pollAgentResult(context, traceId, accepted.body);
|
||||
await saveCompletedAgentWorkspaceState(context, result.response?.body, { traceId, conversationId, sessionId, threadId, providerProfile: requestBody.providerProfile });
|
||||
@@ -963,6 +965,20 @@ async function pollAgentResult(context: any, traceId: string, acceptedBody: any)
|
||||
return { final: false, response: lastResponse, polls, timeoutMs, resultPath };
|
||||
}
|
||||
|
||||
function agentSendWaitPolicy(traceId: string) {
|
||||
return {
|
||||
defaultWait: false,
|
||||
webEquivalent: true,
|
||||
reason: "Cloud Web submits /v1/agent/chat as a short request and observes progress by polling result/trace; CLI follows the same path by default to avoid UniDesk ssh/tran 60s runtime disconnects.",
|
||||
waitCommand: `hwlab-cli client agent send --from-trace ${traceId} --message TEXT --wait`,
|
||||
nextCommands: [
|
||||
`hwlab-cli client agent result ${traceId}`,
|
||||
`hwlab-cli client agent trace ${traceId} --render web`,
|
||||
`hwlab-cli client workbench status`
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
async function workbenchCommand(context: any) {
|
||||
const subcommand = context.rest[0] || "summary";
|
||||
if (wantsHelp(context)) return workbenchHelp();
|
||||
|
||||
Reference in New Issue
Block a user