fix: lock routed workbench composer session (#1323)
This commit is contained in:
@@ -21,6 +21,27 @@ test("R2 composer steers only when an active agent message or status exists", ()
|
||||
assert.equal(composer.targetTraceId, "trc_running");
|
||||
});
|
||||
|
||||
test("R2 composer never reuses a stale workspace session during routed selection", () => {
|
||||
const workspace = workspaceRecord({ activeTraceId: null, sessionStatus: "idle" });
|
||||
const withoutTarget = resolveComposerState({ workspace, messages: [], conversations: [], activeConversationId: "cnv_route", chatPending: false });
|
||||
assert.equal(withoutTarget.disabled, true);
|
||||
assert.equal(withoutTarget.disabledReason, "session_required");
|
||||
assert.equal(withoutTarget.conversationId, "cnv_route");
|
||||
assert.equal(withoutTarget.sessionId, null);
|
||||
|
||||
const withTarget = resolveComposerState({
|
||||
workspace,
|
||||
messages: [],
|
||||
conversations: [{ conversationId: "cnv_route", sessionId: "ses_route", threadId: "thr_route" }],
|
||||
activeConversationId: "cnv_route",
|
||||
chatPending: false
|
||||
});
|
||||
assert.equal(withTarget.disabled, false);
|
||||
assert.equal(withTarget.conversationId, "cnv_route");
|
||||
assert.equal(withTarget.sessionId, "ses_route");
|
||||
assert.equal(withTarget.threadId, "thr_route");
|
||||
});
|
||||
|
||||
test("R2 active trace cleanup preserves workspace and records stale reason", () => {
|
||||
const cleared = workspaceWithClearedActiveTrace(workspaceRecord({ activeTraceId: "trc_stale", sessionStatus: "running" }), "trc_stale", "steer-trace-not-found");
|
||||
assert.equal(cleared?.activeTraceId, null);
|
||||
|
||||
@@ -61,8 +61,13 @@ export function resolveComposerState(input: { workspace: WorkspaceRecord | null;
|
||||
const activeByStatus = isActiveStatus(runningMessage?.status) || isActiveStatus(runningMessage?.runnerTrace?.status) || isActiveStatus(currentRequest?.status) || input.chatPending;
|
||||
const terminal = isTerminalStatus(latestMessage?.status) || isTerminalStatus(currentRequest?.status) || (!latestMessage && isTerminalStatus(workspaceStatus));
|
||||
const conversationId = input.activeConversationId;
|
||||
const sessionId = firstNonEmptyString(runningMessage?.sessionId, currentRequest?.sessionId, input.workspace?.selectedAgentSessionId, input.workspace?.workspace?.selectedAgentSessionId, activeConversation(input.conversations ?? [], conversationId)?.sessionId);
|
||||
const threadId = firstNonEmptyString(runningMessage?.threadId, currentRequest?.threadId, input.workspace?.workspace?.threadId, activeConversation(input.conversations ?? [], conversationId)?.threadId);
|
||||
const active = activeConversation(input.conversations ?? [], conversationId);
|
||||
const workspaceConversationId = selectedConversationIdFromWorkspace(input.workspace);
|
||||
const workspaceMatchesConversation = !conversationId || !workspaceConversationId || workspaceConversationId === conversationId;
|
||||
const workspaceSessionId = workspaceMatchesConversation ? firstNonEmptyString(input.workspace?.selectedAgentSessionId, input.workspace?.workspace?.selectedAgentSessionId) : null;
|
||||
const workspaceThreadId = workspaceMatchesConversation ? firstNonEmptyString(input.workspace?.workspace?.threadId) : null;
|
||||
const sessionId = firstNonEmptyString(runningMessage?.sessionId, currentRequest?.sessionId, active?.sessionId, workspaceSessionId);
|
||||
const threadId = firstNonEmptyString(runningMessage?.threadId, currentRequest?.threadId, active?.threadId, workspaceThreadId);
|
||||
const canSteer = Boolean(conversationId && sessionId && activeTraceId && activeByStatus && !terminal);
|
||||
if (canSteer) return { disabled: false, disabledReason: null, submitMode: "steer", route: "/v1/agent/chat/steer", targetTraceId: activeTraceId, conversationId, sessionId, threadId };
|
||||
if (!sessionId) return { disabled: true, disabledReason: "session_required", submitMode: "turn", route: "/v1/agent/chat", targetTraceId: null, conversationId, sessionId: null, threadId };
|
||||
|
||||
@@ -132,15 +132,18 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
}
|
||||
const current = await ensureWorkspace();
|
||||
if (!current) return false;
|
||||
if (activeConversationId.value === normalized && messages.value.length > 0) return true;
|
||||
const requestEpoch = beginWorkspaceSelection();
|
||||
switchingConversationId.value = normalized;
|
||||
const existing = visibleConversations.value.find((conversation) => conversation.conversationId === normalized) ?? null;
|
||||
if (existing && (existing.messages?.length ?? 0) > 0) {
|
||||
if (activeConversationId.value === normalized && messages.value.length > 0) return true;
|
||||
await selectConversation(existing);
|
||||
return activeConversationId.value === normalized;
|
||||
}
|
||||
const response = await api.workbench.conversation(normalized);
|
||||
const conversation = response.data?.conversation ?? null;
|
||||
if (!response.ok || !conversation) {
|
||||
if (isCurrentWorkspaceSelection(requestEpoch, normalized)) clearSwitchingConversation(normalized);
|
||||
error.value = response.error ?? "session URL not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user