Files
ai-workflow/inbox/internal/httpapi/workflow_runs.go
T

168 lines
4.6 KiB
Go

package httpapi
import (
"encoding/json"
"net/http"
"strconv"
workflowrunapp "inbox/internal/app/workflowrun"
"inbox/internal/base/httpx"
"inbox/internal/domain/workflow"
)
func (h *Handler) getWorkflowRun(w http.ResponseWriter, r *http.Request) {
item, err := h.WorkflowRun.Get(r.Context(), r.PathValue("runID"))
if err != nil {
writeStoreError(w, err)
return
}
httpx.WriteJSON(w, http.StatusOK, workflowRunResponse(item))
}
func (h *Handler) listWorkflowRuns(w http.ResponseWriter, r *http.Request) {
items, err := h.WorkflowRun.ListByTopic(r.Context(), r.PathValue("topicID"))
if err != nil {
writeStoreError(w, err)
return
}
out := make([]map[string]any, 0, len(items))
for _, item := range items {
out = append(out, workflowRunResponse(item))
}
httpx.WriteJSON(w, http.StatusOK, map[string]any{"workflow_runs": out})
}
func (h *Handler) createWorkflowRun(w http.ResponseWriter, r *http.Request) {
type request struct {
WorkspaceID string `json:"workspace_id"`
RoleName string `json:"role_name"`
Stage string `json:"stage"`
Mode string `json:"mode"`
RequestMessageID string `json:"request_message_id"`
CommandJSON string `json:"command_json"`
}
var req request
if err := httpx.DecodeJSON(r, &req); err != nil {
httpx.WriteError(w, http.StatusBadRequest, err.Error())
return
}
item, err := h.WorkflowRun.Start(r.Context(), workflow.Run{
WorkspaceID: req.WorkspaceID,
TopicID: r.PathValue("topicID"),
RoleName: req.RoleName,
Stage: workflow.Stage(req.Stage),
Mode: req.Mode,
RequestMessageID: req.RequestMessageID,
CommandJSON: req.CommandJSON,
})
if err != nil {
writeStoreError(w, err)
return
}
httpx.WriteJSON(w, http.StatusCreated, item)
}
func (h *Handler) patchWorkflowRun(w http.ResponseWriter, r *http.Request) {
type request struct {
Status *workflow.RunStatus `json:"status"`
ReplyMessageID *string `json:"reply_message_id"`
ExitCode *int `json:"exit_code"`
CompletedAt *string `json:"completed_at"`
ErrorMessage *string `json:"error_message"`
CommandJSON *string `json:"command_json"`
}
var req request
if err := httpx.DecodeJSON(r, &req); err != nil {
httpx.WriteError(w, http.StatusBadRequest, err.Error())
return
}
item, err := h.WorkflowRun.Patch(r.Context(), r.PathValue("runID"), workflowrunapp.Patch{
Status: req.Status,
ReplyMessageID: req.ReplyMessageID,
ExitCode: req.ExitCode,
CompletedAt: req.CompletedAt,
ErrorMessage: req.ErrorMessage,
CommandJSON: req.CommandJSON,
})
if err != nil {
writeStoreError(w, err)
return
}
httpx.WriteJSON(w, http.StatusOK, item)
}
func (h *Handler) listWorkflowRunLogs(w http.ResponseWriter, r *http.Request) {
afterSeq := 0
if raw := r.URL.Query().Get("after_seq"); raw != "" {
value, err := strconv.Atoi(raw)
if err != nil {
httpx.WriteError(w, http.StatusBadRequest, "after_seq must be an integer")
return
}
afterSeq = value
}
items, err := h.WorkflowRun.ListLogs(r.Context(), r.PathValue("runID"), afterSeq)
if err != nil {
writeStoreError(w, err)
return
}
httpx.WriteJSON(w, http.StatusOK, map[string]any{"logs": items})
}
func (h *Handler) appendWorkflowRunLog(w http.ResponseWriter, r *http.Request) {
type request struct {
Stream string `json:"stream"`
Content string `json:"content"`
CreatedAt string `json:"created_at"`
}
var req request
if err := httpx.DecodeJSON(r, &req); err != nil {
httpx.WriteError(w, http.StatusBadRequest, err.Error())
return
}
item, err := h.WorkflowRun.AppendLog(r.Context(), workflow.RunLog{
RunID: r.PathValue("runID"),
Stream: workflow.LogStream(req.Stream),
Content: req.Content,
CreatedAt: req.CreatedAt,
})
if err != nil {
writeStoreError(w, err)
return
}
httpx.WriteJSON(w, http.StatusCreated, item)
}
func workflowRunResponse(item workflow.Run) map[string]any {
payload := map[string]any{}
raw, err := json.Marshal(item)
if err == nil {
_ = json.Unmarshal(raw, &payload)
}
if payload == nil {
payload = map[string]any{}
}
if planning, ok := decodeWorkflowRunPlanning(item.CommandJSON); ok {
payload["planning"] = planning
}
return payload
}
func decodeWorkflowRunPlanning(commandJSON string) (map[string]any, bool) {
if commandJSON == "" {
return nil, false
}
var payload map[string]any
if err := json.Unmarshal([]byte(commandJSON), &payload); err != nil {
return nil, false
}
planning, ok := payload["planning"]
if !ok {
return nil, false
}
typed, ok := planning.(map[string]any)
return typed, ok
}