feat(agent): add per-task session persistence for Claude Code resumption
Store the Claude Code session ID and working directory when a task completes. On the next task for the same (agent, issue) pair, look up the prior session and pass --resume <session_id> to Claude Code so the agent retains conversation context across multiple tasks on the same issue. Changes: - Migration 020: add session_id and work_dir columns to agent_task_queue - CompleteAgentTask stores session_id and work_dir on completion - GetLastTaskSession query retrieves prior session for (agent, issue) - ClaimTaskByRuntime handler populates prior_session_id in response - Daemon passes ResumeSessionID through to Claude backend Execute() - Claude backend adds --resume flag when ResumeSessionID is set
This commit is contained in:
parent
42f72371bd
commit
ffda18c809
13 changed files with 147 additions and 49 deletions
|
|
@ -80,19 +80,20 @@ func agentToResponse(a db.Agent) AgentResponse {
|
|||
}
|
||||
|
||||
type AgentTaskResponse struct {
|
||||
ID string `json:"id"`
|
||||
AgentID string `json:"agent_id"`
|
||||
RuntimeID string `json:"runtime_id"`
|
||||
IssueID string `json:"issue_id"`
|
||||
Status string `json:"status"`
|
||||
Priority int32 `json:"priority"`
|
||||
DispatchedAt *string `json:"dispatched_at"`
|
||||
StartedAt *string `json:"started_at"`
|
||||
CompletedAt *string `json:"completed_at"`
|
||||
Result any `json:"result"`
|
||||
Error *string `json:"error"`
|
||||
Agent *TaskAgentData `json:"agent,omitempty"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
ID string `json:"id"`
|
||||
AgentID string `json:"agent_id"`
|
||||
RuntimeID string `json:"runtime_id"`
|
||||
IssueID string `json:"issue_id"`
|
||||
Status string `json:"status"`
|
||||
Priority int32 `json:"priority"`
|
||||
DispatchedAt *string `json:"dispatched_at"`
|
||||
StartedAt *string `json:"started_at"`
|
||||
CompletedAt *string `json:"completed_at"`
|
||||
Result any `json:"result"`
|
||||
Error *string `json:"error"`
|
||||
Agent *TaskAgentData `json:"agent,omitempty"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
PriorSessionID string `json:"prior_session_id,omitempty"` // session ID from a previous task on same issue
|
||||
}
|
||||
|
||||
// TaskAgentData holds agent info included in claim responses so the daemon
|
||||
|
|
|
|||
|
|
@ -216,7 +216,16 @@ func (h *Handler) ClaimTaskByRuntime(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
slog.Info("task claimed by runtime", "task_id", uuidToString(task.ID), "runtime_id", runtimeID, "agent_id", uuidToString(task.AgentID))
|
||||
// Look up the prior session for this (agent, issue) pair so the daemon
|
||||
// can resume the Claude Code conversation context.
|
||||
if prior, err := h.Queries.GetLastTaskSession(r.Context(), db.GetLastTaskSessionParams{
|
||||
AgentID: task.AgentID,
|
||||
IssueID: task.IssueID,
|
||||
}); err == nil && prior.SessionID.Valid {
|
||||
resp.PriorSessionID = prior.SessionID.String
|
||||
}
|
||||
|
||||
slog.Info("task claimed by runtime", "task_id", uuidToString(task.ID), "runtime_id", runtimeID, "agent_id", uuidToString(task.AgentID), "prior_session", resp.PriorSessionID)
|
||||
writeJSON(w, http.StatusOK, map[string]any{"task": resp})
|
||||
}
|
||||
|
||||
|
|
@ -288,8 +297,10 @@ func (h *Handler) ReportTaskProgress(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// CompleteTask marks a running task as completed.
|
||||
type TaskCompleteRequest struct {
|
||||
PRURL string `json:"pr_url"`
|
||||
Output string `json:"output"`
|
||||
PRURL string `json:"pr_url"`
|
||||
Output string `json:"output"`
|
||||
SessionID string `json:"session_id"` // Claude session ID for future resumption
|
||||
WorkDir string `json:"work_dir"` // working directory used during execution
|
||||
}
|
||||
|
||||
func (h *Handler) CompleteTask(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -302,7 +313,7 @@ func (h *Handler) CompleteTask(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
result, _ := json.Marshal(req)
|
||||
task, err := h.TaskService.CompleteTask(r.Context(), parseUUID(taskID), result)
|
||||
task, err := h.TaskService.CompleteTask(r.Context(), parseUUID(taskID), result, req.SessionID, req.WorkDir)
|
||||
if err != nil {
|
||||
slog.Warn("complete task failed", "task_id", taskID, "error", err)
|
||||
writeError(w, http.StatusBadRequest, err.Error())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue