Drop workflow kinds, deliver reviews when done, rename/delete workflows
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
UPDATE workflows SET definition = json_remove(definition, '$.kind')
|
||||
WHERE json_type(definition, '$.kind') IS NOT NULL;
|
||||
|
||||
UPDATE tasks SET workflow_definition = json_remove(workflow_definition, '$.kind')
|
||||
WHERE workflow_definition != '' AND json_type(workflow_definition, '$.kind') IS NOT NULL;
|
||||
|
||||
UPDATE reviews SET definition = json_remove(definition, '$.kind')
|
||||
WHERE definition != '' AND json_type(definition, '$.kind') IS NOT NULL;
|
||||
|
||||
UPDATE events SET payload = json_set(payload, '$.kept', json_array(task_id))
|
||||
WHERE kind = 'task.workflow_finished' AND json_type(payload, '$.kept') IS NULL;
|
||||
@@ -0,0 +1,25 @@
|
||||
CREATE TABLE reviews_next (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_id TEXT NOT NULL REFERENCES tasks(id),
|
||||
snapshot_n INTEGER NOT NULL,
|
||||
agent_session_id TEXT REFERENCES agent_sessions(id),
|
||||
vendor TEXT NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
state TEXT NOT NULL,
|
||||
result TEXT NOT NULL DEFAULT '',
|
||||
error TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL,
|
||||
finished_at TEXT NOT NULL DEFAULT '',
|
||||
finding_states TEXT NOT NULL DEFAULT '{}',
|
||||
finding_responses TEXT NOT NULL DEFAULT '{}',
|
||||
stage TEXT NOT NULL DEFAULT '',
|
||||
definition TEXT NOT NULL DEFAULT '',
|
||||
UNIQUE (task_id, snapshot_n, stage)
|
||||
);
|
||||
|
||||
INSERT INTO reviews_next (id, task_id, snapshot_n, agent_session_id, vendor, model, state, result, error, created_at, finished_at, finding_states, finding_responses, stage, definition)
|
||||
SELECT id, task_id, snapshot_n, agent_session_id, vendor, model, state, result, error, created_at, finished_at, finding_states, finding_responses, stage, definition FROM reviews;
|
||||
|
||||
DROP TABLE reviews;
|
||||
ALTER TABLE reviews_next RENAME TO reviews;
|
||||
CREATE UNIQUE INDEX reviews_session ON reviews(agent_session_id);
|
||||
@@ -18,7 +18,7 @@ type FrozenWorkflow struct {
|
||||
}
|
||||
|
||||
func (s *Store) ListWorkflows(ctx context.Context) ([]api.WorkflowSummary, error) {
|
||||
rows, err := s.db.QueryContext(ctx, `SELECT name, coalesce(json_extract(definition, '$.description'), ''), coalesce(nullif(json_extract(definition, '$.kind'), ''), 'task') FROM workflows ORDER BY name`)
|
||||
rows, err := s.db.QueryContext(ctx, `SELECT name, coalesce(json_extract(definition, '$.description'), '') FROM workflows ORDER BY name`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -27,7 +27,7 @@ func (s *Store) ListWorkflows(ctx context.Context) ([]api.WorkflowSummary, error
|
||||
workflows := []api.WorkflowSummary{}
|
||||
for rows.Next() {
|
||||
w := api.WorkflowSummary{}
|
||||
err = rows.Scan(&w.Name, &w.Description, &w.Kind)
|
||||
err = rows.Scan(&w.Name, &w.Description)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -50,12 +50,46 @@ func (s *Store) GetWorkflow(ctx context.Context, name string) (api.WorkflowDefin
|
||||
return w, err
|
||||
}
|
||||
|
||||
func (s *Store) PutWorkflow(ctx context.Context, name string, def api.WorkflowDefinition, actor string) error {
|
||||
var ErrWorkflowExists = errors.New("workflow exists")
|
||||
|
||||
func (s *Store) PutWorkflow(ctx context.Context, name, from string, def api.WorkflowDefinition, actor string) error {
|
||||
b, err := json.Marshal(def)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
|
||||
if from != "" {
|
||||
found := false
|
||||
err := tx.QueryRowContext(ctx, `SELECT EXISTS (SELECT 1 FROM workflows WHERE name = ?)`, from).Scan(&found)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !found {
|
||||
return fmt.Errorf("%w: no workflow %q", ErrNotFound, from)
|
||||
}
|
||||
}
|
||||
if from != "" && from != name {
|
||||
taken := false
|
||||
err := tx.QueryRowContext(ctx, `SELECT EXISTS (SELECT 1 FROM workflows WHERE name = ?)`, name).Scan(&taken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if taken {
|
||||
return fmt.Errorf("%w: a workflow named %q already exists", ErrWorkflowExists, name)
|
||||
}
|
||||
_, err = tx.ExecContext(ctx, `DELETE FROM workflows WHERE name = ?`, from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = repointReviews(ctx, tx, emit, from, name, actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = emit(api.Event{Kind: "workflow.deleted", Actor: actor, Payload: map[string]any{"name": from}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err := tx.ExecContext(ctx, `INSERT INTO workflows (name, definition) VALUES (?, ?)
|
||||
ON CONFLICT (name) DO UPDATE SET definition = excluded.definition`, name, string(b))
|
||||
if err != nil {
|
||||
@@ -65,6 +99,33 @@ func (s *Store) PutWorkflow(ctx context.Context, name string, def api.WorkflowDe
|
||||
})
|
||||
}
|
||||
|
||||
func repointReviews(ctx context.Context, tx *sql.Tx, emit emitFunc, from, to, actor string) error {
|
||||
rows, err := tx.QueryContext(ctx, `UPDATE projects SET review_workflow = ? WHERE review_workflow = ? RETURNING `+projectColumns, to, from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projects := []api.Project{}
|
||||
for rows.Next() {
|
||||
p, err := scanProject(rows)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return err
|
||||
}
|
||||
projects = append(projects, p)
|
||||
}
|
||||
err = errors.Join(rows.Err(), rows.Close())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range projects {
|
||||
err = emit(api.Event{Kind: "project.updated", ProjectId: &p.Id, Actor: actor, Payload: ToPayload(p)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) DeleteWorkflow(ctx context.Context, name, actor string) error {
|
||||
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
|
||||
res, err := tx.ExecContext(ctx, `DELETE FROM workflows WHERE name = ?`, name)
|
||||
@@ -78,6 +139,10 @@ func (s *Store) DeleteWorkflow(ctx context.Context, name, actor string) error {
|
||||
if n == 0 {
|
||||
return fmt.Errorf("%w: no workflow %q", ErrNotFound, name)
|
||||
}
|
||||
err = repointReviews(ctx, tx, emit, name, "", actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return emit(api.Event{Kind: "workflow.deleted", Actor: actor, Payload: map[string]any{"name": name}})
|
||||
})
|
||||
}
|
||||
@@ -201,7 +266,7 @@ func clearStage(ctx context.Context, tx *sql.Tx, sessionID string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) FinishWorkflow(ctx context.Context, task api.Task, sessionID, workflowName, output string) error {
|
||||
func (s *Store) FinishWorkflow(ctx context.Context, task api.Task, sessionID, workflowName, output string, kept []string) error {
|
||||
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
|
||||
err := clearStage(ctx, tx, sessionID)
|
||||
if err != nil {
|
||||
@@ -212,7 +277,7 @@ func (s *Store) FinishWorkflow(ctx context.Context, task api.Task, sessionID, wo
|
||||
ProjectId: &task.ProjectId,
|
||||
TaskId: &task.Id,
|
||||
Actor: "byre",
|
||||
Payload: map[string]any{"id": task.Id, "workflow": workflowName, "output": output},
|
||||
Payload: map[string]any{"id": task.Id, "workflow": workflowName, "output": output, "kept": kept},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user