Skip to content

Recursive Subagent Execution & Collapsible Tree Log UI & Codegen Documentation - #21

Open
Jacobcdsmith wants to merge 1 commit into
mainfrom
feature/recursive-subagent-execution-3153839162970473936
Open

Recursive Subagent Execution & Collapsible Tree Log UI & Codegen Documentation#21
Jacobcdsmith wants to merge 1 commit into
mainfrom
feature/recursive-subagent-execution-3153839162970473936

Conversation

@Jacobcdsmith

@Jacobcdsmith Jacobcdsmith commented Aug 8, 2026

Copy link
Copy Markdown
Owner

This contribution implements fully functional recursive Subagent (subagent) node execution, dynamic dropdown selection for graph configurations in Inspector.tsx, beautifully structured nested subLogs rendering with collapsible support, and self-documenting comments with node/edge counts in Python and JavaScript code generators. Comprehensive unit tests are also added to verify simulator, UI, and codegen capabilities.


PR created automatically by Jules for task 3153839162970473936 started by @Jacobcdsmith

Summary by CodeRabbit

  • New Features
    • Added support for running nested workflows through subagent nodes.
    • Added workflow selection for subagent configuration, excluding the currently active workflow.
    • Generated Python and JavaScript code now includes nested workflow details.
    • Execution logs now display nested subagent activity, state snapshots, and results with independent expansion controls.
  • Bug Fixes
    • Missing workflow references now report an error instead of producing simulated output.
  • Tests
    • Added coverage for nested execution, output propagation, code generation, and workflow selection.

…I inspector dropdown configuration, nested collapsible logs rendering, and codegen sub-workflow documentation. Also add comprehensive unit tests.
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI lite review requested due to automatic review settings August 8, 2026 14:55
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agent-flow-canvas Ready Ready Preview Aug 8, 2026 2:56pm

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Subagent nodes can select workflows, execute nested workflows, include nested workflow metadata in generated code, and display recursive execution logs. Workflow context now flows through inspectors, code generation, stepper execution, and full flow execution.

Changes

Recursive subagent workflows

