fix: sync terminal workbench conversation
This commit is contained in:
@@ -397,7 +397,7 @@ test("workbench workspace status clears completed AgentRun active trace on read"
|
||||
threadId: "thread-issue-664",
|
||||
sessionStatus: "active",
|
||||
lastTraceId: "trc_issue664_previous",
|
||||
messages: [{ role: "agent", text: "previous turn", traceId: "trc_issue664_previous" }]
|
||||
messages: [{ role: "agent", text: "previous turn still running", status: "running", traceId: "trc_issue664_status_done" }]
|
||||
}, aliceLogin.cookie);
|
||||
assert.equal(conversation.status, 200);
|
||||
|
||||
@@ -441,6 +441,11 @@ test("workbench workspace status clears completed AgentRun active trace on read"
|
||||
assert.equal(restored.body.workspace.activeTraceId, null);
|
||||
assert.equal(restored.body.workspace.workspace.lastTraceId, "trc_issue664_status_done");
|
||||
assert.equal(restored.body.workspace.workspace.sessionStatus, "idle");
|
||||
assert.equal(restored.body.workspace.selectedConversation.status, "idle");
|
||||
assert.equal(restored.body.workspace.selectedConversation.lastTraceId, "trc_issue664_status_done");
|
||||
assert.equal(restored.body.workspace.selectedConversation.messages.length, 1);
|
||||
assert.equal(restored.body.workspace.selectedConversation.messages[0].status, "idle");
|
||||
assert.equal(restored.body.workspace.selectedConversation.messages[0].text, "previous turn completed");
|
||||
assert.equal(restored.body.workspace.revision, 3);
|
||||
assert.ok(agentRunCalls.some((call) => call.path === "/api/v1/runs/run_workspace_status/commands/cmd_workspace_status/result"));
|
||||
} finally {
|
||||
|
||||
@@ -871,6 +871,15 @@ class AccessController {
|
||||
const workspaceJson = normalizeObject(workspace.workspace);
|
||||
const selectedConversationId = safeConversationIdLocal(result.conversationId) ? result.conversationId : workspace.selectedConversationId;
|
||||
const selectedAgentSessionId = safeAgentSessionId(result.sessionId ?? result.session?.sessionId ?? result.sessionReuse?.sessionId) || workspace.selectedAgentSessionId;
|
||||
await this.syncTerminalWorkbenchConversation({
|
||||
workspace,
|
||||
actor,
|
||||
result,
|
||||
activeTraceId,
|
||||
selectedConversationId,
|
||||
selectedAgentSessionId,
|
||||
now
|
||||
});
|
||||
const updated = await this.store.updateWorkspace?.({
|
||||
workspaceId: workspace.id,
|
||||
ownerUserId: workspace.ownerUserId,
|
||||
@@ -913,6 +922,39 @@ class AccessController {
|
||||
return publicWorkbenchWorkspace(workspace, { conversation, selectedDevicePod });
|
||||
}
|
||||
|
||||
async syncTerminalWorkbenchConversation({ workspace, actor, result, activeTraceId, selectedConversationId, selectedAgentSessionId, now }) {
|
||||
if (!safeConversationIdLocal(selectedConversationId) || !safeAgentSessionId(selectedAgentSessionId)) return null;
|
||||
const existing = await this.visibleConversationForActor(actor, selectedConversationId, workspace.projectId);
|
||||
const sessionStatus = terminalWorkbenchSessionStatus(result);
|
||||
const threadId = textOr(result.threadId ?? result.session?.threadId ?? result.sessionReuse?.threadId ?? result.providerTrace?.threadId, existing?.threadId ?? null);
|
||||
const messages = mergeTerminalConversationMessages(existing?.messages, result, {
|
||||
traceId: activeTraceId,
|
||||
conversationId: selectedConversationId,
|
||||
sessionId: selectedAgentSessionId,
|
||||
threadId,
|
||||
now
|
||||
});
|
||||
return await this.recordAgentSessionOwner({
|
||||
ownerUserId: actor.id,
|
||||
sessionId: selectedAgentSessionId,
|
||||
projectId: workspace.projectId,
|
||||
agentId: existing?.agentId ?? "hwlab-code-agent",
|
||||
status: sessionStatus,
|
||||
conversationId: selectedConversationId,
|
||||
threadId,
|
||||
traceId: activeTraceId,
|
||||
session: normalizeConversationSnapshot({
|
||||
...(existing?.snapshot ?? {}),
|
||||
source: "workbench-status-sync",
|
||||
sessionStatus,
|
||||
updatedAt: now,
|
||||
lastTraceId: activeTraceId,
|
||||
messages
|
||||
}, actor),
|
||||
now
|
||||
});
|
||||
}
|
||||
|
||||
async visibleConversationForActor(actor, conversationId, projectId = "") {
|
||||
if (!safeConversationIdLocal(conversationId)) return null;
|
||||
const sessions = await this.store.listAgentSessionsForUser?.({
|
||||
@@ -1943,6 +1985,43 @@ function canActorReadWorkspaceTrace(result = {}, actor = null) {
|
||||
if (!ownerUserId || actor?.role === "admin") return true;
|
||||
return ownerUserId === actor?.id;
|
||||
}
|
||||
function mergeTerminalConversationMessages(existingMessages = [], result = {}, context = {}) {
|
||||
const messages = Array.isArray(existingMessages) ? existingMessages.map(redactConversationMessage).filter(Boolean) : [];
|
||||
const traceId = safeTraceIdLocal(result.traceId ?? context.traceId);
|
||||
const terminalStatus = terminalWorkbenchSessionStatus(result);
|
||||
const assistantText = textOr(result.reply?.content ?? result.assistantText ?? result.message?.content ?? result.error?.message ?? result.userMessage, "");
|
||||
const now = textOr(context.now, new Date().toISOString());
|
||||
const next = messages.map((message) => {
|
||||
if (traceId && message.traceId === traceId && message.role === "agent") {
|
||||
return redactConversationMessage({
|
||||
...message,
|
||||
text: assistantText || message.text,
|
||||
status: terminalStatus,
|
||||
conversationId: context.conversationId ?? message.conversationId,
|
||||
sessionId: context.sessionId ?? message.sessionId,
|
||||
threadId: context.threadId ?? message.threadId,
|
||||
updatedAt: now
|
||||
});
|
||||
}
|
||||
return message;
|
||||
}).filter(Boolean);
|
||||
if (traceId && !next.some((message) => message.traceId === traceId && message.role === "agent")) {
|
||||
next.push(redactConversationMessage({
|
||||
id: result.reply?.messageId ?? result.messageId ?? `msg_${traceId.slice(4)}`,
|
||||
role: "agent",
|
||||
title: "Code Agent result",
|
||||
text: assistantText,
|
||||
status: terminalStatus,
|
||||
traceId,
|
||||
conversationId: context.conversationId,
|
||||
sessionId: context.sessionId,
|
||||
threadId: context.threadId,
|
||||
createdAt: result.reply?.createdAt ?? result.createdAt ?? now,
|
||||
updatedAt: now
|
||||
}));
|
||||
}
|
||||
return next.slice(-50);
|
||||
}
|
||||
function redactConversationMessage(message) {
|
||||
if (!message || typeof message !== "object") return null;
|
||||
const runnerTrace = message.runnerTrace && typeof message.runnerTrace === "object" ? message.runnerTrace : null;
|
||||
|
||||
Reference in New Issue
Block a user