Store workflow definitions as table rows and drop YAML
This commit is contained in:
@@ -15,12 +15,12 @@ import (
|
||||
"g.fc.run/ai/byre/internal/workflow"
|
||||
)
|
||||
|
||||
func (m *Manager) SaveWorkflow(ctx context.Context, name, from string, file []byte, actor string) (api.WorkflowSummary, error) {
|
||||
func (m *Manager) SaveWorkflow(ctx context.Context, name, from string, definition []byte, actor string) (api.WorkflowSummary, error) {
|
||||
name, err := workflow.CleanName(name)
|
||||
if err != nil {
|
||||
return api.WorkflowSummary{}, err
|
||||
}
|
||||
def, err := workflow.Parse(file)
|
||||
def, err := workflow.Parse(definition)
|
||||
if err != nil {
|
||||
return api.WorkflowSummary{}, err
|
||||
}
|
||||
@@ -58,24 +58,12 @@ func reviewProblem(def api.WorkflowDefinition) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) WorkflowFile(ctx context.Context, name string) ([]byte, error) {
|
||||
def, err := m.store.GetWorkflow(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return workflow.Format(def)
|
||||
}
|
||||
|
||||
func (m *Manager) TaskWorkflow(ctx context.Context, taskID string) (api.TaskWorkflow, error) {
|
||||
frozen, err := m.store.TaskWorkflow(ctx, taskID)
|
||||
if err != nil {
|
||||
return api.TaskWorkflow{}, err
|
||||
}
|
||||
file, err := workflow.Format(frozen.Definition)
|
||||
if err != nil {
|
||||
return api.TaskWorkflow{}, err
|
||||
}
|
||||
return api.TaskWorkflow{Name: frozen.Name, Definition: string(file)}, nil
|
||||
return api.TaskWorkflow{Name: frozen.Name, Definition: frozen.Definition}, nil
|
||||
}
|
||||
|
||||
func (m *Manager) WorkflowRun(ctx context.Context, taskID string) (api.WorkflowRun, error) {
|
||||
@@ -719,7 +707,48 @@ func stageGuidance(frozen store.FrozenWorkflow, stage string) string {
|
||||
"%s. Until you call it, the workflow waits on this stage.", stage, frozen.Name, then)
|
||||
}
|
||||
|
||||
const workflowFileHelp = "The file's YAML format is the read_knowledge article workflow-files."
|
||||
const workflowHelp = "The definition's fields are the read_knowledge article workflow-definitions."
|
||||
|
||||
const workflowDefinitionSchema = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {"type": "string"},
|
||||
"steps": {"type": "array", "items": {"$ref": "#/$defs/step"}}
|
||||
},
|
||||
"required": ["steps"],
|
||||
"additionalProperties": false
|
||||
}`
|
||||
|
||||
const workflowSchemaDefs = `"$defs": {
|
||||
"step": {
|
||||
"type": "object",
|
||||
"description": "Exactly one of stage (with model or agents, and prompt), order or parallel.",
|
||||
"properties": {
|
||||
"stage": {"type": "string"},
|
||||
"model": {"type": "string"},
|
||||
"prompt": {"type": "string"},
|
||||
"agents": {"type": "array", "items": {"$ref": "#/$defs/agent"}},
|
||||
"order": {"type": "array", "items": {"$ref": "#/$defs/step"}},
|
||||
"parallel": {"type": "array", "items": {"$ref": "#/$defs/step"}}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"agent": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"model": {"type": "string"},
|
||||
"prompt": {"type": "string"}
|
||||
},
|
||||
"required": ["name", "model", "prompt"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}`
|
||||
|
||||
func formatDefinition(def api.WorkflowDefinition) (string, error) {
|
||||
b, err := json.MarshalIndent(def, "", " ")
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
func (m *Manager) workflowTools(tool func(name, description, schema string, run func(ctx context.Context, user api.User, raw json.RawMessage) (string, error)) mcp.Tool) []mcp.Tool {
|
||||
return []mcp.Tool{
|
||||
@@ -746,7 +775,7 @@ func (m *Manager) workflowTools(tool func(name, description, schema string, run
|
||||
}),
|
||||
|
||||
tool("read_workflow",
|
||||
"Read a workflow's file: with name, the workflow on the server; with task_id, the copy that task froze when it was created. "+workflowFileHelp,
|
||||
"Read a workflow's definition: with name, the workflow on the server; with task_id, the copy that task froze when it was created. "+workflowHelp,
|
||||
`{"type": "object", "properties": {
|
||||
"name": {"type": "string"},
|
||||
"task_id": {"type": "string"}
|
||||
@@ -764,33 +793,40 @@ func (m *Manager) workflowTools(tool func(name, description, schema string, run
|
||||
return "", fmt.Errorf("%w: give exactly one of name and task_id", ErrInvalid)
|
||||
}
|
||||
if args.TaskID != "" {
|
||||
tw, err := m.TaskWorkflow(ctx, args.TaskID)
|
||||
frozen, err := m.store.TaskWorkflow(ctx, args.TaskID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("Task %s froze workflow %q:\n\n%s", args.TaskID, tw.Name, tw.Definition), nil
|
||||
text, err := formatDefinition(frozen.Definition)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("Task %s froze workflow %q:\n\n%s", args.TaskID, frozen.Name, text), nil
|
||||
}
|
||||
file, err := m.WorkflowFile(ctx, args.Name)
|
||||
return string(file), err
|
||||
def, err := m.store.GetWorkflow(ctx, args.Name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return formatDefinition(def)
|
||||
}),
|
||||
|
||||
tool("save_workflow",
|
||||
"Create or replace a workflow on the server from its file. Tasks that already froze it keep their copy. "+
|
||||
"The name is one line of 1 to 100 characters, shown to the human on buttons and pickers. "+workflowFileHelp,
|
||||
"Create or replace a workflow on the server from its definition. Tasks that already froze it keep their copy. "+
|
||||
"The name is one line of 1 to 100 characters, shown to the human on buttons and pickers. "+workflowHelp,
|
||||
`{"type": "object", "properties": {
|
||||
"name": {"type": "string"},
|
||||
"definition": {"type": "string", "description": "The workflow's file, as YAML."}
|
||||
}, "required": ["name", "definition"]}`,
|
||||
"definition": `+workflowDefinitionSchema+`
|
||||
}, "required": ["name", "definition"], `+workflowSchemaDefs+`}`,
|
||||
func(ctx context.Context, user api.User, raw json.RawMessage) (string, error) {
|
||||
args := struct {
|
||||
Name string `json:"name"`
|
||||
Definition string `json:"definition"`
|
||||
Name string `json:"name"`
|
||||
Definition json.RawMessage `json:"definition"`
|
||||
}{}
|
||||
err := json.Unmarshal(raw, &args)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
w, err := m.SaveWorkflow(ctx, args.Name, "", []byte(args.Definition), leadActor(user.Login))
|
||||
w, err := m.SaveWorkflow(ctx, args.Name, "", args.Definition, leadActor(user.Login))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user