Layer / File(s) Summary
Workflow context and selection
frontend/src/flow/Inspector.tsx, frontend/src/flow/runFlow.ts
Inspector props and execution options accept workflow data. Subagent graph fields list templates and saved workflows while excluding the active workflow.
Nested workflow execution
frontend/src/flow/runFlow.ts, frontend/src/test/subagentRecursion.test.tsx
Subagent nodes resolve workflows, construct initial state, execute nested flows, and return nested logs and output. Tests verify state and output propagation.
Workflow-aware code generation
frontend/src/flow/codegen.ts, frontend/src/test/subagentRecursion.test.tsx
Python and JavaScript generation accepts workflows and emits nested workflow metadata or not-found comments.
Execution wiring and recursive logs
frontend/src/pages/Index.tsx, frontend/src/test/subagentRecursion.test.tsx
Index passes workflow context through execution and generation paths. Recursive log rendering supports nested logs and state snapshots. Inspector tests verify workflow selection.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Inspector
  participant ParentFlow
  participant runFlow
  participant ChildWorkflow
  Inspector->>ParentFlow: select child workflow
  ParentFlow->>runFlow: execute subagent with workflow context
  runFlow->>ChildWorkflow: run nested workflow with initial state
  ChildWorkflow-->>runFlow: return logs and output
  runFlow-->>ParentFlow: return nested result
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary changes: recursive subagent execution, collapsible nested logs, and code generation documentation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/recursive-subagent-execution-3153839162970473936

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/flow/codegen.ts`:
- Line 364: Update both workflow lookup sites in frontend/src/flow/codegen.ts at
lines 364-364 and 585-585 to resolve an exact ID match before considering names,
then use a name match only when exactly one workflow has that name; do not
select arbitrarily among duplicate names.
- Line 368: The generated Python and JavaScript comments interpolate
Workflow.name without sanitization, allowing line terminators to escape the
comment. Add or reuse a name-sanitization step before inserting subWf.name at
frontend/src/flow/codegen.ts lines 368-368 and 589-589, applying identical
behavior in both generation paths.

In `@frontend/src/flow/runFlow.ts`:
- Around line 353-363: Update runFlow and its nested invocation to carry
execution ancestry and nesting depth, rejecting a workflow ID that already
appears in the ancestry with a descriptive error before starting the nested run.
Also enforce a maximum nesting depth as a fallback, while preserving normal
acyclic workflow execution and propagating the guarded context through the
existing allWfs-based recursion.
- Around line 365-379: The subflow result handling in runFlow must propagate
failures from the final nested log: before deriving finalResult or returning the
normal subagent result, check lastLog.error and throw it. Preserve the existing
result selection for successful nested flows so the parent flow can use its
error path when a nested flow fails or reaches the max-step guard.
- Around line 328-329: Replace the dynamic execution in the `runFlow` flow
around `new Function` and `fn(state)` so `cfg.input` is never evaluated as
JavaScript. Parse or interpolate the configured value using JSON input or an
existing restricted expression mechanism, preserving the expected state-derived
input behavior without exposing browser globals or arbitrary network and storage
APIs.

In `@frontend/src/pages/Index.tsx`:
- Around line 74-85: Update frontend/src/pages/Index.tsx lines 74-85 in
RunLogItem to accept a parent invocation path and include that path when
constructing uniqueKey, ensuring identical child workflows have distinct
expansion state; update frontend/src/pages/Index.tsx lines 1289-1307 to build
expand-all keys using the same invocation path so both key-generation paths
remain consistent.
- Line 868: Update the useCallback dependency arrays for stepForward,
resumeStepper, and runFlowAction to include workflows, so each execution
callback uses the current workflow collection. Apply this change at
frontend/src/pages/Index.tsx lines 868-868, 1068-1068, and 1225-1225.

In `@frontend/src/test/subagentRecursion.test.tsx`:
- Around line 159-189: The test around Inspector should include a workflow
object with ID "parent-wf-id" in the workflows prop so the active-workflow
filtering is exercised. Keep "child-researcher" available, then assert the
rendered option values contain "child-researcher" and exclude "parent-wf-id".
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8d4a08da-8714-47e8-bc0d-48ff6d8108d8

📥 Commits

Reviewing files that changed from the base of the PR and between 0b7a689 and c1c22e0.

⛔ Files ignored due to path filters (1)
  • server.log is excluded by !**/*.log
📒 Files selected for processing (5)
  • frontend/src/flow/Inspector.tsx
  • frontend/src/flow/codegen.ts
  • frontend/src/flow/runFlow.ts
  • frontend/src/pages/Index.tsx
  • frontend/src/test/subagentRecursion.test.tsx

case "subagent":
case "subagent": {
const subWfId = c.graph || "";
const subWf = workflows?.find((w) => w.id === subWfId || w.name === subWfId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use deterministic workflow resolution in both generators.

The current lookup can return an earlier name match instead of an exact ID match. Duplicate names can also select an arbitrary workflow.

  • frontend/src/flow/codegen.ts#L364-L364: resolve an exact ID first, then accept only a unique name match.
  • frontend/src/flow/codegen.ts#L585-L585: apply the same resolution order and duplicate-name handling.
📍 Affects 1 file
  • frontend/src/flow/codegen.ts#L364-L364 (this comment)
  • frontend/src/flow/codegen.ts#L585-L585
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/flow/codegen.ts` at line 364, Update both workflow lookup sites
in frontend/src/flow/codegen.ts at lines 364-364 and 585-585 to resolve an exact
ID match before considering names, then use a name match only when exactly one
workflow has that name; do not select arbitrarily among duplicate names.

