Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
dca3acb
add http app
satti-hari-krishna-reddy Mar 12, 2026
55e6a27
fix agent stuck loading due to timeout
satti-hari-krishna-reddy Mar 12, 2026
1d7c968
added auth injection for other internal apps as well
satti-hari-krishna-reddy Mar 12, 2026
db9f83b
include more conditions
satti-hari-krishna-reddy Apr 1, 2026
8a2855c
commented out not used code
satti-hari-krishna-reddy Apr 2, 2026
3acdb25
a ton of changes again
satti-hari-krishna-reddy Apr 3, 2026
04deb5b
undo some changes for now
satti-hari-krishna-reddy Apr 3, 2026
44924c5
increase the TTL terminal statuses
satti-hari-krishna-reddy Apr 3, 2026
aa044c1
fixed some abort bugs
satti-hari-krishna-reddy Apr 4, 2026
44c8398
general output format fix
satti-hari-krishna-reddy Apr 4, 2026
26de432
added more visibility in logs
satti-hari-krishna-reddy Apr 5, 2026
9148a37
added trace logs to handleRunDatastoreAutomation
satti-hari-krishna-reddy Apr 5, 2026
943e2e7
using the context instead of modifying function signature
satti-hari-krishna-reddy Apr 5, 2026
117b3f5
use the context for passing caller and trace info
satti-hari-krishna-reddy Apr 5, 2026
1075052
update the call with right params
satti-hari-krishna-reddy Apr 5, 2026
e50fef7
commented out for now
satti-hari-krishna-reddy Apr 5, 2026
3275f96
added new alowed headers to cors check
satti-hari-krishna-reddy Apr 6, 2026
1e556f8
code ql fix: added Escape single quotes
satti-hari-krishna-reddy Apr 6, 2026
d60c6f9
fix: ensure caller context is set in PrepareSingleAction
satti-hari-krishna-reddy Apr 27, 2026
10cc3c3
fix: replace random trace ID generation with UUID
satti-hari-krishna-reddy Apr 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 115 additions & 93 deletions ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -7054,7 +7054,7 @@ func runSupportRequest(ctx context.Context, input QueryInput) string {
// Callers must return immediately after this call.
func abortAgentExecution(ctx context.Context, execution WorkflowExecution, startNode Action, base AgentOutput, abortLabel, reason string) (Action, error) {
agentOutput := base
agentOutput.Status = "FINISHED"
agentOutput.Status = "ABORTED"
agentOutput.Error = reason
agentOutput.CompletedAt = time.Now().Unix()

Expand Down Expand Up @@ -7098,15 +7098,13 @@ func abortAgentExecution(ctx context.Context, execution WorkflowExecution, start
marshalledOutput, marshalErr := json.Marshal(agentOutput)
if marshalErr != nil {
log.Printf("[ERROR][%s] abortAgentExecution: failed marshalling AgentOutput: %s", execution.ExecutionId, marshalErr)
marshalledOutput = []byte(`{"status":"FINISHED","error":"marshal error"}`)
marshalledOutput = []byte(`{"status":"ABORTED","error":"marshal error"}`)
}

log.Printf("[ERROR][%s] AI_AGENT_ABORT: org=%s label=%s decisions=%d llm_calls=%d total_tokens=%d reason=%q",
execution.ExecutionId, execution.Workflow.OrgId, abortLabel,
len(agentOutput.Decisions), agentOutput.LLMCallCount, agentOutput.TotalTokens, reason)
// log.Printf("[ERROR][%s] AI_AGENT_ABORT: org=%s label=%s decisions=%d llm_calls=%d total_tokens=%d reason=%q", execution.ExecutionId, execution.Workflow.OrgId, abortLabel, len(agentOutput.Decisions), agentOutput.LLMCallCount, agentOutput.TotalTokens, reason)

abortResult := ActionResult{
Status: "SUCCESS",
Status: "ABORTED",
Result: string(marshalledOutput),
Action: startNode,
StartedAt: time.Now().UnixMilli(),
Expand All @@ -7127,8 +7125,11 @@ func abortAgentExecution(ctx context.Context, execution WorkflowExecution, start
execution.Results = append(execution.Results, abortResult)
}

execution.Status = "FINISHED"
execution.Status = "ABORTED"

go sendAgentActionSelfRequest("ABORTED", execution, abortResult)
go SetWorkflowExecution(ctx, execution, true)

return startNode, errors.New(reason)
}

Expand Down Expand Up @@ -7181,7 +7182,8 @@ func sendAITokenLimitAlert(ctx context.Context, execution WorkflowExecution, ful

// createNextActions = false => start of agent to find initial decisions
// createNextActions = true => mid-agent to decide next steps
func HandleAiAgentExecutionStart(execution WorkflowExecution, startNode Action, createNextActions bool) (Action, error) {
func HandleAiAgentExecutionStart(ctx context.Context, execution WorkflowExecution, startNode Action, createNextActions bool) (Action, error) {

aiStarttime := time.Now().Unix()
// A handler to ensure we ALWAYS focus on next actions if a node starts late
// or is missing context, but has previous decisions
Expand Down Expand Up @@ -7219,23 +7221,17 @@ func HandleAiAgentExecutionStart(execution WorkflowExecution, startNode Action,
execution.Workflow.OrgId = execution.ExecutionOrg
}

ctx := context.Background()
if ctx == nil {
ctx = context.Background()
}

// Validate On-Prem Configuration immediately
if project.Environment != "cloud" {
if os.Getenv("AI_MODEL") == "" && os.Getenv("OPENAI_MODEL") == "" {
err := errors.New("AI Configuration Error: AI_MODEL or OPENAI_MODEL environment variable must be set for On-Premise AI Agent execution.")
log.Printf("[ERROR] %v", err)

execution.Status = "ABORTED"
execution.Results = append(execution.Results, ActionResult{
Status: "ABORTED",
Result: fmt.Sprintf(`{"success": false, "reason": "%s"}`, err.Error()),
Action: startNode,
})

go SetWorkflowExecution(ctx, execution, true)
return startNode, err
return abortAgentExecution(ctx, execution, startNode, AgentOutput{}, "missing_onprem_ai_config", err.Error())
}
}

Expand Down Expand Up @@ -7445,8 +7441,7 @@ func HandleAiAgentExecutionStart(execution WorkflowExecution, startNode Action,
relevantDecisions = append(relevantDecisions, mappedResult.Decisions[i])
}

log.Printf("[INFO][%s] AI_AGENT: org=%s decisions_total=%d failures=%d successes=%d last_index=%d",
execution.ExecutionId, execution.Workflow.OrgId, len(mappedResult.Decisions), failureCount, successCount, lastFinishedIndex)
log.Printf("[INFO][%s] AI_AGENT: org=%s decisions_total=%d failures=%d successes=%d last_index=%d", execution.ExecutionId, execution.Workflow.OrgId, len(mappedResult.Decisions), failureCount, successCount, lastFinishedIndex)

marshalledDecisions, err = json.Marshal(relevantDecisions)
if err != nil {
Expand Down Expand Up @@ -7663,6 +7658,11 @@ func HandleAiAgentExecutionStart(execution WorkflowExecution, startNode Action,

decidedApps += lowername + ", "
}

// Let's inject http.
if !strings.Contains(decidedApps, "http") {
decidedApps += "http, "
}
}

if len(decidedApps) > 0 {
Expand Down Expand Up @@ -7825,15 +7825,7 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (

if len(userMessage) == 0 {
log.Printf("[ERROR][%s] AI Agent: No user message/input found for action %s", execution.ExecutionId, startNode.ID)
execution.Results = append(execution.Results, ActionResult{
Status: "ABORTED",
Result: fmt.Sprintf(`{"success": false, "reason": "Failed to start AI Agent (3): No input provided."}`),
Action: startNode,
})
go SetWorkflowExecution(ctx, execution, true)

return startNode, errors.New("No user message/input found for AI Agent start")

return abortAgentExecution(ctx, execution, startNode, AgentOutput{}, "no_user_message", "No user message/input found for AI Agent start")
}

// Track who initiated this agent (for audit trail)
Expand All @@ -7843,7 +7835,14 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (
}

if !createNextActions {
log.Printf("[INFO] AI_AGENT_START: execution_id=%s org=%s user=%s input_length=%d", execution.ExecutionId, execution.Workflow.OrgId, initiatedBy, len(userMessage))
caller, _ := ctx.Value("caller").(string)
traceID, _ := ctx.Value("trace_id").(string)
if strings.TrimSpace(caller) == "" {
log.Printf("ERROR[%s] AI agent: No caller function info provided for AI agent, aborting the request ...", execution.ExecutionId)
return abortAgentExecution(ctx, execution, startNode, AgentOutput{}, "no_caller_info", "No caller function info provided for AI Agent start")
Comment on lines +7839 to +7842
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HandleAiAgentExecutionStart now aborts if ctx is missing a non-empty "caller" value. In this repo, GetContext(request) currently always returns context.Background() (no values), so this change will cause agent starts to abort in normal request flows unless every call site/middleware injects ctx.Value("caller"). Consider making caller optional (log a warning + default), or ensure all entry points populate it (e.g., derive from an HTTP header like X-Internal-Caller, or set it at the immediate call sites).

Suggested change
traceID, _ := ctx.Value("trace_id").(string)
if strings.TrimSpace(caller) == "" {
log.Printf("ERROR[%s] AI agent: No caller function info provided for AI agent, aborting the request ...", execution.ExecutionId)
return abortAgentExecution(ctx, execution, startNode, AgentOutput{}, "no_caller_info", "No caller function info provided for AI Agent start")
traceID, _ := ctx.Value("trace_id").(string)
if strings.TrimSpace(caller) == "" {
caller = "unknown"
log.Printf("[WARNING][%s] AI agent: No caller function info provided for AI agent start; defaulting caller=%q", execution.ExecutionId, caller)

Copilot uses AI. Check for mistakes.
}

log.Printf("[INFO][%s] AI_AGENT_START: org=%s workflow=%s user=%s caller=%s trace-id=%s input_length=%d", execution.ExecutionId, execution.Workflow.OrgId, execution.WorkflowId, initiatedBy, caller, traceID, len(userMessage))
}

// Set model based on environment
Expand Down Expand Up @@ -7944,32 +7943,14 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (

if err != nil {
log.Printf("[ERROR][%s] AI Agent: Failed marshalling input for action %s: %s", execution.ExecutionId, startNode.ID, err)

execution.Status = "ABORTED"
execution.Results = append(execution.Results, ActionResult{
Status: "ABORTED",
Result: fmt.Sprintf(`{"success": false, "reason": "Failed to start AI Agent (4): %s"}`, strings.Replace(err.Error(), `"`, `\"`, -1)),
Action: startNode,
})
go SetWorkflowExecution(ctx, execution, true)

return startNode, err
return abortAgentExecution(ctx, execution, startNode, AgentOutput{}, "marshal_request_body_failed", fmt.Sprintf("Failed to start AI Agent (4): %s", err.Error()))
}

//go executeSpecificCloudApp(ctx, execution.ExecutionId, execution.Authorization, urls, startNode)
if !runOpenaiRequest {

log.Printf("[ERROR] AI Agent: Unhandled Singul BODY for OpenAI agent (first request): %s. AI APPNAME (can't be empty): %#v", string(initialAgentRequestBody), appname)

execution.Status = "ABORTED"
execution.Results = append(execution.Results, ActionResult{
Status: "ABORTED",
Result: fmt.Sprintf(`{"success": false, "reason": "Failed to start AI Agent (5): Failed initial AI request. Contact support@shuffler.io if this persists."}`),
Action: startNode,
})
go SetWorkflowExecution(ctx, execution, true)

return startNode, errors.New("Unhandled Singul BODY for OpenAI agent (first request)")
return abortAgentExecution(ctx, execution, startNode, AgentOutput{}, "unsupported_app_not_openai", "Failed to start AI Agent (5): Failed initial AI request. Contact support@shuffler.io if this persists.")
}

if debug {
Expand Down Expand Up @@ -8017,16 +7998,7 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (
marshalledAction, err := json.Marshal(aiNode)
if err != nil {
log.Printf("[ERROR][%s] AI Agent: Failed marshalling action for AI Agent (first agent request): %s", execution.ExecutionId, err)

execution.Status = "ABORTED"
execution.Results = append(execution.Results, ActionResult{
Status: "ABORTED",
Result: fmt.Sprintf(`{"success": false, "reason": "Failed to start AI Agent (6): %s"}`, strings.Replace(err.Error(), `"`, `\"`, -1)),
Action: startNode,
})
go SetWorkflowExecution(ctx, execution, true)

return startNode, err
return abortAgentExecution(ctx, execution, startNode, AgentOutput{}, "marshal_ai_action_failed", fmt.Sprintf("Failed to start AI Agent (6): %s", err.Error()))
}

// Self-request starts here!
Expand Down Expand Up @@ -8078,7 +8050,7 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (
)

if err != nil {
log.Printf("[ERROR][%s] AI Agent: Failed creating request during LLM setup: %s", execution.ExecutionId, err)
log.Printf("[ERROR][%s] AI_AGENT_LLM_FAILURE: Failed creating request during LLM setup: %s", execution.ExecutionId, err)
return abortAgentExecution(ctx, execution, startNode, oldAgentOutput, "llm_request_build_failed", fmt.Sprintf("Failed to start AI Agent (7): %s", err.Error()))
}

Expand Down Expand Up @@ -8167,21 +8139,13 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (
outputMap := HTTPOutput{}
err = json.Unmarshal([]byte(resultMapping.Result), &outputMap)
if err != nil {
log.Printf("[ERROR][%s] AI Agent (3): Failed unmarshalling response from sending request for stream during SKIPPED user input: %s. Body: %s", execution.ExecutionId, err, string(resultMapping.Result))

execution.Status = "ABORTED"
execution.Results = append(execution.Results, ActionResult{
Status: "ABORTED",
Result: fmt.Sprintf(`{"success": false, "reason": "Failed to start AI Agent (1): %s"}`, strings.Replace(err.Error(), `"`, `\"`, -1)),
Action: startNode,
})
go SetWorkflowExecution(ctx, execution, true)

return startNode, err
log.Printf("[ERROR][%s] AI Agent: Failed unmarshalling response from sending request for stream during SKIPPED user input: %s. Body: %s", execution.ExecutionId, err, string(resultMapping.Result))
return abortAgentExecution(ctx, execution, startNode, AgentOutput{}, "llm_response_unmarshal_failed", fmt.Sprintf("Failed to start AI Agent (1): %s", err.Error()))
}

if outputMap.Status != 200 {
log.Printf("[ERROR][%s] AI Agent: Failed to run AI agent with status code %d", execution.ExecutionId, outputMap.Status)
// Don't log AI_AGENT_LLM_FAILURE here yet - wait to see if we can parse the error details below
//return startNode, errors.New(fmt.Sprintf("Failed to run AI agent with status code %d", outputMap.Status))
}

Expand All @@ -8194,20 +8158,14 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (

//choicesString = fmt.Sprintf("LLM Response Error: %s", string(resultMapping.Result))
choicesString = fmt.Sprintf("%s", string(resultMapping.Result))

// Log LLM failure for body parsing error
log.Printf("[ERROR][%s] AI_AGENT_LLM_FAILURE: org=%s status_code=%d error_type=body_parse_error raw_response=%s", execution.ExecutionId, execution.Workflow.OrgId, outputMap.Status, string(resultMapping.Result))
} else {
bodyString, err = json.Marshal(bodyMap)
if err != nil {
log.Printf("[ERROR] AI Agent: Failed marshalling body to string in AI Agent response: %s", err)

execution.Status = "ABORTED"
execution.Results = append(execution.Results, ActionResult{
Status: "ABORTED",
Result: fmt.Sprintf(`{"success": false, "reason": "Failed to start AI Agent (3): %s"}`, strings.Replace(err.Error(), `"`, `\"`, -1)),
Action: startNode,
})
go SetWorkflowExecution(ctx, execution, true)

return startNode, err
return abortAgentExecution(ctx, execution, startNode, AgentOutput{}, "llm_body_marshal_failed", fmt.Sprintf("Failed to start AI Agent (3): %s", err.Error()))
}
}

Expand All @@ -8230,12 +8188,18 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (
newOutput := openai.ErrorResponse{}
err = json.Unmarshal(bodyString, &newOutput)
if err == nil && len(newOutput.Error.Message) > 0 {
choicesString = fmt.Sprintf("LLM Error: %s", newOutput.Error.Message)
// choicesString = fmt.Sprintf("LLM Error: %s", newOutput.Error.Message)

resultMapping.Status = "FAILURE"
// resultMapping.Status = "FAILURE"
// LLM returned a proper error (401 invalid key, 429 rate limit, 500 server error, etc.)
log.Printf("[ERROR][%s] AI_AGENT_LLM_FAILURE: org=%s status_code=%d error_type=%s error_message=%s", execution.ExecutionId, execution.Workflow.OrgId, outputMap.Status, newOutput.Error.Type, newOutput.Error.Message)
return abortAgentExecution(ctx, execution, startNode, oldAgentOutput, "llm_http_error", fmt.Sprintf("LLM error (HTTP %d %s): %s", outputMap.Status, newOutput.Error.Type, newOutput.Error.Message))
} else {
log.Printf("[ERROR][%s] AI Agent: No choices, nor error found in AI agent response. Status: %d. Raw: %s", execution.ExecutionId, outputMap.Status, bodyString)
resultMapping.Status = "FAILURE"

// Log LLM failure for unknown error format
log.Printf("[ERROR][%s] AI_AGENT_LLM_FAILURE: org=%s status_code=%d error_type=unknown_format raw_response=%s", execution.ExecutionId, execution.Workflow.OrgId, outputMap.Status, string(bodyString))
}
} else {
choicesString = openaiOutput.Choices[0].Message.Content
Expand Down Expand Up @@ -8589,11 +8553,14 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (
question = mappedDecision.Fields[0].Value
}

// Escape single quotes to prevent quote injection
safeQuestion := strings.ReplaceAll(question, "'", "\\'")

err = CreateOrgNotification(
ctx,
fmt.Sprintf("Agent - input required: '%s'", question),
fmt.Sprintf("Input required during agent run."),
fmt.Sprintf("/forms/%s?authorization=%s&reference_execution=%s&source_node=%s&decision_id=%s&backend_url=%s", execution.WorkflowId, execution.Authorization, execution.ExecutionId, startNode.ID, mappedDecision.RunDetails.Id, backendUrl),
fmt.Sprintf("Agent - input required: '%s'", safeQuestion),
fmt.Sprintf("Input required during agent run."),
fmt.Sprintf("/forms/%s?authorization=%s&reference_execution=%s&source_node=%s&decision_id=%s&backend_url=%s", execution.WorkflowId, url.QueryEscape(execution.Authorization), execution.ExecutionId, startNode.ID, mappedDecision.RunDetails.Id, url.QueryEscape(backendUrl)),
execution.ExecutionOrg,
false,
"LOW",
Expand Down Expand Up @@ -8686,6 +8653,44 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (

if !decisionActionRan && !strings.Contains(decisionString, conditionText) {
log.Printf("[ERROR][%s] AI Agent: No decision action was run. Marking the agent as FAILURE.", execution.ExecutionId)

// Properly mark the agent as failed
agentOutput.Status = "FAILURE"
agentOutput.CompletedAt = time.Now().Unix()

sentFailure := false
// Update the result status - finds the existing node entry in execution.Results
for resultIndex, result := range execution.Results {
if result.Action.ID != startNode.ID {
continue
}

execution.Results[resultIndex].Status = "FAILURE"
execution.Results[resultIndex].CompletedAt = agentOutput.CompletedAt

marshalledAgentOutput, err := json.Marshal(agentOutput)
if err != nil {
log.Printf("[ERROR] AI Agent: Failed marshalling agent output for FAILURE: %s", err)
} else {
execution.Results[resultIndex].Result = string(marshalledAgentOutput)
resultMapping.Result = string(marshalledAgentOutput)
}

log.Printf("[DEBUG][%s] About to call sendAgentActionSelfRequest for FAILURE on agent action %s", execution.ExecutionId, startNode.ID)
go sendAgentActionSelfRequest("FAILURE", execution, execution.Results[resultIndex])
sentFailure = true
break
}

if !sentFailure {
log.Printf("[WARNING][%s] AI Agent: No result entry found in execution.Results, using resultMapping fallback", execution.ExecutionId)
fallbackOutput, merr := json.Marshal(agentOutput)
if merr == nil {
resultMapping.Status = "FAILURE"
resultMapping.Result = string(fallbackOutput)
}
go sendAgentActionSelfRequest("FAILURE", execution, resultMapping)
}
}

marshalledAgentOutput, err := json.Marshal(agentOutput)
Expand Down Expand Up @@ -8728,9 +8733,9 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (

//log.Printf("[INFO] AI_AGENT_FINISH: execution_id=%s status=%s duration=%ds decisions=%d", execution.ExecutionId, agentOutput.Status, time.Now().Unix()-agentOutput.StartedAt, len(agentOutput.Decisions))

if agentOutput.Status == "FINISHED" && agentOutput.CompletedAt > 0 && execution.Status == "EXECUTING" {
duration := agentOutput.CompletedAt - agentOutput.StartedAt
log.Printf("[INFO][%s] AI_AGENT_COMPLETE: org=%s duration=%ds decisions=%d llm_calls=%d total_tokens=%d status=SUCCESS", execution.ExecutionId, execution.Workflow.OrgId, duration, len(agentOutput.Decisions), agentOutput.LLMCallCount, agentOutput.TotalTokens)
if agentOutput.Status == "FINISHED" && agentOutput.CompletedAt > 0 && execution.Status != "ABORTED" && execution.Status != "FAILURE" {

foundResult := false
for resultIndex, result := range execution.Results {
if result.Action.ID != startNode.ID {
continue
Expand All @@ -8740,12 +8745,26 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (
execution.Results[resultIndex].CompletedAt = agentOutput.CompletedAt
log.Printf("[DEBUG][%s] About to call sendAgentActionSelfRequest for agent action %s", execution.ExecutionId, startNode.ID)
go sendAgentActionSelfRequest("SUCCESS", execution, execution.Results[resultIndex])
foundResult = true
break
}

if !foundResult {
// duration := int64(0)
// if agentOutput.StartedAt > 0 && agentOutput.CompletedAt > 0 {
// duration = agentOutput.CompletedAt - agentOutput.StartedAt
// } else if agentOutput.StartedAt > 0 {
// duration = time.Now().Unix() - agentOutput.StartedAt
// }

// log.Printf("[INFO] AI_AGENT_FINISH: execution_id=%s org=%s status=SUCCESS duration=%ds decisions=%d llm_calls=%d tokens_used=%d", execution.ExecutionId, execution.Workflow.OrgId, duration, len(agentOutput.Decisions), agentOutput.LLMCallCount, agentOutput.TotalTokens)
}
}

} else {
log.Printf("[ERROR] AI Agent: No result found in AI agent response. Status: %d. Body: %s", newresp.StatusCode, string(body))
// LLM returned an empty result body — this is a failure
log.Printf("[ERROR][%s] AI_AGENT_LLM_FAILURE: Empty result body from LLM response (status %d). Aborting agent.", execution.ExecutionId, newresp.StatusCode)
return abortAgentExecution(ctx, execution, startNode, oldAgentOutput, "empty_llm_result", fmt.Sprintf("LLM returned empty response body with HTTP status %d", newresp.StatusCode))
}

if memorizationEngine == "shuffle_db" {
Expand Down Expand Up @@ -8781,6 +8800,10 @@ You are the Action Execution Agent for the Shuffle platform. You receive tools (
}
}

if createNextActions {
return startNode, nil
}

// 1. Map the response back
newResult, err := json.Marshal(resultMapping)
if err != nil {
Expand Down Expand Up @@ -8962,7 +8985,6 @@ func GenerateSingulWorkflows(resp http.ResponseWriter, request *http.Request) {
return
}


// Maps everything AROUND the usecase
err = HandleSingulWorkflowEnablement(ctx, *workflow, user, categoryAction)
if err != nil {
Expand Down
Loading
Loading