Skip to content
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ next-env.d.ts
# Eval results
eval/whiteboard-layout/results/
eval/outline-language/results/
eval/orchestration/results/
eval/orchestration/results-answering/

# e2e screenshot artifacts
e2e/screenshots/
56 changes: 0 additions & 56 deletions components/agent/agent-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ import {
Volume2,
VolumeX,
Loader2,
MessageSquare,
Minus,
Plus,
Search,
} from 'lucide-react';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
Expand Down Expand Up @@ -615,8 +612,6 @@ export function AgentBar() {
const { listAgents } = useAgentRegistry();
const selectedAgentIds = useSettingsStore((s) => s.selectedAgentIds);
const setSelectedAgentIds = useSettingsStore((s) => s.setSelectedAgentIds);
const maxTurns = useSettingsStore((s) => s.maxTurns);
const setMaxTurns = useSettingsStore((s) => s.setMaxTurns);
const agentMode = useSettingsStore((s) => s.agentMode);
const setAgentMode = useSettingsStore((s) => s.setAgentMode);
const ttsProvidersConfig = useSettingsStore((s) => s.ttsProvidersConfig);
Expand Down Expand Up @@ -937,57 +932,6 @@ export function AgentBar() {
</div>
</div>
)}

{/* Max turns — compact stepper */}
<div className="flex items-center gap-1.5 px-2 py-1 mt-1 border-t border-border/30">
<MessageSquare className="size-3 text-muted-foreground/40 shrink-0" />
<span className="text-[11px] text-muted-foreground/50 flex-1">
{t('settings.maxTurns')}
</span>
<div className="flex items-center rounded-full bg-muted/50 h-5 shrink-0">
<button
type="button"
onClick={(e) => {
e.stopPropagation();
const v = Math.max(1, parseInt(maxTurns || '1') - 1);
setMaxTurns(String(v));
}}
className="size-5 flex items-center justify-center text-muted-foreground/60 hover:text-foreground transition-colors rounded-full hover:bg-muted"
>
<Minus className="size-2.5" />
</button>
<input
type="text"
inputMode="numeric"
value={maxTurns}
onChange={(e) => {
const raw = e.target.value.replace(/\D/g, '');
if (!raw) {
setMaxTurns('');
return;
}
const v = Math.min(20, Math.max(1, parseInt(raw)));
setMaxTurns(String(v));
}}
onBlur={() => {
if (!maxTurns || parseInt(maxTurns) < 1) setMaxTurns('1');
}}
onClick={(e) => e.stopPropagation()}
className="w-5 h-5 text-[11px] font-medium tabular-nums text-center bg-transparent outline-none border-none"
/>
<button
type="button"
onClick={(e) => {
e.stopPropagation();
const v = Math.min(20, parseInt(maxTurns || '1') + 1);
setMaxTurns(String(v));
}}
className="size-5 flex items-center justify-center text-muted-foreground/60 hover:text-foreground transition-colors rounded-full hover:bg-muted"
>
<Plus className="size-2.5" />
</button>
</div>
</div>
</div>
</motion.div>
)}
Expand Down
4 changes: 3 additions & 1 deletion components/chat/session-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type { ChatSession, SessionStatus } from '@/lib/types/chat';
import { cn } from '@/lib/utils';
import { useI18n } from '@/lib/hooks/use-i18n';
import { ChevronDown, Circle, CheckCircle, Clock } from 'lucide-react';
import { ChevronDown, Circle, CheckCircle, Clock, AlertCircle } from 'lucide-react';
import { motion, AnimatePresence } from 'motion/react';
import { ChatSessionComponent } from './chat-session';