const docComment = subWf
? [
`# Nested Subagent Workflow Details:`,
`# Name: ${subWf.name}`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Sanitize workflow names before emitting generated source comments.

Workflow.name is interpolated directly into Python and JavaScript line comments. A line terminator ends the comment, and the remaining text can become executable code inside the generated node function.

  • frontend/src/flow/codegen.ts#L368-L368: sanitize subWf.name before inserting it into the Python comment.
  • frontend/src/flow/codegen.ts#L589-L589: apply the same sanitization before inserting it into the JavaScript comment.
📍 Affects 1 file
  • frontend/src/flow/codegen.ts#L368-L368 (this comment)
  • frontend/src/flow/codegen.ts#L589-L589
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/flow/codegen.ts` at line 368, The generated Python and
JavaScript comments interpolate Workflow.name without sanitization, allowing
line terminators to escape the comment. Add or reuse a name-sanitization step
before inserting subWf.name at frontend/src/flow/codegen.ts lines 368-368 and
589-589, applying identical behavior in both generation paths.

Comment on lines +328 to +329
const fn = new Function("state", `return ${inputVal};`);
const evaluated = fn(state);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not execute cfg.input as JavaScript.

cfg.input is workflow configuration. Imported or edited workflow data can execute in the browser global scope through new Function. A malicious workflow can access browser storage and send data through network APIs.

Use interpolation, JSON input, or a restricted expression parser. Do not evaluate configuration as JavaScript.

🧰 Tools
🪛 OpenGrep (1.26.0)

[ERROR] 328-328: new Function() with dynamic input can execute arbitrary code. Avoid dynamic code evaluation entirely, or use a safe alternative.

(coderabbit.code-injection.new-function-js)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/flow/runFlow.ts` around lines 328 - 329, Replace the dynamic
execution in the `runFlow` flow around `new Function` and `fn(state)` so
`cfg.input` is never evaluated as JavaScript. Parse or interpolate the
configured value using JSON input or an existing restricted expression
mechanism, preserving the expected state-derived input behavior without exposing
browser globals or arbitrary network and storage APIs.

Source: Linters/SAST tools

Comment on lines +353 to +363
const subLogs = await runFlow({
nodes: subWf.nodes,
edges: subWf.edges,
gateways,
initialState: subState,
stepDelay: opts.stepDelay,
onHumanApproval: opts.onHumanApproval,
globals: globalsList,
secrets: secretsList,
workflows: allWfs,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Reject recursive workflow cycles before starting the nested run.

The nested call passes allWfs back into runFlow without an ancestry or depth guard. A self-reference, or a cycle such as A → B → A, creates unbounded nested execution. The per-flow maxSteps guard does not limit recursion across calls.

Track selected workflow IDs in the execution context. Throw a descriptive error when a workflow ID repeats. Add a maximum nesting depth as a fallback.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/flow/runFlow.ts` around lines 353 - 363, Update runFlow and its
nested invocation to carry execution ancestry and nesting depth, rejecting a
workflow ID that already appears in the ancestry with a descriptive error before
starting the nested run. Also enforce a maximum nesting depth as a fallback,
while preserving normal acyclic workflow execution and propagating the guarded
context through the existing allWfs-based recursion.

Comment on lines +365 to +379
const lastLog = subLogs[subLogs.length - 1];
let finalResult: unknown = undefined;
if (lastLog) {
if (lastLog.stateSnapshot && "last_output" in lastLog.stateSnapshot) {
finalResult = lastLog.stateSnapshot.last_output;
} else {
finalResult = lastLog.output;
}
}

return {
simulated: true,
subagent: cfg.graph || "unknown",
input: interpolate(cfg.input || "", state, globalsList, secretsList),
note: "subagent execution is schematic",
workflowId: subWf.id,
workflowName: subWf.name,
subLogs,
result: finalResult,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Propagate an unhandled nested-flow error to the parent flow.

runFlow records failures in RunLog.error. This code ignores lastLog.error and returns a normal subagent result. The parent flow then follows its success path even when the nested flow stopped on an error or the max-step guard.

If the final nested log has error, throw it from the subagent node so that the parent can select its error edge.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/flow/runFlow.ts` around lines 365 - 379, The subflow result
handling in runFlow must propagate failures from the final nested log: before
deriving finalResult or returning the normal subagent result, check
lastLog.error and throw it. Preserve the existing result selection for
successful nested flows so the parent flow can use its error path when a nested
flow fails or reaches the max-step guard.

Comment on lines +74 to +85
const uniqueKey = `${log.step}-${log.nodeId}-${depth}`;
const isExpanded = !!expandedLogSnapshots[uniqueKey];

const hasSubLogs = log.kind === "subagent" &&
log.output &&
typeof log.output === "object" &&
"subLogs" in (log.output as any) &&
Array.isArray((log.output as any).subLogs);

const subLogs: RunLog[] = hasSubLogs ? (log.output as any).subLogs : [];
const subLogsKey = `${uniqueKey}-sublogs`;
const isSubLogsExpanded = expandedLogSnapshots[subLogsKey] !== false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use an invocation path for log expansion keys.

Two invocations of the same child workflow at the same depth produce identical expansion keys. Expanding one nested snapshot or nested execution section also expands the other.

  • frontend/src/pages/Index.tsx#L74-L85: Pass a parent invocation path into RunLogItem and include it in uniqueKey.
  • frontend/src/pages/Index.tsx#L1289-L1307: Build expand-all keys from the same invocation path.
📍 Affects 1 file
  • frontend/src/pages/Index.tsx#L74-L85 (this comment)
  • frontend/src/pages/Index.tsx#L1289-L1307
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/Index.tsx` around lines 74 - 85, Update
frontend/src/pages/Index.tsx lines 74-85 in RunLogItem to accept a parent
invocation path and include that path when constructing uniqueKey, ensuring
identical child workflows have distinct expansion state; update
frontend/src/pages/Index.tsx lines 1289-1307 to build expand-all keys using the
same invocation path so both key-generation paths remain consistent.

edges,
gateways,
onHumanApproval: approvalPromise,
workflows: [...TEMPLATES, ...workflows],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Include workflows in each execution callback dependency array.

stepForward, resumeStepper, and runFlowAction capture workflows, but their useCallback dependency arrays omit it. If a custom nested workflow changes while the current canvas nodes do not change, these paths use a stale workflow collection.

  • frontend/src/pages/Index.tsx#L868-L868: Add workflows to stepForward dependencies.
  • frontend/src/pages/Index.tsx#L1068-L1068: Add workflows to resumeStepper dependencies.
  • frontend/src/pages/Index.tsx#L1225-L1225: Add workflows to runFlowAction dependencies.
📍 Affects 1 file
  • frontend/src/pages/Index.tsx#L868-L868 (this comment)
  • frontend/src/pages/Index.tsx#L1068-L1068
  • frontend/src/pages/Index.tsx#L1225-L1225
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/Index.tsx` at line 868, Update the useCallback dependency
arrays for stepForward, resumeStepper, and runFlowAction to include workflows,
so each execution callback uses the current workflow collection. Apply this
change at frontend/src/pages/Index.tsx lines 868-868, 1068-1068, and 1225-1225.

Comment on lines +159 to +189
it("should render dropdown menu with other workflows in Inspector UI, excluding active", () => {
const activeWorkflowId = "parent-wf-id";
const changeMock = () => {};
const deleteMock = () => {};

const nodeUnderTest: Node<AgentNodeData> = parentNodes.find((n) => n.id === "p2")!;

const { container } = render(
<ReactFlowProvider>
<Inspector
node={nodeUnderTest}
edges={parentEdges}
nodes={parentNodes}
activeWorkflowId={activeWorkflowId}
workflows={[subWf]}
onChange={changeMock}
onDelete={deleteMock}
/>
</ReactFlowProvider>
);

// Verify dropdown is rendered for graph selection
const selectElem = container.querySelector("select");
expect(selectElem).not.toBeNull();

// It should have options: child-researcher, and exclude the parent active graph
const options = container.querySelectorAll("option");
const optionValues = Array.from(options).map((o) => o.value);
expect(optionValues).toContain("child-researcher");
expect(optionValues).not.toContain("parent-wf-id");
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the active-workflow exclusion assertion effective.

"parent-wf-id" is not present in workflows or in the template list. The assertion passes even if the Inspector does not filter the active workflow.

Add a workflow with ID "parent-wf-id" to workflows. Then assert that this option is absent and that "child-researcher" is present.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/test/subagentRecursion.test.tsx` around lines 159 - 189, The
test around Inspector should include a workflow object with ID "parent-wf-id" in
the workflows prop so the active-workflow filtering is exercised. Keep
"child-researcher" available, then assert the rendered option values contain
"child-researcher" and exclude "parent-wf-id".

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the agent-flow canvas to support recursive execution of subagent nodes, improves the UI for selecting subagent workflows and viewing nested execution logs, and enriches generated Python/JavaScript output with self-documenting subagent workflow details. It also adds unit tests covering subagent recursion, UI dropdown behavior, and codegen annotations.

Changes:

  • Implement recursive subagent execution in the simulator (runFlow) and propagate nested sub-logs/results.
  • Add collapsible nested sub-log rendering in the run log UI and add workflow selection dropdown behavior in Inspector.
  • Add codegen comments for nested subagent workflow metadata and add a new test suite covering recursion/UI/codegen.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
server.log Updates a dev-server output log (appears to be an accidental/ephemeral artifact).
frontend/src/test/subagentRecursion.test.tsx Adds tests for subagent recursion, Inspector workflow dropdown, and codegen comments.
frontend/src/pages/Index.tsx Adds recursive/collapsible nested run-log rendering and threads workflow lists into codegen/runFlow/Inspector.
frontend/src/flow/runFlow.ts Implements actual subagent execution via recursive runFlow and adds workflows to options.
frontend/src/flow/Inspector.tsx Adds workflow dropdown selection for subagent nodes (excluding active workflow).
frontend/src/flow/codegen.ts Adds optional workflow metadata to codegen for self-documenting nested subagent comments.
Suppressed comments (5)

frontend/src/pages/Index.tsx:156

  • After adding a path-based uniqueKey, recursive RunLogItem calls need to pass a child path; otherwise nested expansion state will still collide and the component will be missing required props.
              {subLogs.map((sl) => (
                <RunLogItem
                  key={`${sl.step}-${sl.nodeId}`}
                  log={sl}
                  expandedLogSnapshots={expandedLogSnapshots}

frontend/src/pages/Index.tsx:1293

  • handleLogsExpandAll builds keys using step/nodeId/depth, which will no longer match path-based keys (and also collides across multiple subagent runs). It should generate the same hierarchical path keys as RunLogItem.
    const recurseExpand = (logsList: RunLog[], d = 0) => {
      logsList.forEach((l) => {
        const uniqueKey = `${l.step}-${l.nodeId}-${d}`;
        if (l.stateSnapshot) {
          patch[uniqueKey] = true;

frontend/src/pages/Index.tsx:2109

  • Top-level RunLogItem calls also need to provide a stable path (e.g., list index) so expansion keys are unique per log entry and don’t collide across similar step/node IDs.
            {filteredLogs.map((l) => (
              <RunLogItem
                key={`${l.step}-${l.nodeId}`}
                log={l}
                expandedLogSnapshots={expandedLogSnapshots}

frontend/src/flow/runFlow.ts:357

  • The recursive runFlow call should propagate the call-stack/depth guard options so nested subagent calls are also protected.
      const subLogs = await runFlow({
        nodes: subWf.nodes,
        edges: subWf.edges,
        gateways,
        initialState: subState,

frontend/src/flow/runFlow.ts:320

  • Subagent execution can recurse indefinitely if a workflow references itself (directly or indirectly). Inspector filters the active workflow in the UI, but configs can still be set manually or cycles can occur across multiple workflows. A call-stack / max-depth guard avoids runaway recursion and makes failures clearer.
      const subWfId = cfg.graph || "";
      const allWfs = opts.workflows ?? [...TEMPLATES, ...loadWorkflows()];
      const subWf = allWfs.find((w) => w.id === subWfId || w.name === subWfId);
      if (!subWf) {
        throw new Error(`Subagent workflow with ID or Name "${subWfId}" not found`);

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +66 to +85
interface RunLogItemProps {
log: RunLog;
expandedLogSnapshots: Record<string, boolean>;
setExpandedLogSnapshots: React.Dispatch<React.SetStateAction<Record<string, boolean>>>;
depth?: number;
}

function RunLogItem({ log, expandedLogSnapshots, setExpandedLogSnapshots, depth = 0 }: RunLogItemProps) {
const uniqueKey = `${log.step}-${log.nodeId}-${depth}`;
const isExpanded = !!expandedLogSnapshots[uniqueKey];

const hasSubLogs = log.kind === "subagent" &&
log.output &&
typeof log.output === "object" &&
"subLogs" in (log.output as any) &&
Array.isArray((log.output as any).subLogs);

const subLogs: RunLog[] = hasSubLogs ? (log.output as any).subLogs : [];
const subLogsKey = `${uniqueKey}-sublogs`;
const isSubLogsExpanded = expandedLogSnapshots[subLogsKey] !== false;
Comment on lines +327 to +329
// Evaluate as JS expression against current parent state
const fn = new Function("state", `return ${inputVal};`);
const evaluated = fn(state);
Comment on lines 35 to 38
globals?: { key: string; value: string }[];
secrets?: { key: string; value: string }[];
workflows?: Workflow[];
}
import { Edge, Node } from "reactflow";
import { AgentNodeData, NODE_TYPES } from "./types";
import type { Gateway } from "./gateways";
import { TEMPLATES, Workflow } from "./workflows";
import { Edge, Node } from "reactflow";
import { AgentNodeData, AgentNodeKind } from "./types";
import { GlobalVar, SecretVar } from "./globals";
import { Workflow } from "./workflows";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants