归档
This commit is contained in:
1 parent
594436fddd
commit
9da521ee4e
31 files changed
+5768
-267
No files matched your search
+24
-3
@@ -116,6 +116,11 @@ type Server struct {
|
||||
// the persisted current profile at every new LLM call.
|
||||
taskAgentMu sync.Mutex
|
||||
taskAgents map[string]*taskAgentBundle
|
||||
|
||||
// Cold task archives run through one persistent FIFO worker. The buffered wake
|
||||
// channel coalesces enqueue bursts; the database remains the source of truth.
|
||||
archiveWake chan struct{}
|
||||
archiveWG sync.WaitGroup
|
||||
}
|
||||
|
||||
// profBundle is a planner/worker pair built from one LLM profile.
|
||||
@@ -151,7 +156,7 @@ func New(ctx context.Context, m *Manager, skillDir string, dataDir string, keyDi
|
||||
triggerActive: map[string]int{}, triggerCfg: map[string]triggerBehavior{},
|
||||
profAgents: map[int64]*profBundle{}, profChatAgents: map[int64]*agent.ChatAgent{},
|
||||
provByProfile: map[int64]*provEntry{}, llmHealth: newLLMHealthRegistry(m.pg),
|
||||
taskAgents: map[string]*taskAgentBundle{}}
|
||||
taskAgents: map[string]*taskAgentBundle{}, archiveWake: make(chan struct{}, 1)}
|
||||
// Every task uses a stable task router. An empty explicit chain is resolved by
|
||||
// that router through Agent bindings and then the global provider, so adding a
|
||||
// first chain to a running task takes effect on its very next LLM call.
|
||||
@@ -264,6 +269,7 @@ func New(ctx context.Context, m *Manager, skillDir string, dataDir string, keyDi
|
||||
}
|
||||
}
|
||||
go s.reconcileConcurrency()
|
||||
s.startTaskArchiveWorker()
|
||||
s.wireInterceptReviewer() // LLM 兜底审批:未命中拦截规则的命令交给模型判定
|
||||
return s
|
||||
}
|
||||
@@ -690,6 +696,14 @@ func (s *Server) Handler() http.Handler {
|
||||
mux.HandleFunc("PATCH /api/tasks/{id}", s.updateTaskMetadata)
|
||||
mux.HandleFunc("PATCH /api/tasks/{id}/category", s.updateTaskCategory)
|
||||
mux.HandleFunc("POST /api/tasks/control/batch", s.controlTasksBatch)
|
||||
mux.HandleFunc("GET /api/task-archives", s.listTaskArchives)
|
||||
mux.HandleFunc("GET /api/task-archives/{id}", s.getTaskArchive)
|
||||
mux.HandleFunc("POST /api/tasks/{id}/archive", s.queueTaskArchive)
|
||||
mux.HandleFunc("POST /api/tasks/archive/batch", s.queueTaskArchivesBatch)
|
||||
mux.HandleFunc("POST /api/task-archives/{id}/restore", s.queueTaskArchiveRestore)
|
||||
mux.HandleFunc("POST /api/task-archives/restore/batch", s.restoreTaskArchivesBatch)
|
||||
mux.HandleFunc("DELETE /api/task-archives/{id}", s.queueTaskArchiveDelete)
|
||||
mux.HandleFunc("POST /api/task-archives/delete/batch", s.deleteTaskArchivesBatch)
|
||||
mux.HandleFunc("GET /api/tasks/{id}/coverage", s.taskCoverage)
|
||||
mux.HandleFunc("GET /api/tasks/{id}/coverage-graph", s.taskCoverageGraph)
|
||||
mux.HandleFunc("GET /api/tasks/{id}/asset-refs", s.taskAssetRefs)
|
||||
@@ -996,9 +1010,11 @@ func (s *Server) listTasks(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
list := s.m.List()
|
||||
metrics, _ := s.m.PG().TaskListMetricsAll()
|
||||
archiveBlockers, _ := s.m.PG().TaskArchiveBlockers()
|
||||
dtos := make([]TaskDTO, 0, len(list))
|
||||
for _, t := range list {
|
||||
dto := taskDTO(t, s.resolvedTaskStatus(t))
|
||||
applyTaskArchiveBlocker(&dto, archiveBlockers)
|
||||
metric := metrics[t.ExpID]
|
||||
dto.Tokens = tokenTotalDTO(metric.Tokens)
|
||||
// prefer the live in-memory heartbeat (fresher) and fall back to the
|
||||
@@ -1640,7 +1656,10 @@ func (s *Server) getTask(w http.ResponseWriter, r *http.Request) {
|
||||
writeErr(w, 404, "task not found")
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, taskDTO(t, s.resolvedTaskStatus(t)))
|
||||
dto := taskDTO(t, s.resolvedTaskStatus(t))
|
||||
archiveBlockers, _ := s.m.PG().TaskArchiveBlockers()
|
||||
applyTaskArchiveBlocker(&dto, archiveBlockers)
|
||||
writeJSON(w, 200, dto)
|
||||
}
|
||||
|
||||
// taskCoverage returns a task's rough asset test coverage (denominator/tested/backlog).
|
||||
@@ -1842,6 +1861,7 @@ func (s *Server) findings(w http.ResponseWriter, r *http.Request) {
|
||||
VulnClass: normFilter(q.Get("vulnclass")),
|
||||
// task_id(独立于会切到「按任务节点」分支的 task 参数):全局表按任务筛选。
|
||||
TaskID: normFilter(q.Get("task_id")),
|
||||
Query: q.Get("q"),
|
||||
Sort: q.Get("sort"),
|
||||
}
|
||||
fs, total, err := s.m.pg.ListFindingsPage(filter, page, limit)
|
||||
@@ -2011,7 +2031,7 @@ func (s *Server) getFinding(w http.ResponseWriter, r *http.Request) {
|
||||
// format = md-single(整合一份 .md)| md-zip(一漏洞一 .md,打包 zip)
|
||||
// | csv | json
|
||||
// ids = 逗号分隔的 finding id(scope=selected 时必填)
|
||||
// 筛选参数 severity/status/vulnclass/task_id/sort 与列表接口一致(scope=filtered 用)。
|
||||
// 筛选参数 severity/status/vulnclass/task_id/q/sort 与列表接口一致(scope=filtered 用)。
|
||||
func (s *Server) findingsExport(w http.ResponseWriter, r *http.Request) {
|
||||
q := r.URL.Query()
|
||||
scope := q.Get("scope")
|
||||
@@ -2045,6 +2065,7 @@ func (s *Server) findingsExport(w http.ResponseWriter, r *http.Request) {
|
||||
Status: normFilter(q.Get("status")),
|
||||
VulnClass: normFilter(q.Get("vulnclass")),
|
||||
TaskID: normFilter(q.Get("task_id")),
|
||||
Query: q.Get("q"),
|
||||
Sort: q.Get("sort"),
|
||||
}
|
||||
default:
|
||||
|
||||
Reference in new issue
Block a user