Expand Down Expand Up @@ -32,6 +32,8 @@ function getStatusIcon(status: SessionStatus) {
return <Clock className="size-2.5 text-yellow-500" />;
case 'completed':
return <CheckCircle className="size-2.5 text-gray-400" />;
case 'error':
return <AlertCircle className="size-2.5 text-red-500" />;
case 'idle':
default:
return <Circle className="size-2.5 text-gray-300" />;
Expand Down
60 changes: 29 additions & 31 deletions components/chat/use-chat-sessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ export function useChatSessions(options: UseChatSessionsOptions = {}) {
s.id === sessionId
? {
...s,
status: 'error' as SessionStatus,
updatedAt: now,
messages: [
...s.messages,
Expand Down Expand Up @@ -456,8 +457,6 @@ export function useChatSessions(options: UseChatSessionsOptions = {}) {
controller: AbortController,
sessionType: SessionType,
): Promise<void> => {
const settingsState = useSettingsStore.getState();

// Attach full configs for generated (non-default) agents so the server can use them.
// The server-side registry only has default agents; generated agents exist only client-side.
const generatedConfigs = requestTemplate.config.agentIds
Expand All @@ -469,11 +468,6 @@ export function useChatSessions(options: UseChatSessionsOptions = {}) {
requestTemplate.config.agentConfigs = generatedConfigs;
}

const defaultMaxTurns = requestTemplate.config.agentIds.length <= 1 ? 1 : 10;
const maxTurns = settingsState.maxTurns
? parseInt(settingsState.maxTurns, 10) || defaultMaxTurns
: defaultMaxTurns;

// Per-iteration buffer reference — set in onEvent, used in onIterationEnd
let currentBuffer: StreamBuffer | null = null;
// Tracks agent_start messageId so text_delta/action events with a missing
Expand Down Expand Up @@ -607,28 +601,40 @@ export function useChatSessions(options: UseChatSessionsOptions = {}) {
},
},
controller.signal,
maxTurns,
);

// Handle loop completion (UI-specific)
// Handle loop completion (UI-specific). Map each outcome.reason to a
// distinct session state — don't conflate error paths with completion.
if (!controller.signal.aborted) {
if (outcome.reason !== 'cue_user') {
setSessions((prev) =>
prev.map((s) =>
s.id === sessionId
? {
...s,
status: 'completed' as SessionStatus,
updatedAt: Date.now(),
}
: s,
),
);
onStopSessionRef.current?.();
switch (outcome.reason) {
case 'cue_user':
// Session stays active; UI waits for the next user message.
break;
case 'end':
setSessions((prev) =>
prev.map((s) =>
s.id === sessionId
? { ...s, status: 'completed' as SessionStatus, updatedAt: Date.now() }
: s,
),
);
onStopSessionRef.current?.();
break;
case 'empty_turns':
clearLiveSessionAfterError(sessionId, t('chat.error.emptyAgentResponses'));
onStopSessionRef.current?.();
break;
case 'no_done':
clearLiveSessionAfterError(sessionId, t('chat.error.streamInterrupted'));
onStopSessionRef.current?.();
break;
case 'aborted':
// Already handled elsewhere via abort signal.
break;
}
}
},
[createBufferForSession],
[createBufferForSession, clearLiveSessionAfterError, t],
);

/**
Expand All @@ -646,8 +652,6 @@ export function useChatSessions(options: UseChatSessionsOptions = {}) {
messages: [],
config: {
agentIds: ['default-1'],
maxTurns: 0, // Not used for runtime — frontend loop manages maxTurns
currentTurn: 0,
defaultAgentId: 'default-1',
},
toolCalls: [],
Expand Down Expand Up @@ -1070,8 +1074,6 @@ export function useChatSessions(options: UseChatSessionsOptions = {}) {
messages: [userMessage],
config: {
agentIds,
maxTurns: 0, // Not used for runtime — frontend loop manages maxTurns
currentTurn: 0,
defaultAgentId: agentIds[0],
},
toolCalls: [],
Expand Down Expand Up @@ -1208,8 +1210,6 @@ export function useChatSessions(options: UseChatSessionsOptions = {}) {
messages: [],
config: {
agentIds,
maxTurns: 0, // Not used for runtime — frontend loop manages maxTurns
currentTurn: 0,
triggerAgentId: agentId,
},
toolCalls: [],
Expand Down Expand Up @@ -1370,8 +1370,6 @@ export function useChatSessions(options: UseChatSessionsOptions = {}) {
messages: [lectureMessage],
config: {
agentIds: ['default-1'],
maxTurns: 0,
currentTurn: 0,
},
toolCalls: [],
pendingToolCalls: [],
Expand Down
21 changes: 0 additions & 21 deletions components/settings/agent-settings.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use client';

import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import { Checkbox } from '@/components/ui/checkbox';
import { AlertCircle, User, Users, Sparkles, Info } from 'lucide-react';
import { cn } from '@/lib/utils';
Expand All @@ -20,20 +19,16 @@ interface Agent {
interface AgentSettingsProps {
agents: Agent[];
selectedAgentIds: string[];
maxTurns: string;
agentMode: 'preset' | 'auto';
onToggleAgent: (agentId: string) => void;
onMaxTurnsChange: (value: string) => void;
onAgentModeChange: (mode: 'preset' | 'auto') => void;
}

export function AgentSettings({
agents,
selectedAgentIds,
maxTurns,
agentMode,
onToggleAgent,
onMaxTurnsChange,
onAgentModeChange,
}: AgentSettingsProps) {
const { t } = useI18n();
Expand Down Expand Up @@ -165,22 +160,6 @@ export function AgentSettings({
</span>
)}
</div>

{/* Max turns config - only show for multi-agent */}
{selectedAgentIds.length > 1 && (
<div className="space-y-2 border-l-4 border-purple-500 pl-4">
<Label>{t('settings.maxTurns')}</Label>
<p className="text-xs text-muted-foreground">{t('settings.maxTurnsDesc')}</p>
<Input
type="number"
min="1"
max="20"
value={maxTurns}
onChange={(e) => onMaxTurnsChange(e.target.value)}
className="w-24"
/>
</div>
)}
</>
) : (
<>
Expand Down
Loading
Loading