feat(agent): UI hot-swap de profil (A2) — commande Tauri + sélecteur + dialog
- Tauri : commande change_agent_profile + ChangeAgentProfileRequestDto/Dto (camelCase, relaunchedSession omis si None), câblage state.rs par composition. - Front : gateway changeAgentProfile (adapters Tauri+mock), sélecteur de profil par agent, dialog de confirmation FR (« Changer le moteur abandonne l'historique de conversation… »), refresh sur event agentProfileChanged. Tests : app-tauri dto 5/5 ; vitest 314/314 (mapping, payload, dialog gating, libellé FR, refresh). 0 régression. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -9,7 +9,12 @@
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import type { Agent, AgentProfile, GatewayError } from "@/domain";
|
||||
import type {
|
||||
Agent,
|
||||
AgentProfile,
|
||||
GatewayError,
|
||||
TerminalSession,
|
||||
} from "@/domain";
|
||||
import type { LiveAgent, OpenTerminalOptions, TerminalHandle } from "@/ports";
|
||||
import { useGateways } from "@/app/di";
|
||||
|
||||
@ -44,6 +49,19 @@ export interface AgentsViewModel {
|
||||
selectAgent: (agentId: string) => Promise<void>;
|
||||
/** Saves the context for the currently selected agent. */
|
||||
saveContext: (content: string) => Promise<void>;
|
||||
/**
|
||||
* Hot-swaps an agent's runtime AI profile. The caller is expected to have
|
||||
* confirmed with the user first (the conversation history is abandoned). On a
|
||||
* live agent the backend relaunches the session and returns it so the cell can
|
||||
* rebind; the agent list is refreshed locally. Returns the relaunched session,
|
||||
* if any, so the panel can rebind the hosting cell.
|
||||
*/
|
||||
changeAgentProfile: (
|
||||
agentId: string,
|
||||
profileId: string,
|
||||
rows: number,
|
||||
cols: number,
|
||||
) => Promise<TerminalSession | undefined>;
|
||||
/** Deletes an agent; deselects if it was selected. */
|
||||
deleteAgent: (agentId: string) => Promise<void>;
|
||||
/**
|
||||
@ -124,7 +142,11 @@ export function useAgents(projectId: string): AgentsViewModel {
|
||||
let cancelled = false;
|
||||
void system
|
||||
.onDomainEvent((event) => {
|
||||
if (event.type === "agentLaunched" || event.type === "agentExited") {
|
||||
if (
|
||||
event.type === "agentLaunched" ||
|
||||
event.type === "agentExited" ||
|
||||
event.type === "agentProfileChanged"
|
||||
) {
|
||||
void refresh();
|
||||
void refreshLiveAgents();
|
||||
}
|
||||
@ -193,6 +215,38 @@ export function useAgents(projectId: string): AgentsViewModel {
|
||||
[agent, projectId, selectedAgentId],
|
||||
);
|
||||
|
||||
const changeAgentProfile = useCallback(
|
||||
async (
|
||||
agentId: string,
|
||||
profileId: string,
|
||||
rows: number,
|
||||
cols: number,
|
||||
): Promise<TerminalSession | undefined> => {
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
try {
|
||||
const { agent: updated, relaunchedSession } =
|
||||
await agent.changeAgentProfile(projectId, agentId, profileId, rows, cols);
|
||||
// Reflect the new profile locally; the `agentProfileChanged` event (when
|
||||
// wired) also triggers a full refresh, but updating here keeps the UI
|
||||
// responsive offline / in tests.
|
||||
setAgents((prev) =>
|
||||
prev.map((a) => (a.id === updated.id ? updated : a)),
|
||||
);
|
||||
// A hot relaunch produces a fresh live session id — keep the live list
|
||||
// in sync so the cell can rebind.
|
||||
void refreshLiveAgents();
|
||||
return relaunchedSession;
|
||||
} catch (e) {
|
||||
setError(describe(e));
|
||||
return undefined;
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
},
|
||||
[agent, projectId, refreshLiveAgents],
|
||||
);
|
||||
|
||||
const deleteAgent = useCallback(
|
||||
async (agentId: string) => {
|
||||
setBusy(true);
|
||||
@ -271,6 +325,7 @@ export function useAgents(projectId: string): AgentsViewModel {
|
||||
createAgent,
|
||||
selectAgent,
|
||||
saveContext,
|
||||
changeAgentProfile,
|
||||
deleteAgent,
|
||||
launchAgent,
|
||||
stopAgent,
|
||||
|
||||
Reference in New Issue
Block a user