mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-26 12:53:59 +02:00
feat: show sub-workflow agents and lifecycle in the Activity panel
Deep agent resolution in the sidecar now walks sub-workflow nodes so nested agents carry subworkflowNodeId and subworkflowName on activity events. New subworkflow-started / subworkflow-completed activity types let the frontend track sub-workflow lifecycle. The Activity panel groups nested agents under collapsible sub-workflow cards with status badges, accent-colored left borders, and smooth expand/collapse transitions. Cards auto-expand when a sub-workflow starts running. Workflows without sub-workflow nodes render identically to before. Extracted AgentRow, SubWorkflowGroup, and shared accent constants to a new components/activity/ feature directory. Added resolveWorkflowAgentHierarchy and buildGroupedActivityRows for hierarchical activity grouping with dynamic fallback for unresolved sub-workflow agents. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -115,19 +115,86 @@ public sealed class AgentIdentityResolverTests
|
||||
Assert.Equal("UX Specialist", agent.AgentName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryResolveKnownAgentIdentity_ResolvesReferencedSubworkflowAgentWithContext()
|
||||
{
|
||||
WorkflowDefinitionDto nestedWorkflow = CreateWorkflow(
|
||||
"nested-review-workflow",
|
||||
[
|
||||
CreateAgent("agent-reviewer", "Reviewer"),
|
||||
],
|
||||
orchestrationMode: "single");
|
||||
WorkflowDefinitionDto workflow = CreateWorkflow(
|
||||
"parent-workflow",
|
||||
[
|
||||
CreateSubworkflow("subworkflow-review", "Review Lane", workflowId: nestedWorkflow.Id),
|
||||
],
|
||||
orchestrationMode: "single");
|
||||
|
||||
bool resolved = AgentIdentityResolver.TryResolveKnownAgentIdentity(
|
||||
workflow,
|
||||
[nestedWorkflow],
|
||||
"Reviewer_agent_reviewer",
|
||||
out AgentIdentity agent);
|
||||
|
||||
Assert.True(resolved);
|
||||
Assert.Equal("agent-reviewer", agent.AgentId);
|
||||
Assert.Equal("Reviewer", agent.AgentName);
|
||||
Assert.Equal("subworkflow-review", agent.Subworkflow?.SubworkflowNodeId);
|
||||
Assert.Equal("Review Lane", agent.Subworkflow?.SubworkflowName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildAgentSubworkflowIndex_UsesImmediateNestedSubworkflowContext()
|
||||
{
|
||||
WorkflowDefinitionDto innerWorkflow = CreateWorkflow(
|
||||
"inner-workflow",
|
||||
[
|
||||
CreateAgent("agent-inner-reviewer", "Inner Reviewer"),
|
||||
],
|
||||
orchestrationMode: "single");
|
||||
WorkflowDefinitionDto outerWorkflow = CreateWorkflow(
|
||||
"outer-workflow",
|
||||
[
|
||||
CreateSubworkflow("subworkflow-inner", "Inner Review", inlineWorkflow: innerWorkflow),
|
||||
],
|
||||
orchestrationMode: "single");
|
||||
WorkflowDefinitionDto workflow = CreateWorkflow(
|
||||
"parent-workflow",
|
||||
[
|
||||
CreateSubworkflow("subworkflow-outer", "Outer Review", inlineWorkflow: outerWorkflow),
|
||||
],
|
||||
orchestrationMode: "single");
|
||||
|
||||
IReadOnlyDictionary<string, SubworkflowContext> index =
|
||||
AgentIdentityResolver.BuildAgentSubworkflowIndex(workflow);
|
||||
|
||||
Assert.True(index.TryGetValue("agent-inner-reviewer", out SubworkflowContext subworkflow));
|
||||
Assert.Equal("subworkflow-inner", subworkflow.SubworkflowNodeId);
|
||||
Assert.Equal("Inner Review", subworkflow.SubworkflowName);
|
||||
}
|
||||
|
||||
private static WorkflowDefinitionDto CreateWorkflow(
|
||||
IReadOnlyList<WorkflowNodeDto> agents,
|
||||
IReadOnlyList<WorkflowNodeDto> nodes,
|
||||
string orchestrationMode = "concurrent")
|
||||
{
|
||||
return CreateWorkflow($"{orchestrationMode}-workflow", nodes, orchestrationMode);
|
||||
}
|
||||
|
||||
private static WorkflowDefinitionDto CreateWorkflow(
|
||||
string id,
|
||||
IReadOnlyList<WorkflowNodeDto> nodes,
|
||||
string orchestrationMode = "concurrent")
|
||||
{
|
||||
return new WorkflowDefinitionDto
|
||||
{
|
||||
Id = $"{orchestrationMode}-workflow",
|
||||
Id = id,
|
||||
Name = "Workflow",
|
||||
Graph = new WorkflowGraphDto
|
||||
{
|
||||
Nodes =
|
||||
[
|
||||
.. agents,
|
||||
.. nodes,
|
||||
],
|
||||
},
|
||||
Settings = new WorkflowSettingsDto
|
||||
@@ -154,4 +221,24 @@ public sealed class AgentIdentityResolverTests
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static WorkflowNodeDto CreateSubworkflow(
|
||||
string id,
|
||||
string label,
|
||||
string? workflowId = null,
|
||||
WorkflowDefinitionDto? inlineWorkflow = null)
|
||||
{
|
||||
return new WorkflowNodeDto
|
||||
{
|
||||
Id = id,
|
||||
Kind = "sub-workflow",
|
||||
Label = label,
|
||||
Config = new WorkflowNodeConfigDto
|
||||
{
|
||||
Kind = "sub-workflow",
|
||||
WorkflowId = workflowId,
|
||||
InlineWorkflow = inlineWorkflow,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,40 @@ public sealed class CopilotTurnExecutionStateTests
|
||||
Assert.Equal("agent-1", observedAgent.AgentId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObserveSessionEvent_AssistantMessageDelta_ForNestedAgent_IncludesSubworkflowContext()
|
||||
{
|
||||
RunTurnCommandDto command = CreateCommandWithReferencedSubworkflow();
|
||||
CopilotTurnExecutionState state = new(command);
|
||||
WorkflowDefinitionDto nestedWorkflow = Assert.Single(command.WorkflowLibrary!);
|
||||
WorkflowNodeDto nestedAgent = Assert.Single(nestedWorkflow.GetAgentNodes());
|
||||
|
||||
state.ObserveSessionEvent(
|
||||
nestedAgent,
|
||||
SessionEvent.FromJson(
|
||||
"""
|
||||
{
|
||||
"type": "assistant.message_delta",
|
||||
"data": {
|
||||
"messageId": "msg-nested-1",
|
||||
"deltaContent": "Reviewing"
|
||||
},
|
||||
"id": "7ef95d90-7ee7-45e2-ac38-cf749caf4f69",
|
||||
"timestamp": "2026-03-27T00:00:00Z"
|
||||
}
|
||||
"""));
|
||||
|
||||
AgentActivityEventDto activity = Assert.Single(state.DrainPendingEvents().OfType<AgentActivityEventDto>());
|
||||
Assert.Equal("thinking", activity.ActivityType);
|
||||
Assert.Equal("agent-reviewer", activity.AgentId);
|
||||
Assert.Equal("Reviewer", activity.AgentName);
|
||||
Assert.Equal("subworkflow-review", activity.SubworkflowNodeId);
|
||||
Assert.Equal("Review Lane", activity.SubworkflowName);
|
||||
Assert.True(state.ActiveAgent.HasValue);
|
||||
Assert.Equal("subworkflow-review", state.ActiveAgent.Value.Subworkflow?.SubworkflowNodeId);
|
||||
Assert.Equal("Review Lane", state.ActiveAgent.Value.Subworkflow?.SubworkflowName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObserveSessionEvent_ToolExecutionStart_TracksToolNameByCallIdAndQueuesToolActivity()
|
||||
{
|
||||
@@ -746,5 +780,79 @@ public sealed class CopilotTurnExecutionStateTests
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static RunTurnCommandDto CreateCommandWithReferencedSubworkflow()
|
||||
{
|
||||
WorkflowDefinitionDto nestedWorkflow = CreateWorkflow(
|
||||
"nested-review-workflow",
|
||||
[
|
||||
CreateAgent("agent-reviewer", "Reviewer"),
|
||||
]);
|
||||
|
||||
return new RunTurnCommandDto
|
||||
{
|
||||
RequestId = "turn-1",
|
||||
SessionId = "session-1",
|
||||
WorkflowLibrary = [nestedWorkflow],
|
||||
Workflow = CreateWorkflow(
|
||||
"workflow-parent",
|
||||
[
|
||||
CreateSubworkflow("subworkflow-review", "Review Lane", workflowId: nestedWorkflow.Id),
|
||||
]),
|
||||
};
|
||||
}
|
||||
|
||||
private static WorkflowDefinitionDto CreateWorkflow(string id, IReadOnlyList<WorkflowNodeDto> nodes)
|
||||
{
|
||||
return new WorkflowDefinitionDto
|
||||
{
|
||||
Id = id,
|
||||
Name = "Execution State Workflow",
|
||||
Graph = new WorkflowGraphDto
|
||||
{
|
||||
Nodes = [.. nodes],
|
||||
},
|
||||
Settings = new WorkflowSettingsDto
|
||||
{
|
||||
OrchestrationMode = "single",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static WorkflowNodeDto CreateAgent(string id, string name)
|
||||
{
|
||||
return new WorkflowNodeDto
|
||||
{
|
||||
Id = id,
|
||||
Kind = "agent",
|
||||
Label = name,
|
||||
Config = new WorkflowNodeConfigDto
|
||||
{
|
||||
Kind = "agent",
|
||||
Id = id,
|
||||
Name = name,
|
||||
Model = "gpt-5.4",
|
||||
Instructions = "Help with the request.",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static WorkflowNodeDto CreateSubworkflow(
|
||||
string id,
|
||||
string label,
|
||||
string? workflowId = null)
|
||||
{
|
||||
return new WorkflowNodeDto
|
||||
{
|
||||
Id = id,
|
||||
Kind = "sub-workflow",
|
||||
Label = label,
|
||||
Config = new WorkflowNodeConfigDto
|
||||
{
|
||||
Kind = "sub-workflow",
|
||||
WorkflowId = workflowId,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1052,6 +1052,78 @@ public sealed class CopilotWorkflowRunnerTests
|
||||
Assert.Equal("Primary", completed.AgentName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleWorkflowEventAsync_EmitsSubworkflowStartedActivityForSubworkflowExecutor()
|
||||
{
|
||||
RunTurnCommandDto command = CreateReferencedSubworkflowCommand();
|
||||
CopilotTurnExecutionState state = new(command);
|
||||
List<AgentActivityEventDto> activities = [];
|
||||
|
||||
MethodInfo handleWorkflowEvent = typeof(CopilotWorkflowRunner).GetMethod(
|
||||
"HandleWorkflowEventAsync",
|
||||
BindingFlags.NonPublic | BindingFlags.Static)!;
|
||||
Task<bool> handleTask = (Task<bool>)handleWorkflowEvent.Invoke(
|
||||
null,
|
||||
[
|
||||
command,
|
||||
new ExecutorInvokedEvent("subworkflow-review", null!),
|
||||
Array.Empty<ChatMessage>(),
|
||||
state,
|
||||
(Func<TurnDeltaEventDto, Task>)(_ => Task.CompletedTask),
|
||||
(Func<SidecarEventDto, Task>)(sidecarEvent =>
|
||||
{
|
||||
activities.Add(Assert.IsType<AgentActivityEventDto>(sidecarEvent));
|
||||
return Task.CompletedTask;
|
||||
}),
|
||||
])!;
|
||||
|
||||
bool shouldEndTurn = await handleTask;
|
||||
|
||||
Assert.False(shouldEndTurn);
|
||||
AgentActivityEventDto activity = Assert.Single(activities);
|
||||
Assert.Equal("subworkflow-started", activity.ActivityType);
|
||||
Assert.Null(activity.AgentId);
|
||||
Assert.Null(activity.AgentName);
|
||||
Assert.Equal("subworkflow-review", activity.SubworkflowNodeId);
|
||||
Assert.Equal("Review Lane", activity.SubworkflowName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleWorkflowEventAsync_EmitsSubworkflowCompletedActivityForSubworkflowExecutor()
|
||||
{
|
||||
RunTurnCommandDto command = CreateReferencedSubworkflowCommand();
|
||||
CopilotTurnExecutionState state = new(command);
|
||||
List<AgentActivityEventDto> activities = [];
|
||||
|
||||
MethodInfo handleWorkflowEvent = typeof(CopilotWorkflowRunner).GetMethod(
|
||||
"HandleWorkflowEventAsync",
|
||||
BindingFlags.NonPublic | BindingFlags.Static)!;
|
||||
Task<bool> handleTask = (Task<bool>)handleWorkflowEvent.Invoke(
|
||||
null,
|
||||
[
|
||||
command,
|
||||
new ExecutorCompletedEvent("subworkflow-review", null),
|
||||
Array.Empty<ChatMessage>(),
|
||||
state,
|
||||
(Func<TurnDeltaEventDto, Task>)(_ => Task.CompletedTask),
|
||||
(Func<SidecarEventDto, Task>)(sidecarEvent =>
|
||||
{
|
||||
activities.Add(Assert.IsType<AgentActivityEventDto>(sidecarEvent));
|
||||
return Task.CompletedTask;
|
||||
}),
|
||||
])!;
|
||||
|
||||
bool shouldEndTurn = await handleTask;
|
||||
|
||||
Assert.False(shouldEndTurn);
|
||||
AgentActivityEventDto activity = Assert.Single(activities);
|
||||
Assert.Equal("subworkflow-completed", activity.ActivityType);
|
||||
Assert.Null(activity.AgentId);
|
||||
Assert.Null(activity.AgentName);
|
||||
Assert.Equal("subworkflow-review", activity.SubworkflowNodeId);
|
||||
Assert.Equal("Review Lane", activity.SubworkflowName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleWorkflowEventAsync_EmitsWorkflowWarningDiagnostic()
|
||||
{
|
||||
@@ -2243,11 +2315,37 @@ public sealed class CopilotWorkflowRunnerTests
|
||||
};
|
||||
}
|
||||
|
||||
private static WorkflowNodeDto CreateSubworkflow(
|
||||
string id,
|
||||
string label,
|
||||
string? workflowId = null,
|
||||
WorkflowDefinitionDto? inlineWorkflow = null)
|
||||
{
|
||||
return new WorkflowNodeDto
|
||||
{
|
||||
Id = id,
|
||||
Kind = "sub-workflow",
|
||||
Label = label,
|
||||
Config = new WorkflowNodeConfigDto
|
||||
{
|
||||
Kind = "sub-workflow",
|
||||
WorkflowId = workflowId,
|
||||
InlineWorkflow = inlineWorkflow,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static RunTurnCommandDto CreateCommand(
|
||||
string orchestrationMode,
|
||||
params WorkflowNodeDto[] agents)
|
||||
{
|
||||
return CreateCommand(orchestrationMode, modeSettings: null, workflowName: null, workflowDescription: null, agents);
|
||||
return CreateCommand(
|
||||
orchestrationMode,
|
||||
modeSettings: null,
|
||||
workflowName: null,
|
||||
workflowDescription: null,
|
||||
workflowLibrary: null,
|
||||
agents: agents);
|
||||
}
|
||||
|
||||
private static RunTurnCommandDto CreateCommand(
|
||||
@@ -2255,12 +2353,14 @@ public sealed class CopilotWorkflowRunnerTests
|
||||
OrchestrationModeSettingsDto? modeSettings = null,
|
||||
string? workflowName = null,
|
||||
string? workflowDescription = null,
|
||||
IReadOnlyList<WorkflowDefinitionDto>? workflowLibrary = null,
|
||||
params WorkflowNodeDto[] agents)
|
||||
{
|
||||
return new RunTurnCommandDto
|
||||
{
|
||||
RequestId = "turn-1",
|
||||
SessionId = "session-1",
|
||||
WorkflowLibrary = workflowLibrary ?? [],
|
||||
Workflow = new WorkflowDefinitionDto
|
||||
{
|
||||
Id = $"workflow-{orchestrationMode}",
|
||||
@@ -2336,6 +2436,35 @@ public sealed class CopilotWorkflowRunnerTests
|
||||
};
|
||||
}
|
||||
|
||||
private static RunTurnCommandDto CreateReferencedSubworkflowCommand()
|
||||
{
|
||||
WorkflowDefinitionDto nestedWorkflow = new()
|
||||
{
|
||||
Id = "nested-review-workflow",
|
||||
Name = "Nested Review Workflow",
|
||||
Graph = new WorkflowGraphDto
|
||||
{
|
||||
Nodes =
|
||||
[
|
||||
CreateAgent("agent-reviewer", "Reviewer"),
|
||||
],
|
||||
},
|
||||
Settings = new WorkflowSettingsDto
|
||||
{
|
||||
OrchestrationMode = "single",
|
||||
},
|
||||
};
|
||||
|
||||
return CreateCommand(
|
||||
"single",
|
||||
workflowName: "Parent Workflow",
|
||||
workflowLibrary: [nestedWorkflow],
|
||||
agents:
|
||||
[
|
||||
CreateSubworkflow("subworkflow-review", "Review Lane", workflowId: nestedWorkflow.Id),
|
||||
]);
|
||||
}
|
||||
|
||||
private static RunTurnCommandDto CreateHandoffCommand()
|
||||
{
|
||||
return CreateCommand(
|
||||
|
||||
@@ -246,6 +246,54 @@ public sealed class WorkflowRequestInfoInterpreterTests
|
||||
Assert.Empty(tracking.ToolCallHasArgumentsById);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryCreateActivityFromRequest_IncludesSubworkflowContextForToolCallingAgent()
|
||||
{
|
||||
var tracking = CreateToolTracking();
|
||||
RequestInfoEvent requestInfo = CreateRequestInfoEvent(
|
||||
new FunctionCallContent("call-1", "view", new Dictionary<string, object?>
|
||||
{
|
||||
["path"] = @"C:\workspace\file.txt",
|
||||
}));
|
||||
|
||||
AgentActivityEventDto? activity = WorkflowRequestInfoInterpreter.TryCreateActivityFromRequest(
|
||||
CreateSingleAgentCommand(),
|
||||
requestInfo,
|
||||
new AgentIdentity(
|
||||
"agent-reviewer",
|
||||
"Reviewer",
|
||||
new SubworkflowContext("subworkflow-review", "Review Lane")),
|
||||
tracking.ToolNamesByCallId,
|
||||
tracking.ToolCallHasArgumentsById);
|
||||
|
||||
Assert.NotNull(activity);
|
||||
Assert.Equal("tool-calling", activity.ActivityType);
|
||||
Assert.Equal("subworkflow-review", activity.SubworkflowNodeId);
|
||||
Assert.Equal("Review Lane", activity.SubworkflowName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryCreateActivityFromRequest_ResolvesReferencedSubworkflowContextForHandoffTargets()
|
||||
{
|
||||
var tracking = CreateToolTracking();
|
||||
RequestInfoEvent requestInfo = CreateRequestInfoEvent(
|
||||
CreateHandoffTarget("agent-handoff-ux", "UX Specialist"));
|
||||
|
||||
AgentActivityEventDto? activity = WorkflowRequestInfoInterpreter.TryCreateActivityFromRequest(
|
||||
CreateHandoffCommandWithReferencedSubworkflow(),
|
||||
requestInfo,
|
||||
new AgentIdentity("agent-handoff-triage", "Triage"),
|
||||
tracking.ToolNamesByCallId,
|
||||
tracking.ToolCallHasArgumentsById);
|
||||
|
||||
Assert.NotNull(activity);
|
||||
Assert.Equal("handoff", activity.ActivityType);
|
||||
Assert.Equal("agent-handoff-ux", activity.AgentId);
|
||||
Assert.Equal("UX Specialist", activity.AgentName);
|
||||
Assert.Equal("subworkflow-review", activity.SubworkflowNodeId);
|
||||
Assert.Equal("Review Lane", activity.SubworkflowName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RequiresUserInputTurnBoundary_ReturnsTrueForUnhandledHandoffRequests()
|
||||
{
|
||||
@@ -341,24 +389,56 @@ public sealed class WorkflowRequestInfoInterpreterTests
|
||||
CreateAgent("agent-handoff-ux", "UX Specialist"),
|
||||
]);
|
||||
|
||||
private static RunTurnCommandDto CreateHandoffCommandWithReferencedSubworkflow()
|
||||
{
|
||||
WorkflowDefinitionDto nestedWorkflow = new()
|
||||
{
|
||||
Id = "nested-review-workflow",
|
||||
Name = "Nested Review Workflow",
|
||||
Graph = new WorkflowGraphDto
|
||||
{
|
||||
Nodes =
|
||||
[
|
||||
CreateAgent("agent-handoff-ux", "UX Specialist"),
|
||||
],
|
||||
},
|
||||
Settings = new WorkflowSettingsDto
|
||||
{
|
||||
OrchestrationMode = "single",
|
||||
},
|
||||
};
|
||||
|
||||
return CreateCommand(
|
||||
"handoff",
|
||||
[
|
||||
CreateAgent("agent-handoff-triage", "Triage"),
|
||||
CreateSubworkflow("subworkflow-review", "Review Lane", workflowId: nestedWorkflow.Id),
|
||||
],
|
||||
workflowLibrary: [nestedWorkflow]);
|
||||
}
|
||||
|
||||
private static (
|
||||
ConcurrentDictionary<string, string> ToolNamesByCallId,
|
||||
ConcurrentDictionary<string, bool> ToolCallHasArgumentsById) CreateToolTracking()
|
||||
=> (new(StringComparer.Ordinal), new(StringComparer.Ordinal));
|
||||
|
||||
private static RunTurnCommandDto CreateCommand(string orchestrationMode, IReadOnlyList<WorkflowNodeDto> agents)
|
||||
private static RunTurnCommandDto CreateCommand(
|
||||
string orchestrationMode,
|
||||
IReadOnlyList<WorkflowNodeDto> nodes,
|
||||
IReadOnlyList<WorkflowDefinitionDto>? workflowLibrary = null)
|
||||
{
|
||||
return new RunTurnCommandDto
|
||||
{
|
||||
RequestId = "turn-1",
|
||||
SessionId = "session-1",
|
||||
WorkflowLibrary = workflowLibrary ?? [],
|
||||
Workflow = new WorkflowDefinitionDto
|
||||
{
|
||||
Id = $"{orchestrationMode}-workflow",
|
||||
Name = "Workflow",
|
||||
Graph = new WorkflowGraphDto
|
||||
{
|
||||
Nodes = [.. agents],
|
||||
Nodes = [.. nodes],
|
||||
},
|
||||
Settings = new WorkflowSettingsDto
|
||||
{
|
||||
@@ -386,6 +466,26 @@ public sealed class WorkflowRequestInfoInterpreterTests
|
||||
};
|
||||
}
|
||||
|
||||
private static WorkflowNodeDto CreateSubworkflow(
|
||||
string id,
|
||||
string label,
|
||||
string? workflowId = null,
|
||||
WorkflowDefinitionDto? inlineWorkflow = null)
|
||||
{
|
||||
return new WorkflowNodeDto
|
||||
{
|
||||
Id = id,
|
||||
Kind = "sub-workflow",
|
||||
Label = label,
|
||||
Config = new WorkflowNodeConfigDto
|
||||
{
|
||||
Kind = "sub-workflow",
|
||||
WorkflowId = workflowId,
|
||||
InlineWorkflow = inlineWorkflow,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static RequestInfoEvent CreateRequestInfoEvent(object payload)
|
||||
{
|
||||
RequestPort port = RequestPort.Create<object, object>("test-port");
|
||||
|
||||
Reference in New Issue
Block a user