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
127 lines
4.1 KiB
Go
127 lines
4.1 KiB
Go
// Package instance provides data structures for multi-agent instance management.
|
|
// It defines the core types used to represent, create, and serialize agent instances
|
|
// that run as separate processes with their own HTTP servers.
|
|
package instance
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/kandev/kandev/internal/agentctl/server/process"
|
|
)
|
|
|
|
// Instance represents a single agent instance running as a subprocess.
|
|
// Each instance has its own process manager, HTTP server, and configuration.
|
|
type Instance struct {
|
|
// ID is the unique identifier for this instance
|
|
ID string
|
|
|
|
// Port is the HTTP port this instance is listening on
|
|
Port int
|
|
|
|
// Status is the current status of the instance (e.g., "running", "stopped", "error")
|
|
Status string
|
|
|
|
// WorkspacePath is the absolute path to the workspace directory for this instance
|
|
WorkspacePath string
|
|
|
|
// AgentCommand is the command used to start the agent subprocess
|
|
AgentCommand string
|
|
|
|
// Env contains environment variables passed to the agent process
|
|
Env map[string]string
|
|
|
|
// CreatedAt is the timestamp when this instance was created
|
|
CreatedAt time.Time
|
|
|
|
// manager is the process manager handling the agent subprocess (unexported)
|
|
manager *process.Manager
|
|
|
|
// server is the HTTP server for this instance's API (unexported)
|
|
server *http.Server
|
|
}
|
|
|
|
// CreateRequest contains the parameters for creating a new agent instance.
|
|
type CreateRequest struct {
|
|
// ID is an optional identifier for the instance. If empty, one will be generated.
|
|
ID string `json:"id,omitempty"`
|
|
|
|
// WorkspacePath is the required absolute path to the workspace directory.
|
|
WorkspacePath string `json:"workspace_path"`
|
|
|
|
// AgentCommand is an optional command to start the agent. If empty, a default is used.
|
|
AgentCommand string `json:"agent_command,omitempty"`
|
|
|
|
// Protocol is the protocol adapter to use (acp, codex). If empty, default is used.
|
|
Protocol string `json:"protocol,omitempty"`
|
|
|
|
// WorkspaceFlag is the CLI flag for workspace path (e.g., "--workspace-root").
|
|
// If empty, only cwd is used for workspace path.
|
|
WorkspaceFlag string `json:"workspace_flag,omitempty"`
|
|
|
|
// Env contains optional environment variables to pass to the agent process.
|
|
Env map[string]string `json:"env,omitempty"`
|
|
|
|
// AutoStart indicates whether to start the agent automatically after creation.
|
|
AutoStart bool `json:"auto_start,omitempty"`
|
|
}
|
|
|
|
// CreateResponse contains the result of creating a new agent instance.
|
|
type CreateResponse struct {
|
|
// ID is the unique identifier assigned to the created instance
|
|
ID string `json:"id"`
|
|
|
|
// Port is the HTTP port the instance is listening on
|
|
Port int `json:"port"`
|
|
}
|
|
|
|
// InstanceInfo contains serializable information about an instance for API responses.
|
|
// It mirrors the exported fields from Instance and is safe for JSON serialization.
|
|
type InstanceInfo struct {
|
|
// ID is the unique identifier for this instance
|
|
ID string `json:"id"`
|
|
|
|
// Port is the HTTP port this instance is listening on
|
|
Port int `json:"port"`
|
|
|
|
// Status is the current status of the instance
|
|
Status string `json:"status"`
|
|
|
|
// WorkspacePath is the absolute path to the workspace directory
|
|
WorkspacePath string `json:"workspace_path"`
|
|
|
|
// AgentCommand is the command used to start the agent subprocess
|
|
AgentCommand string `json:"agent_command"`
|
|
|
|
// Env contains environment variables passed to the agent process
|
|
Env map[string]string `json:"env,omitempty"`
|
|
|
|
// CreatedAt is the timestamp when this instance was created
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// Info returns a safe copy of the instance data for API serialization.
|
|
// This method creates an InstanceInfo struct containing only the exported,
|
|
// serializable fields from the Instance.
|
|
func (i *Instance) Info() *InstanceInfo {
|
|
// Create a copy of the environment map to prevent external modification
|
|
var envCopy map[string]string
|
|
if i.Env != nil {
|
|
envCopy = make(map[string]string, len(i.Env))
|
|
for k, v := range i.Env {
|
|
envCopy[k] = v
|
|
}
|
|
}
|
|
|
|
return &InstanceInfo{
|
|
ID: i.ID,
|
|
Port: i.Port,
|
|
Status: i.Status,
|
|
WorkspacePath: i.WorkspacePath,
|
|
AgentCommand: i.AgentCommand,
|
|
Env: envCopy,
|
|
CreatedAt: i.CreatedAt,
|
|
}
|
|
}
|
|
|