2e108b040f
* feat: session resumption with ACP session ID support - Add useSessionResumption hook for automatic session recovery on page reload - Fix ACPSessionID not being set on AgentInstance in Launch() and createInstance() - Add task.session.status and task.session.resume WebSocket actions - Fix shell terminal retry logic for resumed sessions - Fix taskSessionState reading from Zustand store instead of local state - Remove dead code: unused stream handling functions in lifecycle/manager.go - Fix test mock interfaces (CleanupStaleInstanceByTaskID, NewManager signature) - Add enhanced logging for session resumption debugging - Simplify page-client.tsx state merging logic * refactor: remove unused AgentController (dead code) - Delete agent_controller.go - entirely unused duplicate of Manager methods - Remove agentController field from Manager struct - Remove AgentController initialization in NewManager The AgentController duplicated StartAgentProcess, initializeACPSession, and PromptAgent from Manager but was never called. All agent control operations go through Manager's own methods. * refactor: remove unused MemoryRepository (dead code) - Delete memory.go - entire MemoryRepository implementation unused (replaced by SQLite repository) - Delete memory_test.go - tests for removed MemoryRepository Found via 'deadcode' tool analysis. * refactor: consolidate agentctl packages into server/client structure Reorganize the confusing dual agentctl packages: - internal/agentctl/* → internal/agentctl/server/ - internal/agent/agentctl/* → internal/agentctl/client/ Structure is now: internal/agentctl/ ├── client/ - HTTP client for talking to agentctl servers │ ├── client.go │ ├── standalone.go │ ├── acp.go │ └── launcher/ ├── server/ - agentctl server implementation (runs in containers) │ ├── api/ │ ├── adapter/ │ ├── acp/ │ ├── config/ │ ├── instance/ │ ├── process/ │ └── shell/ └── types/ - Shared types used by both client and server Also consolidated shared types (GitStatusUpdate, FileInfo, etc.) from process/types.go into the shared types/ package. * refactor: rename AgentInstance to AgentExecution for clarity Rename AgentInstance -> AgentExecution across the entire codebase to better reflect what it represents: an agent actively working on a task, not just a generic 'instance'. Changes: - AgentInstance struct -> AgentExecution - InstanceStore -> ExecutionStore (new file: execution_store.go) - RecoveredInstance -> RecoveredExecution - All method names: GetInstance* -> GetExecution*, ListInstances -> ListExecutions, etc. - All parameters: instanceID -> executionID - All local variables: instance -> execution - DTOs and JSON tags: agent_instance_id -> agent_execution_id - Database columns: agent_instance_id -> agent_execution_id Also consolidates duplicate prompt logic: - Merge sendInitialPrompt and SendPrompt into single SendPrompt method - Add validateStatus parameter to differentiate initial vs follow-up prompts Also extracts ACP session management to session.go: - Move initializeACPSession logic to SessionManager.InitializeAndPrompt - Move PromptAgent logic to SessionManager.SendPrompt - Manager now delegates to SessionManager for all prompt operations Also removes duplicate event publishing: - Remove 9 duplicate m.publish*() methods from manager.go - Use existing EventPublisher methods via m.eventPublisher.Publish*() Also extracts types to dedicated file: - Move AgentExecution, LaunchRequest, PromptResult, etc. to types.go Net reduction: ~600 lines removed from manager.go through deduplication and better separation of concerns. * fix(backend): Docker runtime now creates instance via ControlServer The Docker runtime was incorrectly creating an agentctl.Client pointing directly to port 9999 (the ControlServer port), then trying to call instance-specific APIs like /api/v1/agent/configure which only exist on per-instance servers. Fixed by making Docker runtime follow the same flow as standalone mode: - LaunchContainer now uses StandaloneCtl to create an instance via the control API, then creates Client pointing to the instance port - RecoverInstances queries the ControlServer to get the instance port - Added waitForHealth helper to wait for agentctl to be ready Also improved HTTP error handling in agentctl client: - All client methods now check HTTP status codes before JSON decoding - Better error messages include status code and response body * fix: restore session resumption imports and variables * fix: add sessionId prop back to TaskLayout
74 lines
2.4 KiB
TypeScript
74 lines
2.4 KiB
TypeScript
'use client';
|
|
|
|
import { memo, useState } from 'react';
|
|
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@kandev/ui/resizable';
|
|
import { getLocalStorage, setLocalStorage } from '@/lib/local-storage';
|
|
import { TaskLeftPanel } from './task-left-panel';
|
|
import { TaskRightPanel } from './task-right-panel';
|
|
import { TaskFilesPanel } from './task-files-panel';
|
|
import type { OpenFileTab } from '@/lib/types/backend';
|
|
|
|
const DEFAULT_HORIZONTAL_LAYOUT: [number, number] = [75, 25];
|
|
|
|
type TaskLayoutProps = {
|
|
taskId: string | null;
|
|
sessionId: string | null;
|
|
onSendMessage: (content: string) => Promise<void>;
|
|
};
|
|
|
|
export const TaskLayout = memo(function TaskLayout({
|
|
taskId,
|
|
sessionId,
|
|
onSendMessage,
|
|
}: TaskLayoutProps) {
|
|
const [horizontalLayout, setHorizontalLayout] = useState<[number, number]>(
|
|
getLocalStorage('task-layout-horizontal', DEFAULT_HORIZONTAL_LAYOUT)
|
|
);
|
|
const [selectedDiffPath, setSelectedDiffPath] = useState<string | null>(null);
|
|
const [openFileRequest, setOpenFileRequest] = useState<OpenFileTab | null>(null);
|
|
|
|
const handleSelectDiffPath = (path: string) => {
|
|
setSelectedDiffPath(path);
|
|
};
|
|
|
|
const handleOpenFile = (file: OpenFileTab) => {
|
|
setOpenFileRequest(file);
|
|
};
|
|
|
|
const topFilesPanel = (
|
|
<TaskFilesPanel
|
|
taskId={taskId}
|
|
onSelectDiffPath={handleSelectDiffPath}
|
|
onOpenFile={handleOpenFile}
|
|
/>
|
|
);
|
|
|
|
return (
|
|
<div className="flex-1 min-h-0 px-4 pb-4">
|
|
<ResizablePanelGroup
|
|
direction="horizontal"
|
|
className="h-full"
|
|
onLayout={(sizes) => {
|
|
setHorizontalLayout(sizes as [number, number]);
|
|
setLocalStorage('task-layout-horizontal', sizes);
|
|
}}
|
|
>
|
|
<ResizablePanel defaultSize={horizontalLayout[0]} minSize={55}>
|
|
<TaskLeftPanel
|
|
taskId={taskId}
|
|
onSendMessage={onSendMessage}
|
|
selectedDiffPath={selectedDiffPath}
|
|
openFileRequest={openFileRequest}
|
|
onDiffPathHandled={() => setSelectedDiffPath(null)}
|
|
onFileOpenHandled={() => setOpenFileRequest(null)}
|
|
/>
|
|
</ResizablePanel>
|
|
<ResizableHandle className="w-px" />
|
|
<ResizablePanel defaultSize={horizontalLayout[1]} minSize={20}>
|
|
<TaskRightPanel topPanel={topFilesPanel} taskId={taskId ?? ''} sessionId={sessionId} />
|
|
</ResizablePanel>
|
|
</ResizablePanelGroup>
|
|
</div>
|
|
);
|
|
});
|