fix(frontend): nouvelle conversation par défaut à l'ouverture et au lancement d'un agent — #371 (QA verte)
cause: l'ouverture d'IdeA ou le lancement ordinaire d'un agent dérivait la sélection UI du conversationId persisté sur la leaf (T4b), exposant l'ancien fil par défaut au retour d'application ; la persistance du pivot runtime/historique était confondue avec un choix de reprise. fix: le lancement ordinaire d'une cellule agent passe désormais freshStart: true sans transmettre le conversationId de la leaf — seul un resume explicite (menu Conversations / sélection intentional) fournit un id ; CustomAgentChatView reçoit freshOnOpen du LeafView, donc une ouverture normale démarre sur une nouvelle conversation quand aucune session structurée live n'existe ; garde de continuité préservée : si une session structurée est toujours vivante (remount transitoire), réattach live sans fresh ; l'id assigné par un lancement reste persisté sur la leaf via setCellConversation mais uniquement comme pivot runtime/historique, jamais comme sélection UI implicite (#371) ; contrats ports/domain/adapters/useLayout réalignés (assignedConversationId, launchAgent, LeafCell.conversationId). tests: ouverture ordinaire = nouvelle conversation sans readPage ni reprise ; resume explicite toujours fonctionnel ; continuité live au remontage avec session vivante préservée. QA verte: git diff --check ; npm run typecheck ; vitest ciblé setCellConversation/CustomAgentChatView/resumeProject/LayoutGrid/LayoutGrid.chat 144/144 ; npm test src/features/agents src/features/layout 350/350. fichiers .ideai/* et scripts/ hors périmètre ; aucun push. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -1069,8 +1069,8 @@ export function CustomAgentChatView({
|
||||
() => new Set(),
|
||||
);
|
||||
const [currentSession, setCurrentSession] = useState(sessionId);
|
||||
// `freshOnOpen` is reserved for an explicit reset intent. Ordinary React
|
||||
// remounts keep the durable conversation selected by the hosting cell.
|
||||
// A normal cell opening starts fresh when no live session exists. React
|
||||
// remounts with a live session still preserve that runtime continuity.
|
||||
const [activeConversationId, setActiveConversationId] = useState<string | null>(
|
||||
sessionId || !freshOnOpen ? conversationId : null,
|
||||
);
|
||||
@ -2005,6 +2005,7 @@ export function CustomAgentChatView({
|
||||
options.conversationId === undefined
|
||||
? activeConversationIdRef.current ?? undefined
|
||||
: options.conversationId ?? undefined,
|
||||
...(options.conversationId === null ? { freshStart: true } : {}),
|
||||
...(nodeId ? { nodeId } : {}),
|
||||
};
|
||||
console.debug("[ticket149] recoverStructuredSession:launchAgentChat:start", {
|
||||
@ -2266,6 +2267,29 @@ export function CustomAgentChatView({
|
||||
setSavedConversationLoadState("idle");
|
||||
setLiveSessionAttached(false);
|
||||
if (freshOnOpen) {
|
||||
// A missing layout session can be a transient remount while this
|
||||
// agent is still active. Preserve that live continuity without
|
||||
// treating the leaf's persisted conversation id as a UI choice.
|
||||
const live = agent.listLiveAgents
|
||||
? (await agent.listLiveAgents(projectId)).find(
|
||||
(candidate) =>
|
||||
candidate.agentId === agentId && candidate.kind === "structured",
|
||||
)
|
||||
: undefined;
|
||||
if (live) {
|
||||
const rebound =
|
||||
nodeId && live.nodeId !== nodeId && agent.attachLiveAgent
|
||||
? await agent.attachLiveAgent(projectId, agentId, nodeId)
|
||||
: live;
|
||||
const attachedSessionId = await reattachStructuredSession(rebound.sessionId, {
|
||||
applyScrollback: true,
|
||||
preserveViewOnEmptyScrollback: true,
|
||||
});
|
||||
if (cancelled) return;
|
||||
publishSessionId(attachedSessionId);
|
||||
setResumedConversation(false);
|
||||
return;
|
||||
}
|
||||
await recoverStructuredSession({
|
||||
applyScrollback: false,
|
||||
retryAttachNotFound: true,
|
||||
|
||||
Reference in New Issue
Block a user