The task run API was emitting PascalCase fields, so the client never saw status or error_message and treated every disconnect as a network error. Co-authored-by: Cursor <cursoragent@cursor.com>
76 lines
2.5 KiB
Go
76 lines
2.5 KiB
Go
package taskrun
|
||
|
||
import (
|
||
"context"
|
||
"sync"
|
||
"time"
|
||
|
||
"chat-agent-system/internal/stream"
|
||
)
|
||
|
||
// CreateRequest 创建后台任务运行实例。
|
||
type CreateRequest struct {
|
||
SessionID string
|
||
ProjectID int64
|
||
UserID int64
|
||
ClientTurnID string
|
||
TaskKey string
|
||
Stage string
|
||
WorkDir string
|
||
UserMessage string
|
||
AssistantMsgID int64
|
||
IncludeDetails bool
|
||
TaskReq any // *server task payload converted to bizdev request at execution layer
|
||
}
|
||
|
||
// RunRecord 运行实例状态。
|
||
// JSON 键与前端约定及 task_runs 列名一致;缺标签时 encoding/json 会输出 PascalCase,
|
||
// 前端读 status/error_message 会得到 undefined,断线恢复分支全部失效。
|
||
type RunRecord struct {
|
||
RunID string `json:"run_id"`
|
||
SessionID string `json:"session_id"`
|
||
ProjectID int64 `json:"project_id"`
|
||
UserID int64 `json:"user_id"`
|
||
ClientTurnID string `json:"client_turn_id"`
|
||
IdempotencyKey string `json:"idempotency_key"`
|
||
TaskKey string `json:"task_key"`
|
||
Stage string `json:"stage"`
|
||
WorkflowInstanceID int64 `json:"workflow_instance_id"`
|
||
StageInstanceID int64 `json:"stage_instance_id"`
|
||
WorkflowStageKey string `json:"workflow_stage_key"`
|
||
Status string `json:"status"` // pending | running | completed | failed | cancelled | pending_author_confirmation | blocked_pending_governance | …
|
||
WorkspaceID string `json:"workspace_id"`
|
||
AssistantMsgID int64 `json:"assistant_message_id"`
|
||
WorkerID string `json:"worker_id"`
|
||
LeaseExpiresAt *time.Time `json:"lease_expires_at"`
|
||
CreatedAt time.Time `json:"created_at"`
|
||
UpdatedAt time.Time `json:"updated_at"`
|
||
ErrorMessage string `json:"error_message"`
|
||
Attempt int `json:"attempt"`
|
||
}
|
||
|
||
// BuildTaskRunIdempotencyKey 新创建用稳定幂等键;空 client_turn 不设键。
|
||
func BuildTaskRunIdempotencyKey(sessionID, clientTurnID string) string {
|
||
if sessionID == "" || clientTurnID == "" {
|
||
return ""
|
||
}
|
||
return "turn:" + sessionID + ":" + clientTurnID
|
||
}
|
||
|
||
// StoredEvent 持久化 SSE 事件(支持重连重放)。
|
||
type StoredEvent struct {
|
||
Seq int64
|
||
Event stream.StreamEvent
|
||
}
|
||
|
||
type activeRun struct {
|
||
record *RunRecord
|
||
events []StoredEvent
|
||
nextSeq int64
|
||
subs map[int]chan StoredEvent
|
||
subSeq int
|
||
cancel context.CancelFunc
|
||
done chan struct{}
|
||
mu sync.RWMutex
|
||
}
|