Files
Agent-System-Backend/internal/store/work_tasks.go
weichen 44ccd63d3b Add trusted project context to work model calls
Why: Project work currently reaches model calls without current authorized project facts or a persisted input receipt.

Evidence: SELF go test ./... -count=1, targeted go test -race for W6 paths, go vet ./..., and CGO_ENABLED=0 go build ./cmd/agent-system passed on this change set.

Impact: Add optional X1 interfaces, trusted persisted work-task binding, request-scoped context injection, evidence reauthorization, and attempted/responded/unknown manifests. Existing non-project behavior stays available.

Refs: TT-C01 TT-C02 TT-C03 TT-C04; stage5 W6; Dev stage6 X1 public extension request r1
2026-10-14 04:09:58 +00:00

58 lines
2.3 KiB
Go

package store
import (
"context"
"database/sql"
"errors"
)
type WorkTaskBinding struct {
TaskID string
Owner string
PluginID string
ConversationID string
ProjectID string
Status string
}
// CreateWorkTask atomically saves the legacy task row and its trusted creation
// scope. A legacy TaskCreate row has no binding and cannot enter work recovery.
func (s *Store) CreateWorkTask(owner, pluginID, projectID, conversationID, kind, title string) (BackgroundTask, error) {
if owner == "" || pluginID == "" || projectID == "" || conversationID == "" || kind == "" {
return BackgroundTask{}, errors.New("work task scope incomplete")
}
tx, err := s.db.BeginTx(context.Background(), nil)
if err != nil {
return BackgroundTask{}, err
}
defer tx.Rollback()
now := nowISO()
t := BackgroundTask{ID: NewID("task"), Owner: owner, Kind: kind, Title: title, Status: "queued", ConversationID: conversationID, CreatedAt: now, UpdatedAt: now}
if _, err := tx.Exec(s.q(`INSERT INTO background_tasks(id,owner,kind,title,status,progress,error,conversation_id,created_at,updated_at) VALUES(?,?,?,?,?,?,?,?,?,?)`),
t.ID, owner, kind, title, t.Status, 0, "", conversationID, now, now); err != nil {
return BackgroundTask{}, err
}
if _, err := tx.Exec(s.q(`INSERT INTO work_task_bindings(task_id,owner,plugin_id,conversation_id,project_id,created_at) VALUES(?,?,?,?,?,?)`),
t.ID, owner, pluginID, conversationID, projectID, now); err != nil {
return BackgroundTask{}, err
}
if err := tx.Commit(); err != nil {
return BackgroundTask{}, err
}
return t, nil
}
// WorkTaskScope resolves a task only under its original owner and plugin.
func (s *Store) WorkTaskScope(owner, pluginID, taskID string) (WorkTaskBinding, error) {
var b WorkTaskBinding
if owner == "" || pluginID == "" || taskID == "" {
return b, ErrNotFound
}
err := s.db.QueryRow(s.q(`SELECT b.task_id,b.owner,b.plugin_id,b.conversation_id,b.project_id,t.status FROM work_task_bindings b JOIN background_tasks t ON t.id=b.task_id WHERE b.task_id=? AND b.owner=? AND b.plugin_id=? AND t.owner=? AND t.conversation_id=b.conversation_id`),
taskID, owner, pluginID, owner).Scan(&b.TaskID, &b.Owner, &b.PluginID, &b.ConversationID, &b.ProjectID, &b.Status)
if errors.Is(err, sql.ErrNoRows) {
return WorkTaskBinding{}, ErrNotFound
}
return b, err
}