Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions frontend/src/components/agents/AgentChatPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ type Props = {
/** Progression live pendant l’envoi (SSE). */
liveSteps?: AgentChatStep[];
liveAssistantText?: string | null;
/** Provider actif actuel (pour filtrer les erreurs non pertinentes) */
activeRoutingProvider?: string | null;
};

export function AgentChatPanel({
Expand Down Expand Up @@ -212,6 +214,7 @@ export function AgentChatPanel({
activeSubagentCount = 0,
liveSteps = [],
liveAssistantText = null,
activeRoutingProvider = null,
}: Props) {
const scrollRef = useRef<HTMLDivElement>(null);
const textareaRef = useRef<HTMLTextAreaElement>(null);
Expand Down Expand Up @@ -308,7 +311,7 @@ export function AgentChatPanel({
</div>
)}

<AgentErrorAlert agent={agent} compact />
<AgentErrorAlert agent={agent} compact activeProvider={activeRoutingProvider} />

{activeSubagentCount > 0 && (
<div class="shrink-0 border-b border-info/30 bg-info/10 px-3 py-2 text-xs text-info sm:px-4">
Expand Down Expand Up @@ -515,7 +518,7 @@ export function AgentChatPanel({
</div>
)}

<div class="shrink-0 bg-base-100 p-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] sm:p-4">
<div class="agent-chat-composer shrink-0 bg-base-100 p-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] sm:p-4">
{error && (
<p class="mb-2 rounded-lg border border-error/30 bg-error/10 px-3 py-2 text-xs text-error" role="alert">
{error}
Expand Down
16 changes: 9 additions & 7 deletions frontend/src/components/agents/AgentChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,15 @@ export function AgentChatView({ agent, onBack, onAgentUpdated, userName }: Props
</div>
)}

<AgentViewSwitcher
mode={viewMode}
runsActive={runsActive}
runsCount={runsCount}
sessionsCount={sessionsCount}
onChange={(mode) => switchView(mode, focusedRunUuid ?? agent.latest_run?.uuid ?? null)}
/>
<div class="hidden sm:block">
<AgentViewSwitcher
mode={viewMode}
runsActive={runsActive}
runsCount={runsCount}
sessionsCount={sessionsCount}
onChange={(mode) => switchView(mode, focusedRunUuid ?? agent.latest_run?.uuid ?? null)}
/>
</div>

<div class="flex min-h-0 min-w-0 flex-1">
{viewMode === 'runs' ? (
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/agents/AgentConversationView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ export function AgentConversationView({

return (
<div class="flex min-h-0 min-w-0 flex-1 flex-col lg:flex-row">
<aside class="flex max-h-[min(30vh,14rem)] min-h-0 shrink-0 flex-col border-b border-base-300 bg-base-200/20 lg:max-h-none lg:w-72 lg:max-w-[40%] lg:border-b-0 lg:border-e">
<aside class="hidden shrink-0 flex-col border-e border-base-300 bg-base-200/20 lg:flex lg:w-72 lg:max-w-[40%]">
<div class="flex shrink-0 items-center justify-end gap-1 px-3 pt-3">
<button
class="btn btn-ghost btn-sm btn-square size-9 min-h-9 p-0"
Expand Down Expand Up @@ -447,6 +447,7 @@ export function AgentConversationView({
activeSubagentCount={activeSubagentCount}
liveSteps={liveSteps}
liveAssistantText={liveAssistantText}
activeRoutingProvider={agent.provider?.provider ?? null}
/>
</div>
</div>
Expand Down
53 changes: 48 additions & 5 deletions frontend/src/components/agents/AgentErrorAlert.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AlertCircle } from 'lucide-preact';
import { AlertCircle, X } from 'lucide-preact';
import { useState } from 'preact/hooks';
import type { Agent } from '../../lib/domain-api';
import { getAgentErrorMessage } from '../../lib/agent-errors';
import { agentDetailPath } from '../../lib/agent-routes';
Expand All @@ -8,12 +9,46 @@ type Props = {
agent: Agent;
compact?: boolean;
onNavigate?: (event: MouseEvent, path: string) => void;
/** Provider actuellement actif (si différent du default agent) */
activeProvider?: string | null;
};

export function AgentErrorAlert({ agent, compact = false, onNavigate }: Props) {
/**
* Détermine si l'erreur est pertinente pour le contexte actuel.
* Une erreur Ollama n'est pas pertinente si l'agent tourne actuellement sur Gemini.
*/
function isErrorRelevant(
agent: Agent,
activeProvider: string | null | undefined,
): boolean {
const errorMessage = getAgentErrorMessage(agent);
if (!errorMessage) {
return false;
}

// Si pas de provider actif spécifié, on montre l'erreur
if (!activeProvider) {
return true;
}

const lower = errorMessage.toLowerCase();
const isOllamaError = lower.includes('ollama');
const isGeminiActive = activeProvider === 'gemini' || agent.provider?.provider === 'gemini';

// Si l'erreur est Ollama mais que l'agent tourne sur Gemini, on cache l'erreur
if (isOllamaError && isGeminiActive) {
return false;
}

return true;
}

export function AgentErrorAlert({ agent, compact = false, onNavigate, activeProvider }: Props) {
const [dismissed, setDismissed] = useState(false);

const message = getAgentErrorMessage(agent);

if (!message) {
if (!message || dismissed || !isErrorRelevant(agent, activeProvider)) {
return null;
}

Expand All @@ -26,13 +61,13 @@ export function AgentErrorAlert({ agent, compact = false, onNavigate }: Props) {

return (
<div
class={`rounded-lg border border-error/30 bg-error/10 text-error ${compact ? 'px-3 py-2' : 'p-3'}`}
class={`shrink-0 rounded-lg border border-error/30 bg-error/10 text-error ${compact ? 'px-3 py-2' : 'p-3'}`}
role="alert"
>
<div class="flex items-start gap-2">
<AlertCircle class={`mt-0.5 shrink-0 ${compact ? 'size-3.5' : 'size-4'}`} aria-hidden />
<div class="min-w-0 flex-1">
<p class={`font-medium ${compact ? 'text-[11px]' : 'text-xs'}`}>Dernière erreur</p>
<p class={`font-medium ${compact ? 'text-[11px]' : 'text-xs'}`}>Erreur récente</p>
<p class={`mt-0.5 break-words text-error/90 ${compact ? 'line-clamp-3 text-[11px]' : 'text-xs'}`}>
{message}
</p>
Expand All @@ -46,6 +81,14 @@ export function AgentErrorAlert({ agent, compact = false, onNavigate }: Props) {
</a>
)}
</div>
<button
type="button"
class="btn btn-ghost btn-xs size-6 min-h-6 shrink-0 rounded-md p-0 text-error/70 hover:bg-error/20 hover:text-error"
aria-label="Masquer l'erreur"
onClick={() => setDismissed(true)}
>
<X class="size-3.5" aria-hidden />
</button>
</div>
</div>
);
Expand Down
15 changes: 15 additions & 0 deletions frontend/src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -658,3 +658,18 @@ input {
color: var(--color-error);
font-weight: 600;
}

/* Mobile chat improvements: composer always accessible, full-width messages */
@media (max-width: 640px) {
/* Agent chat composer: safe bottom spacing */
.agent-chat-composer {
padding-bottom: max(0.75rem, env(safe-area-inset-bottom));
}

/* Prevent horizontal overflow on messages */
.agent-chat-message {
max-width: 100%;
word-wrap: break-word;
overflow-wrap: break-word;
}
}