Store workflow definitions as table rows and drop YAML
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"g.fc.run/ai/byre/internal/api"
|
||||
)
|
||||
|
||||
func insertDefinition(ctx context.Context, tx *sql.Tx, def api.WorkflowDefinition) (string, error) {
|
||||
id := NewID()
|
||||
_, err := tx.ExecContext(ctx, `INSERT INTO workflow_definitions (id, description) VALUES (?, ?)`, id, def.Description)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
next := 0
|
||||
var insert func(steps []api.WorkflowStep, parent *int) error
|
||||
insert = func(steps []api.WorkflowStep, parent *int) error {
|
||||
for pos, s := range steps {
|
||||
stepID := next
|
||||
next++
|
||||
kind, children := "stage", (*[]api.WorkflowStep)(nil)
|
||||
switch {
|
||||
case s.Order != nil:
|
||||
kind, children = "order", s.Order
|
||||
case s.Parallel != nil:
|
||||
kind, children = "parallel", s.Parallel
|
||||
}
|
||||
_, err := tx.ExecContext(ctx, `INSERT INTO workflow_steps (definition_id, id, parent, position, kind, stage, model, prompt) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
id, stepID, parent, pos, kind, s.Stage, s.Model, s.Prompt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.Agents != nil {
|
||||
for i, a := range *s.Agents {
|
||||
_, err = tx.ExecContext(ctx, `INSERT INTO workflow_agents (definition_id, step_id, position, name, model, prompt) VALUES (?, ?, ?, ?, ?, ?)`,
|
||||
id, stepID, i, a.Name, a.Model, a.Prompt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if children != nil {
|
||||
err = insert(*children, &stepID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return id, insert(def.Steps, nil)
|
||||
}
|
||||
|
||||
type stepRow struct {
|
||||
id int
|
||||
kind string
|
||||
step api.WorkflowStep
|
||||
}
|
||||
|
||||
func loadDefinition(ctx context.Context, q querier, id string) (api.WorkflowDefinition, error) {
|
||||
def := api.WorkflowDefinition{}
|
||||
err := q.QueryRowContext(ctx, `SELECT description FROM workflow_definitions WHERE id = ?`, id).Scan(&def.Description)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return def, fmt.Errorf("%w: no workflow definition %s", ErrNotFound, id)
|
||||
}
|
||||
if err != nil {
|
||||
return def, err
|
||||
}
|
||||
|
||||
agents := map[int][]api.TeamMember{}
|
||||
rows, err := q.QueryContext(ctx, `SELECT step_id, name, model, prompt FROM workflow_agents WHERE definition_id = ? ORDER BY step_id, position`, id)
|
||||
if err != nil {
|
||||
return def, err
|
||||
}
|
||||
for rows.Next() {
|
||||
step := 0
|
||||
a := api.TeamMember{}
|
||||
err = rows.Scan(&step, &a.Name, &a.Model, &a.Prompt)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return def, err
|
||||
}
|
||||
agents[step] = append(agents[step], a)
|
||||
}
|
||||
err = errors.Join(rows.Err(), rows.Close())
|
||||
if err != nil {
|
||||
return def, err
|
||||
}
|
||||
|
||||
children := map[int][]stepRow{}
|
||||
rows, err = q.QueryContext(ctx, `SELECT id, coalesce(parent, -1), kind, stage, model, prompt FROM workflow_steps WHERE definition_id = ? ORDER BY coalesce(parent, -1), position`, id)
|
||||
if err != nil {
|
||||
return def, err
|
||||
}
|
||||
for rows.Next() {
|
||||
r := stepRow{}
|
||||
parent := 0
|
||||
err = rows.Scan(&r.id, &parent, &r.kind, &r.step.Stage, &r.step.Model, &r.step.Prompt)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return def, err
|
||||
}
|
||||
if a, found := agents[r.id]; found {
|
||||
r.step.Agents = &a
|
||||
}
|
||||
children[parent] = append(children[parent], r)
|
||||
}
|
||||
err = errors.Join(rows.Err(), rows.Close())
|
||||
if err != nil {
|
||||
return def, err
|
||||
}
|
||||
|
||||
var build func(parent int) []api.WorkflowStep
|
||||
build = func(parent int) []api.WorkflowStep {
|
||||
steps := []api.WorkflowStep{}
|
||||
for _, r := range children[parent] {
|
||||
switch r.kind {
|
||||
case "order":
|
||||
sub := build(r.id)
|
||||
r.step.Order = &sub
|
||||
case "parallel":
|
||||
sub := build(r.id)
|
||||
r.step.Parallel = &sub
|
||||
}
|
||||
steps = append(steps, r.step)
|
||||
}
|
||||
return steps
|
||||
}
|
||||
def.Steps = build(-1)
|
||||
return def, nil
|
||||
}
|
||||
Reference in New Issue
Block a user