merge(slash-commands): route /clean et /help en commandes natives IdeA (#183, QA verte)
This commit is contained in:
@ -1,10 +1,11 @@
|
|||||||
---
|
---
|
||||||
issueRef: "#182"
|
issueRef: "#182"
|
||||||
version: 2
|
version: 3
|
||||||
updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
|
updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
|
||||||
updatedAt: 1786455261558
|
updatedAt: 1786455395341
|
||||||
---
|
---
|
||||||
2026-08-11
|
2026-08-11
|
||||||
- Ticket ouvert suite au signalement utilisateur.
|
- Ticket ouvert suite au signalement utilisateur.
|
||||||
- Cadrage UX: restauration transparente du brouillon au retour sur la cellule/layout; pas de persistance des attachments; TTL court acceptable.
|
- Cadrage UX: restauration transparente du brouillon au retour sur la cellule/layout; pas de persistance des attachments; TTL court acceptable.
|
||||||
- Cadrage architecture: persistance bornée par projet/layout/node, à trancher entre stockage frontend léger et store backend dédié selon l'implémentation existante.
|
- Arbitrage architecture validé: store backend JSON, scoped par projet/layout/node; pas de solution frontend-only.
|
||||||
|
- L'implémentation devra nettoyer le draft à l'envoi et après /clean si la conversation est vidée.
|
||||||
@ -11,7 +11,7 @@ attachments: []
|
|||||||
createdBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
|
createdBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
|
||||||
updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
|
updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
|
||||||
createdAt: 1786454719252
|
createdAt: 1786454719252
|
||||||
updatedAt: 1786455261558
|
updatedAt: 1786455395341
|
||||||
version: 2
|
version: 3
|
||||||
---
|
---
|
||||||
Quand l'utilisateur tape un message dans le chat puis change de layout ou de projet, le texte saisi doit rester dans le chat quand il revient sur ce layout.
|
Quand l'utilisateur tape un message dans le chat puis change de layout ou de projet, le texte saisi doit rester dans le chat quand il revient sur ce layout.
|
||||||
@ -1,11 +1,13 @@
|
|||||||
---
|
---
|
||||||
issueRef: "#183"
|
issueRef: "#183"
|
||||||
version: 2
|
version: 4
|
||||||
updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
|
updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
|
||||||
updatedAt: 1786455261582
|
updatedAt: 1786455949201
|
||||||
---
|
---
|
||||||
2026-08-11
|
2026-08-11
|
||||||
- Ticket ouvert suite au signalement utilisateur.
|
- Ticket ouvert suite au signalement utilisateur.
|
||||||
- Symptôme confirmé: /clean et /help échouent faute d'effet pluginCallback, alors que /profile fonctionne.
|
- Symptôme confirmé: /clean et /help échouent faute d'effet pluginCallback, alors que /profile fonctionne.
|
||||||
- Cadrage UX: /help et /clean sont des commandes natives IdeA; erreur inconnue doit pointer vers /help.
|
- Cadrage UX: /help et /clean sont des commandes natives IdeA; erreur inconnue doit pointer vers /help.
|
||||||
- Cadrage architecture: router explicitement les commandes natives séparément des commandes plugin et préserver /profile comme natif.
|
- Cadrage architecture: router explicitement les commandes natives séparément des commandes plugin et préserver /profile comme natif.
|
||||||
|
- Implémentation dev reçue sur fix/183-native-slash-commands-routing: dispatch frontend explicite des effets natifs help/cleanConversation/profileSwitch/pluginCallback, tests frontend ajoutés; garde backend que les commandes natives priment sur les plugins.
|
||||||
|
- QA 2026-08-11: VERT. Vérifications exécutées avec succès: cargo test -p application slash_command ; npm test -- --run src/features/agents/CustomAgentChatView.test.tsx.
|
||||||
@ -2,7 +2,7 @@
|
|||||||
id: "a48be9fa-1b0c-4109-ba1d-c5ad0919d113"
|
id: "a48be9fa-1b0c-4109-ba1d-c5ad0919d113"
|
||||||
number: 183
|
number: 183
|
||||||
title: "Réparer les commandes /clean et /help comme commandes natives IdeA"
|
title: "Réparer les commandes /clean et /help comme commandes natives IdeA"
|
||||||
status: "inProgress"
|
status: "qa"
|
||||||
priority: "critical"
|
priority: "critical"
|
||||||
sprint: null
|
sprint: null
|
||||||
links: []
|
links: []
|
||||||
@ -11,7 +11,7 @@ attachments: []
|
|||||||
createdBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
|
createdBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
|
||||||
updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
|
updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
|
||||||
createdAt: 1786454719274
|
createdAt: 1786454719274
|
||||||
updatedAt: 1786455261582
|
updatedAt: 1786455949201
|
||||||
version: 2
|
version: 4
|
||||||
---
|
---
|
||||||
Les commandes /clean et /help échouent avec l'erreur: "La commande /clean n'a pas renvoyé d'effet pluginCallback." L'utilisateur précise que /clean, /help et /profile sont des commandes fournies nativement par IdeA. /profile fonctionne, /clean et /help non. Il faut lever la confusion entre commandes natives IdeA et futures commandes extensibles par plugins.
|
Les commandes /clean et /help échouent avec l'erreur: "La commande /clean n'a pas renvoyé d'effet pluginCallback." L'utilisateur précise que /clean, /help et /profile sont des commandes fournies nativement par IdeA. /profile fonctionne, /clean et /help non. Il faut lever la confusion entre commandes natives IdeA et futures commandes extensibles par plugins.
|
||||||
@ -2449,13 +2449,13 @@
|
|||||||
"kind": "agent",
|
"kind": "agent",
|
||||||
"agent_id": "a6c6ea12-bfc6-4bdc-8031-324102dfa34d"
|
"agent_id": "a6c6ea12-bfc6-4bdc-8031-324102dfa34d"
|
||||||
},
|
},
|
||||||
"updatedAt": 1786455261558
|
"updatedAt": 1786455395341
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"issueRef": "#183",
|
"issueRef": "#183",
|
||||||
"path": "183",
|
"path": "183",
|
||||||
"title": "Réparer les commandes /clean et /help comme commandes natives IdeA",
|
"title": "Réparer les commandes /clean et /help comme commandes natives IdeA",
|
||||||
"status": "inProgress",
|
"status": "qa",
|
||||||
"priority": "critical",
|
"priority": "critical",
|
||||||
"sprint": null,
|
"sprint": null,
|
||||||
"assignedAgentIds": [],
|
"assignedAgentIds": [],
|
||||||
@ -2463,7 +2463,7 @@
|
|||||||
"kind": "agent",
|
"kind": "agent",
|
||||||
"agent_id": "a6c6ea12-bfc6-4bdc-8031-324102dfa34d"
|
"agent_id": "a6c6ea12-bfc6-4bdc-8031-324102dfa34d"
|
||||||
},
|
},
|
||||||
"updatedAt": 1786455261582
|
"updatedAt": 1786455949201
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -386,6 +386,37 @@ mod tests {
|
|||||||
assert_eq!(arguments, vec![serde_json::json!({ "selection": "abc" })]);
|
assert_eq!(arguments, vec![serde_json::json!({ "selection": "abc" })]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn native_command_names_are_routed_before_plugin_commands() {
|
||||||
|
let colliding_plugin = plugin_slash_command(
|
||||||
|
"dev.acme.plugin",
|
||||||
|
"dev.acme.plugin.clean",
|
||||||
|
"/clean",
|
||||||
|
"Plugin clean",
|
||||||
|
false,
|
||||||
|
SlashCommandAvailability::Available,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let sid = session();
|
||||||
|
|
||||||
|
let out = ExecuteSlashCommand::new(SlashCommandRegistry::new())
|
||||||
|
.execute_with_plugins(
|
||||||
|
ExecuteSlashCommandInput {
|
||||||
|
name: "/clean".to_owned(),
|
||||||
|
session_id: Some(sid),
|
||||||
|
arguments: Vec::new(),
|
||||||
|
},
|
||||||
|
vec![colliding_plugin],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(out.command.source, SlashCommandSource::Native);
|
||||||
|
assert_eq!(
|
||||||
|
out.effect,
|
||||||
|
SlashCommandEffect::CleanConversation { session_id: sid }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn runtime_catalog_plugin_slash_commands_feed_unified_registry() {
|
fn runtime_catalog_plugin_slash_commands_feed_unified_registry() {
|
||||||
let catalog = PluginRuntimeCatalog {
|
let catalog = PluginRuntimeCatalog {
|
||||||
|
|||||||
@ -972,6 +972,169 @@ describe("CustomAgentChatView", () => {
|
|||||||
expect(composer.value).toBe("");
|
expect(composer.value).toBe("");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("executes /clean as a native conversation clear effect", async () => {
|
||||||
|
const agent = {
|
||||||
|
launchAgentChat: vi.fn(),
|
||||||
|
reattachAgentChat: vi.fn(async (sessionId: string) => ({
|
||||||
|
sessionId,
|
||||||
|
scrollback: [{ kind: "userPrompt", text: "old conversation" }],
|
||||||
|
})),
|
||||||
|
sendAgentChat: vi.fn(async () => {}),
|
||||||
|
executeSlashCommand: vi.fn(async () => ({
|
||||||
|
command: {
|
||||||
|
name: "/clean",
|
||||||
|
shortDescription: "Nettoyer la conversation courante",
|
||||||
|
requiresConfirmation: false,
|
||||||
|
availability: { status: "available" as const },
|
||||||
|
source: "native" as const,
|
||||||
|
native: "clean" as const,
|
||||||
|
},
|
||||||
|
effect: {
|
||||||
|
kind: "cleanConversation" as const,
|
||||||
|
sessionId: "chat-session-1",
|
||||||
|
clearedChunks: 1,
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
cancelAgentChat: vi.fn(async () => {}),
|
||||||
|
closeAgentChat: vi.fn(async () => {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
render(
|
||||||
|
<DIProvider
|
||||||
|
gateways={{
|
||||||
|
agent,
|
||||||
|
system: { pickFile: vi.fn(async () => null) },
|
||||||
|
} as unknown as Gateways}
|
||||||
|
>
|
||||||
|
<CustomAgentChatView
|
||||||
|
projectId="project-1"
|
||||||
|
agentId="agent-1"
|
||||||
|
agentName="Worker"
|
||||||
|
profile={profile}
|
||||||
|
cwd="/repo"
|
||||||
|
nodeId="node-1"
|
||||||
|
sessionId="chat-session-1"
|
||||||
|
conversationId="conversation-1"
|
||||||
|
onSessionId={vi.fn()}
|
||||||
|
onConversationId={vi.fn()}
|
||||||
|
/>
|
||||||
|
</DIProvider>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await screen.findByText("old conversation")).toBeTruthy();
|
||||||
|
|
||||||
|
const composer = screen.getByLabelText(/message CLI custom/) as HTMLTextAreaElement;
|
||||||
|
fireEvent.change(composer, { target: { value: "/clean" } });
|
||||||
|
fireEvent.keyDown(composer, { key: "Enter" });
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(agent.executeSlashCommand).toHaveBeenCalledWith("/clean", {
|
||||||
|
sessionId: "chat-session-1",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
await waitFor(() => expect(screen.queryByText("old conversation")).toBeNull());
|
||||||
|
expect(screen.queryByRole("alert")).toBeNull();
|
||||||
|
expect(agent.sendAgentChat).not.toHaveBeenCalled();
|
||||||
|
expect(composer.value).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("executes /help as a native help effect", async () => {
|
||||||
|
const agent = {
|
||||||
|
launchAgentChat: vi.fn(),
|
||||||
|
reattachAgentChat: vi.fn(async (sessionId: string) => ({
|
||||||
|
sessionId,
|
||||||
|
scrollback: [],
|
||||||
|
})),
|
||||||
|
sendAgentChat: vi.fn(async () => {}),
|
||||||
|
executeSlashCommand: vi.fn(async () => ({
|
||||||
|
command: {
|
||||||
|
name: "/help",
|
||||||
|
shortDescription: "Afficher les commandes disponibles",
|
||||||
|
requiresConfirmation: false,
|
||||||
|
availability: { status: "available" as const },
|
||||||
|
source: "native" as const,
|
||||||
|
native: "help" as const,
|
||||||
|
},
|
||||||
|
effect: {
|
||||||
|
kind: "help" as const,
|
||||||
|
commands: [
|
||||||
|
{
|
||||||
|
name: "/help",
|
||||||
|
shortDescription: "Afficher les commandes disponibles",
|
||||||
|
requiresConfirmation: false,
|
||||||
|
availability: { status: "available" as const },
|
||||||
|
source: "native" as const,
|
||||||
|
native: "help" as const,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "/clean",
|
||||||
|
shortDescription: "Nettoyer la conversation courante",
|
||||||
|
requiresConfirmation: false,
|
||||||
|
availability: { status: "available" as const },
|
||||||
|
source: "native" as const,
|
||||||
|
native: "clean" as const,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "/profile",
|
||||||
|
shortDescription: "Changer le profil de l'agent",
|
||||||
|
requiresConfirmation: true,
|
||||||
|
availability: { status: "available" as const },
|
||||||
|
source: "native" as const,
|
||||||
|
native: "profile" as const,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
cancelAgentChat: vi.fn(async () => {}),
|
||||||
|
closeAgentChat: vi.fn(async () => {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
render(
|
||||||
|
<DIProvider
|
||||||
|
gateways={{
|
||||||
|
agent,
|
||||||
|
system: { pickFile: vi.fn(async () => null) },
|
||||||
|
} as unknown as Gateways}
|
||||||
|
>
|
||||||
|
<CustomAgentChatView
|
||||||
|
projectId="project-1"
|
||||||
|
agentId="agent-1"
|
||||||
|
agentName="Worker"
|
||||||
|
profile={profile}
|
||||||
|
cwd="/repo"
|
||||||
|
nodeId="node-1"
|
||||||
|
sessionId="chat-session-1"
|
||||||
|
conversationId="conversation-1"
|
||||||
|
onSessionId={vi.fn()}
|
||||||
|
onConversationId={vi.fn()}
|
||||||
|
/>
|
||||||
|
</DIProvider>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(agent.reattachAgentChat).toHaveBeenCalledWith(
|
||||||
|
"chat-session-1",
|
||||||
|
expect.any(Function),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const composer = screen.getByLabelText(/message CLI custom/) as HTMLTextAreaElement;
|
||||||
|
fireEvent.change(composer, { target: { value: "/help" } });
|
||||||
|
fireEvent.keyDown(composer, { key: "Enter" });
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(agent.executeSlashCommand).toHaveBeenCalledWith("/help", {
|
||||||
|
sessionId: "chat-session-1",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
await screen.findByText(/\/clean - Nettoyer la conversation courante/),
|
||||||
|
).toBeTruthy();
|
||||||
|
expect(screen.queryByRole("alert")).toBeNull();
|
||||||
|
expect(agent.sendAgentChat).not.toHaveBeenCalled();
|
||||||
|
expect(composer.value).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
it("shows feedback when a plugin slash-command callback cannot be dispatched", async () => {
|
it("shows feedback when a plugin slash-command callback cannot be dispatched", async () => {
|
||||||
const registry = new PluginRuntimeRegistry();
|
const registry = new PluginRuntimeRegistry();
|
||||||
const agent = {
|
const agent = {
|
||||||
|
|||||||
@ -401,6 +401,12 @@ function isSlashCommandAvailable(command: SlashCommand): boolean {
|
|||||||
return command.availability.status === "available";
|
return command.availability.status === "available";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatSlashCommandHelp(commands: SlashCommand[]): string {
|
||||||
|
return commands
|
||||||
|
.map((command) => `${command.name} - ${command.shortDescription}`)
|
||||||
|
.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
function foldChunk(turns: ChatTurn[], raw: unknown): ChatTurn[] {
|
function foldChunk(turns: ChatTurn[], raw: unknown): ChatTurn[] {
|
||||||
if (!isReplyRecord(raw)) {
|
if (!isReplyRecord(raw)) {
|
||||||
return [...turns, { role: "unknown", text: unknownChunkLabel(raw) }];
|
return [...turns, { role: "unknown", text: unknownChunkLabel(raw) }];
|
||||||
@ -792,42 +798,23 @@ export function CustomAgentChatView({
|
|||||||
[supported, draft, attachments.length, busy, opening],
|
[supported, draft, attachments.length, busy, opening],
|
||||||
);
|
);
|
||||||
|
|
||||||
async function openProfileCommandFlow() {
|
async function openProfileDialog() {
|
||||||
if (!agent.executeSlashCommand) {
|
const availableProfiles = (await profileGateway.listProfiles()).filter((candidate) =>
|
||||||
setError("Commande /profile indisponible dans ce runtime.");
|
Boolean(candidate.structuredAdapter),
|
||||||
return;
|
);
|
||||||
}
|
if (availableProfiles.length === 0) {
|
||||||
setError(null);
|
throw new Error("Aucun profil compatible avec la CLI custom n'est configuré.");
|
||||||
try {
|
|
||||||
const sid =
|
|
||||||
currentSession ??
|
|
||||||
(await recoverStructuredSession({
|
|
||||||
applyScrollback: false,
|
|
||||||
retryAttachNotFound: true,
|
|
||||||
}));
|
|
||||||
const result = await agent.executeSlashCommand("/profile", { sessionId: sid });
|
|
||||||
if (result.effect.kind !== "profileSwitch") {
|
|
||||||
throw new Error("La commande /profile n'a pas renvoyé le flow profil.");
|
|
||||||
}
|
|
||||||
const availableProfiles = (await profileGateway.listProfiles()).filter(
|
|
||||||
(candidate) => Boolean(candidate.structuredAdapter),
|
|
||||||
);
|
|
||||||
if (availableProfiles.length === 0) {
|
|
||||||
throw new Error("Aucun profil compatible avec la CLI custom n'est configuré.");
|
|
||||||
}
|
|
||||||
setDraft("");
|
|
||||||
setProfileDialog({
|
|
||||||
profiles: availableProfiles,
|
|
||||||
selectedProfileId:
|
|
||||||
availableProfiles.find((candidate) => candidate.id !== profile.id)?.id ??
|
|
||||||
availableProfiles[0].id,
|
|
||||||
confirmedReset: false,
|
|
||||||
busy: false,
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
setError(describe(e));
|
|
||||||
}
|
}
|
||||||
|
setDraft("");
|
||||||
|
setProfileDialog({
|
||||||
|
profiles: availableProfiles,
|
||||||
|
selectedProfileId:
|
||||||
|
availableProfiles.find((candidate) => candidate.id !== profile.id)?.id ??
|
||||||
|
availableProfiles[0].id,
|
||||||
|
confirmedReset: false,
|
||||||
|
busy: false,
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function confirmProfileCommandChange() {
|
async function confirmProfileCommandChange() {
|
||||||
@ -904,22 +891,38 @@ export function CustomAgentChatView({
|
|||||||
}));
|
}));
|
||||||
const result = await agent.executeSlashCommand(invocation.name, {
|
const result = await agent.executeSlashCommand(invocation.name, {
|
||||||
sessionId: sid,
|
sessionId: sid,
|
||||||
arguments: invocation.arguments,
|
...(invocation.arguments.length > 0
|
||||||
|
? { arguments: invocation.arguments }
|
||||||
|
: {}),
|
||||||
});
|
});
|
||||||
if (result.effect.kind !== "pluginCallback") {
|
if (result.effect.kind === "help") {
|
||||||
throw new Error(
|
const helpText = formatSlashCommandHelp(result.effect.commands);
|
||||||
`La commande ${invocation.name} n'a pas renvoyé d'effet pluginCallback.`,
|
setTurns((prev) => [
|
||||||
);
|
...prev,
|
||||||
|
{ role: "agent", text: helpText },
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result.effect.kind === "cleanConversation") {
|
||||||
|
setTurns([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result.effect.kind === "profileSwitch") {
|
||||||
|
await openProfileDialog();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result.effect.kind === "pluginCallback") {
|
||||||
|
await pluginRuntime.registry.runCommandStrict(
|
||||||
|
result.effect.pluginId,
|
||||||
|
result.effect.commandId,
|
||||||
|
...result.effect.arguments,
|
||||||
|
);
|
||||||
|
setTurns((prev) => [
|
||||||
|
...prev,
|
||||||
|
{ role: "tool", label: `Commande plugin ${result.command.name} exécutée.` },
|
||||||
|
]);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
await pluginRuntime.registry.runCommandStrict(
|
|
||||||
result.effect.pluginId,
|
|
||||||
result.effect.commandId,
|
|
||||||
...result.effect.arguments,
|
|
||||||
);
|
|
||||||
setTurns((prev) => [
|
|
||||||
...prev,
|
|
||||||
{ role: "tool", label: `Commande plugin ${result.command.name} exécutée.` },
|
|
||||||
]);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const message = `Commande ${invocation.name} échouée: ${describe(e)}`;
|
const message = `Commande ${invocation.name} échouée: ${describe(e)}`;
|
||||||
setError(message);
|
setError(message);
|
||||||
@ -971,10 +974,6 @@ export function CustomAgentChatView({
|
|||||||
async function send() {
|
async function send() {
|
||||||
const text = draft.trim();
|
const text = draft.trim();
|
||||||
if (!canSend || !agent.sendAgentChat) return;
|
if (!canSend || !agent.sendAgentChat) return;
|
||||||
if (text === "/profile") {
|
|
||||||
await openProfileCommandFlow();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const slashInvocation = slashCommandInvocation(text);
|
const slashInvocation = slashCommandInvocation(text);
|
||||||
if (slashInvocation) {
|
if (slashInvocation) {
|
||||||
await executeSlashCommand(slashInvocation);
|
await executeSlashCommand(slashInvocation);
|
||||||
|
|||||||
Reference in New Issue
Block a user