Skip to content

Commit 5cf08f9

Browse files
simple-agent-manager[bot]raphaeltmclaude
authored
refactor: split api.ts into domain-specific modules (#597)
* chore: move task to active Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: split api.ts (2,255 lines) into domain-specific modules Split apps/web/src/lib/api.ts into 17 domain-specific modules under apps/web/src/lib/api/ with a barrel index.ts re-exporting everything. All existing imports continue to work without changes. Modules: client, auth, credentials, providers, github, projects, tasks, sessions, nodes, workspaces, agents, files, admin, notifications, deployment, misc. No file exceeds 370 lines (was 2,255). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: archive completed task Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve pre-existing ChatSession.tsx type errors - Import SessionStateMessage type from acp-client - Move handleFirstConnect above useAcpSession call to fix used-before-declaration - Remove unused `connected` destructuring - Use ref pattern to break circular dependency with switchAgent Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: repair broken test file syntax and unused imports - Fix `define vi.mock` → `vi.mock` (syntax error) - Remove unused imports (renderHook, act, useRef, useState, beforeEach, afterEach) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: trigger CI Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: add trailing newline to api/index.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove trigger comment from index.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Raphaël Titsworth-Morin <raphael@raphaeltm.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f5a2cec commit 5cf08f9

21 files changed

Lines changed: 2524 additions & 2297 deletions

apps/web/src/components/ChatSession.tsx

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type {
22
AcpLifecycleEvent,
33
AgentPanelHandle,
44
ChatSettingsData,
5+
SessionStateMessage,
56
TokenUsage,
67
} from '@simple-agent-manager/acp-client';
78
import { AgentPanel,useAcpMessages, useAcpSession } from '@simple-agent-manager/acp-client';
@@ -155,6 +156,45 @@ export const ChatSession = React.forwardRef<ChatSessionHandle, ChatSessionProps>
155156
// conversation from the agent via session/update notifications.
156157
const acpMessages = useAcpMessages();
157158

159+
// Handle agent auto-selection on first connection using event-driven approach.
160+
// This replaces the useEffect-based logic and prevents infinite loops by design.
161+
const hasAutoSelectedRef = useRef(false);
162+
163+
// NOTE: switchAgent is used in handleFirstConnect but comes from acpSession below.
164+
// We store it in a ref to break the circular dependency.
165+
const switchAgentRef = useRef<((agentId: string) => void) | null>(null);
166+
167+
const handleFirstConnect = useCallback((sessionState: SessionStateMessage) => {
168+
// Only auto-select if we haven't already done so for this session
169+
if (hasAutoSelectedRef.current) return;
170+
171+
// Don't auto-select if:
172+
// 1. No preferred agent is specified
173+
// 2. An agent is already running (agentType matches preferredAgentId)
174+
// 3. The session is in an error state
175+
if (!preferredAgentId) return;
176+
if (sessionState.agentType === preferredAgentId) return;
177+
if (sessionState.status === 'error') return;
178+
179+
// Only auto-select for idle sessions (no agent running yet)
180+
if (sessionState.status !== 'idle') return;
181+
182+
hasAutoSelectedRef.current = true;
183+
reportError({
184+
level: 'info',
185+
message: `Auto-selecting agent on first connect: ${preferredAgentId}`,
186+
source: 'acp-chat',
187+
context: {
188+
workspaceId,
189+
sessionId,
190+
preferredAgentId,
191+
currentAgentType: sessionState.agentType,
192+
sessionStatus: sessionState.status
193+
},
194+
});
195+
switchAgentRef.current?.(preferredAgentId);
196+
}, [preferredAgentId, workspaceId, sessionId]);
197+
158198
// Own ACP session hook — separate WebSocket per chat tab
159199
const acpSession = useAcpSession({
160200
wsUrl: null,
@@ -165,7 +205,8 @@ export const ChatSession = React.forwardRef<ChatSessionHandle, ChatSessionProps>
165205
onFirstConnect: handleFirstConnect,
166206
});
167207

168-
const { connected, agentType, state, switchAgent } = acpSession;
208+
const { agentType, state, switchAgent } = acpSession;
209+
switchAgentRef.current = switchAgent;
169210
const { clear: clearMessages } = acpMessages;
170211

171212
// Clear messages when no agent session exists (idle SessionHost).
@@ -185,41 +226,6 @@ export const ChatSession = React.forwardRef<ChatSessionHandle, ChatSessionProps>
185226
}
186227
}, [state, clearMessages, workspaceId, sessionId]);
187228

188-
// Handle agent auto-selection on first connection using event-driven approach.
189-
// This replaces the useEffect-based logic and prevents infinite loops by design.
190-
const hasAutoSelectedRef = useRef(false);
191-
192-
const handleFirstConnect = useCallback((sessionState: SessionStateMessage) => {
193-
// Only auto-select if we haven't already done so for this session
194-
if (hasAutoSelectedRef.current) return;
195-
196-
// Don't auto-select if:
197-
// 1. No preferred agent is specified
198-
// 2. An agent is already running (agentType matches preferredAgentId)
199-
// 3. The session is in an error state
200-
if (!preferredAgentId) return;
201-
if (sessionState.agentType === preferredAgentId) return;
202-
if (sessionState.status === 'error') return;
203-
204-
// Only auto-select for idle sessions (no agent running yet)
205-
if (sessionState.status !== 'idle') return;
206-
207-
hasAutoSelectedRef.current = true;
208-
reportError({
209-
level: 'info',
210-
message: `Auto-selecting agent on first connect: ${preferredAgentId}`,
211-
source: 'acp-chat',
212-
context: {
213-
workspaceId,
214-
sessionId,
215-
preferredAgentId,
216-
currentAgentType: sessionState.agentType,
217-
sessionStatus: sessionState.status
218-
},
219-
});
220-
switchAgent(preferredAgentId);
221-
}, [preferredAgentId, workspaceId, sessionId, switchAgent]);
222-
223229
// Report activity
224230
const handleActivity = useCallback(() => {
225231
onActivity?.();

0 commit comments

Comments
 (0)