feat(agents): role orchestrateur du contexte global expose et configurable par agent — isOrchestrator distinct des permissions MCP, DTO update_project_orchestrator (terminologie wire legacy conservee), refus idea_context_update explicite avec writer effectif + orientation idea_context_propose, surface AgentsPanel + adaptateurs frontend — #276 (QA verte: cargo fmt/check, tests cibles application/app-tauri/infrastructure/backend, npm typecheck, 69/69 tests frontend agents/adapters)
This commit is contained in:
@ -176,6 +176,18 @@ describe("TauriAgentGateway invoke payloads", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("update_project_orchestrator wraps the project and agent in the request DTO", async () => {
|
||||
invoke.mockResolvedValueOnce({ orchestratorAgentId: "agent-2" });
|
||||
|
||||
await expect(
|
||||
new TauriAgentGateway().updateProjectOrchestrator("proj-1", "agent-2"),
|
||||
).resolves.toEqual({ orchestratorAgentId: "agent-2" });
|
||||
|
||||
expect(invoke).toHaveBeenCalledWith("update_project_orchestrator", {
|
||||
request: { projectId: "proj-1", agentId: "agent-2" },
|
||||
});
|
||||
});
|
||||
|
||||
it("cancelAgentChat invokes cancel_agent_chat without closing the session", async () => {
|
||||
await new TauriAgentGateway().cancelAgentChat("chat-session-1");
|
||||
|
||||
|
||||
@ -154,6 +154,16 @@ export class TauriAgentGateway implements AgentGateway {
|
||||
});
|
||||
}
|
||||
|
||||
updateProjectOrchestrator(
|
||||
projectId: string,
|
||||
agentId: string,
|
||||
): Promise<{ orchestratorAgentId: string }> {
|
||||
return invoke<{ orchestratorAgentId: string }>(
|
||||
"update_project_orchestrator",
|
||||
{ request: { projectId, agentId } },
|
||||
);
|
||||
}
|
||||
|
||||
readContext(projectId: string, agentId: string): Promise<string> {
|
||||
return invoke<AgentContextDocument>("read_agent_context", {
|
||||
projectId,
|
||||
|
||||
@ -141,6 +141,26 @@ describe("HttpAgentGateway WS round-trip (B6 frames)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("updates the project orchestrator through the dedicated request DTO", async () => {
|
||||
const response = { orchestratorAgentId: "agent-2" };
|
||||
const { gw, calls } = httpAgentGateway(async () => ({
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => response,
|
||||
text: async () => JSON.stringify(response),
|
||||
}));
|
||||
|
||||
await expect(
|
||||
gw.updateProjectOrchestrator("proj-1", "agent-2"),
|
||||
).resolves.toEqual(response);
|
||||
|
||||
const init = calls[0].init as { body: string };
|
||||
expect(JSON.parse(init.body)).toEqual({
|
||||
command: "update_project_orchestrator",
|
||||
args: { request: { projectId: "proj-1", agentId: "agent-2" } },
|
||||
});
|
||||
});
|
||||
|
||||
it("launch → attached: conforming agent.launch frame, assignedConversationId consumed", async () => {
|
||||
const { gw, sockets } = gateway();
|
||||
const chunks: Uint8Array[] = [];
|
||||
|
||||
@ -258,6 +258,15 @@ export class HttpAgentGateway implements AgentGateway {
|
||||
request: { projectId, agentId, contactable },
|
||||
});
|
||||
}
|
||||
updateProjectOrchestrator(
|
||||
projectId: string,
|
||||
agentId: string,
|
||||
): Promise<{ orchestratorAgentId: string }> {
|
||||
return this.http.invoke<{ orchestratorAgentId: string }>(
|
||||
"update_project_orchestrator",
|
||||
{ request: { projectId, agentId } },
|
||||
);
|
||||
}
|
||||
readContext(projectId: string, agentId: string): Promise<string> {
|
||||
return this.http
|
||||
.invoke<AgentContextDocument>("read_agent_context", { projectId, agentId })
|
||||
|
||||
@ -720,6 +720,24 @@ export class MockAgentGateway implements AgentGateway {
|
||||
return structuredClone(list[idx]);
|
||||
}
|
||||
|
||||
async updateProjectOrchestrator(
|
||||
projectId: string,
|
||||
agentId: string,
|
||||
): Promise<{ orchestratorAgentId: string }> {
|
||||
const list = this.getAgents(projectId);
|
||||
if (!list.some((agent) => agent.id === agentId)) {
|
||||
const err: GatewayError = {
|
||||
code: "NOT_FOUND",
|
||||
message: `agent ${agentId} not found in project ${projectId}`,
|
||||
};
|
||||
throw err;
|
||||
}
|
||||
for (let index = 0; index < list.length; index += 1) {
|
||||
list[index] = { ...list[index], isOrchestrator: list[index].id === agentId };
|
||||
}
|
||||
return { orchestratorAgentId: agentId };
|
||||
}
|
||||
|
||||
// ── Internal helpers for MockTemplateGateway (same-package use only) ──
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user