Skip to content

Implement structured node inputs and outputs with variable interpolation - #3

Merged
quickerup merged 1 commit into
mainfrom
feature/structured-node-inputs-outputs-10442992188653594916
Jul 14, 2026
Merged

Implement structured node inputs and outputs with variable interpolation#3
quickerup merged 1 commit into
mainfrom
feature/structured-node-inputs-outputs-10442992188653594916

Conversation

@quickerup

@quickerup quickerup commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Define structured inputs and outputs fields on nodes to enable data-passing and dynamic interpolation (such as referencing previous step's output values using n8n-style variables) within DAG graph-based workflows.


PR created automatically by Jules for task 10442992188653594916 started by @aethelred-agent-factory

Summary by CodeRabbit

  • New Features

    • Workflow nodes can now define reusable inputs and outputs.
    • Node inputs can reference outputs from earlier steps using template expressions, including nested values.
    • Workflow execution results are consistently available for subsequent steps.
    • Workflow APIs now save and return node inputs and outputs.
  • Validation

    • Added checks to ensure node inputs and outputs use valid object structures.
  • Documentation

    • Updated workflow schemas and examples to demonstrate connected node data.

This commit introduces a structured node/step interface that adds `inputs` and `outputs` properties to graph-based workflow nodes.

Specifically, it implements:
- Updates to `workflows/workflow.schema.json` to include optional `inputs` and `outputs` definitions on nodes.
- DB updates in `worker/schema.sql` adding `inputs` and `outputs` text columns (storing JSON objects) to the `nodes` table.
- Worker logic updates in `worker/src/index.js` to correctly persist, fetch, validate, and execute nodes containing these fields.
- Verification updates in `scripts/validate.js` ensuring `inputs` and `outputs` are objects.
- Migration updates in `scripts/migrate-workflow.js` to generate default empty inputs/outputs.
- Dynamic evaluation/interpolation in `scripts/executor.js` to resolve references to previous nodes' outputs using the format `{{ nodes.NODE_ID.outputs.PATH }}`.
- Structured output storage (such as `response` from HTTP calls, `output` from command line execution) to the step results in execution logs.
- Realistic test coverage and samples in `workflows/example.json` and `scripts/test-api.js` demonstrating n8n-style dynamic branching and context sharing.

Co-authored-by: aethelred-agent-factory <238771426+aethelred-agent-factory@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 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.

@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 Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Node inputs and outputs are now part of the workflow schema, validation, D1 persistence, API responses, and execution flow. The executor interpolates prior node outputs into later node inputs/configuration and records structured results.

Changes

Node input/output support

Layer / File(s) Summary
Node contract and validation
workflows/workflow.schema.json, scripts/validate.js, worker/src/index.js
Node schemas and validators accept optional non-null object inputs and outputs fields.
Node persistence and API wiring
worker/schema.sql, worker/src/index.js
D1 stores node inputs and outputs, while workflow creation, retrieval, confirmation, and execution paths persist or load them.
Execution interpolation and outputs
scripts/executor.js
Node references resolve against previous results, and run, HTTP, delay, and notify results are stored under entry.outputs.
Migration and integration coverage
scripts/migrate-workflow.js, workflows/example.json, scripts/test-api.js
Migrated workflows initialize the new fields, the example uses output references, and API tests verify persisted values.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: google-labs-jules[bot]

Sequence Diagram(s)

sequenceDiagram
  participant WorkflowAPI
  participant Executor
  participant nodeResults
  participant WorkflowNode
  WorkflowAPI->>Executor: load nodes with inputs and outputs
  Executor->>nodeResults: resolve prior node output references
  Executor->>WorkflowNode: execute resolved inputs and config
  WorkflowNode-->>Executor: return normalized outputs
  Executor->>nodeResults: store node outputs
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: structured node inputs/outputs plus variable interpolation.
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/structured-node-inputs-outputs-10442992188653594916

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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 `@scripts/executor.js`:
- Around line 102-111: Prevent the interpolation logic using nodeResults and
getNestedValue from substituting untrusted values into run.config.command, which
is executed by /bin/bash. Route dynamic node outputs through a constrained
argument or environment interface instead of shell command text, while
preserving safe interpolation behavior for non-command fields.
- Line 164: Update the body assignment in the step request construction to check
explicitly for null or undefined rather than using a truthiness check,
preserving valid falsy values such as false, 0, and an empty string while still
producing undefined for absent bodies.

In `@worker/schema.sql`:
- Around line 22-23: Add a D1 migration for the existing nodes table that
executes ALTER TABLE nodes ADD COLUMN inputs TEXT and ALTER TABLE nodes ADD
COLUMN outputs TEXT before this Worker version is deployed, while retaining the
CREATE TABLE definitions for new databases.

In `@worker/src/index.js`:
- Around line 589-595: Reject arrays in both the worker validators at
worker/src/index.js lines 589-595 and the CLI validators at scripts/validate.js
lines 64-70 by adding Array.isArray checks to the existing inputs and outputs
object-validation conditions. Keep both validators identical so they match the
workflow schema and cannot diverge.
🪄 Autofix (Beta)

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: adf15dc3-e868-4a47-8dc1-b9fa4ee22c53

📥 Commits

Reviewing files that changed from the base of the PR and between 2091836 and a72e44a.

📒 Files selected for processing (10)
  • executions/hello-world-1783998684604.json
  • executions/hello-world-1784001389646.json
  • scripts/executor.js
  • scripts/migrate-workflow.js
  • scripts/test-api.js
  • scripts/validate.js
  • worker/schema.sql
  • worker/src/index.js
  • workflows/example.json
  • workflows/workflow.schema.json
💤 Files with no reviewable changes (2)
  • executions/hello-world-1784001389646.json
  • executions/hello-world-1783998684604.json

Comment thread scripts/executor.js
Comment on lines +102 to +111
return value.replace(/\{\{\s*nodes\.([a-zA-Z0-9_-]+)\.outputs\.([a-zA-Z0-9_\.-]+)\s*\}\}/g, (match, nodeId, path) => {
const nodeRes = nodeResults[nodeId];
if (nodeRes && nodeRes.outputs) {
const val = getNestedValue(nodeRes.outputs, path);
if (val !== undefined) {
return typeof val === 'object' ? JSON.stringify(val) : String(val);
}
}
return match;
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Do not interpolate untrusted output into shell commands.

Interpolation applies to run.config.command, which is executed by /bin/bash. A response from an HTTP node can therefore inject shell syntax into a later run node. Keep dynamic values out of shell command text; pass them through a constrained argument/environment interface instead.

Also applies to: 134-143

🤖 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 `@scripts/executor.js` around lines 102 - 111, Prevent the interpolation logic
using nodeResults and getNestedValue from substituting untrusted values into
run.config.command, which is executed by /bin/bash. Route dynamic node outputs
through a constrained argument or environment interface instead of shell command
text, while preserving safe interpolation behavior for non-command fields.

Comment thread scripts/executor.js
method: step.method || 'GET',
headers: step.headers || {},
body: step.body ? JSON.stringify(step.body) : undefined,
body: step.body ? (typeof step.body === 'string' ? step.body : JSON.stringify(step.body)) : undefined,

Copy link
Copy Markdown

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

Preserve falsy HTTP request bodies.

false, 0, and "" are valid body values but are converted to undefined here. Check explicitly for null/undefined instead.

Proposed fix
- body: step.body ? (typeof step.body === 'string' ? step.body : JSON.stringify(step.body)) : undefined,
+ body: step.body !== undefined && step.body !== null
+   ? (typeof step.body === 'string' ? step.body : JSON.stringify(step.body))
+   : undefined,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
body: step.body ? (typeof step.body === 'string' ? step.body : JSON.stringify(step.body)) : undefined,
body: step.body !== undefined && step.body !== null
? (typeof step.body === 'string' ? step.body : JSON.stringify(step.body))
: undefined,
🤖 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 `@scripts/executor.js` at line 164, Update the body assignment in the step
request construction to check explicitly for null or undefined rather than using
a truthiness check, preserving valid falsy values such as false, 0, and an empty
string while still producing undefined for absent bodies.

Comment thread worker/schema.sql
Comment on lines +22 to +23
inputs TEXT, -- JSON string (optional inputs)
outputs TEXT, -- JSON string (optional outputs)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

git ls-files

Repository: quickerup/telegram-workflow-bot

Length of output: 565


🏁 Script executed:

cat -n worker/schema.sql && printf '\n--- wrangler ---\n' && cat -n worker/wrangler.toml

Repository: quickerup/telegram-workflow-bot

Length of output: 3452


🏁 Script executed:

rg -n "inputs|outputs|schema.sql|d1|migrate|CREATE TABLE nodes|ALTER TABLE nodes" worker scripts README.md

Repository: quickerup/telegram-workflow-bot

Length of output: 7478


🏁 Script executed:

cat -n worker/deploy.sh && printf '\n--- readme ---\n' && rg -n "d1 execute|schema.sql|deploy.sh|wrangler d1|migration" README.md worker/package.json worker/src/index.js

Repository: quickerup/telegram-workflow-bot

Length of output: 2717


🏁 Script executed:

sed -n '1,120p' README.md

Repository: quickerup/telegram-workflow-bot

Length of output: 4557


Add a D1 migration for nodes.inputs and nodes.outputs.
CREATE TABLE nodes only applies to new databases; existing D1 installs still need these columns added before this Worker version ships.

Migration SQL
ALTER TABLE nodes ADD COLUMN inputs TEXT;
ALTER TABLE nodes ADD COLUMN outputs TEXT;
🤖 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 `@worker/schema.sql` around lines 22 - 23, Add a D1 migration for the existing
nodes table that executes ALTER TABLE nodes ADD COLUMN inputs TEXT and ALTER
TABLE nodes ADD COLUMN outputs TEXT before this Worker version is deployed,
while retaining the CREATE TABLE definitions for new databases.

Comment thread worker/src/index.js
Comment on lines +589 to +595
if (node.inputs !== undefined && (typeof node.inputs !== 'object' || node.inputs === null)) {
errors.push(`node ${i} (${node.id || 'unnamed'}): "inputs" must be an object`);
}

if (node.outputs !== undefined && (typeof node.outputs !== 'object' || node.outputs === null)) {
errors.push(`node ${i} (${node.id || 'unnamed'}): "outputs" must be an object`);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep both validators consistent with the JSON Schema. typeof value === 'object' accepts arrays, but workflows/workflow.schema.json declares inputs and outputs as objects. Reject arrays in both validators.

  • worker/src/index.js#L589-L595: add Array.isArray(node.inputs) and Array.isArray(node.outputs) to the rejection conditions.
  • scripts/validate.js#L64-L70: apply the identical array checks so CLI and API validation cannot diverge.
- typeof node.inputs !== 'object' || node.inputs === null
+ typeof node.inputs !== 'object' || node.inputs === null || Array.isArray(node.inputs)

- typeof node.outputs !== 'object' || node.outputs === null
+ typeof node.outputs !== 'object' || node.outputs === null || Array.isArray(node.outputs)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (node.inputs !== undefined && (typeof node.inputs !== 'object' || node.inputs === null)) {
errors.push(`node ${i} (${node.id || 'unnamed'}): "inputs" must be an object`);
}
if (node.outputs !== undefined && (typeof node.outputs !== 'object' || node.outputs === null)) {
errors.push(`node ${i} (${node.id || 'unnamed'}): "outputs" must be an object`);
}
if (node.inputs !== undefined && (typeof node.inputs !== 'object' || node.inputs === null || Array.isArray(node.inputs))) {
errors.push(`node ${i} (${node.id || 'unnamed'}): "inputs" must be an object`);
}
if (node.outputs !== undefined && (typeof node.outputs !== 'object' || node.outputs === null || Array.isArray(node.outputs))) {
errors.push(`node ${i} (${node.id || 'unnamed'}): "outputs" must be an object`);
}
📍 Affects 2 files
  • worker/src/index.js#L589-L595 (this comment)
  • scripts/validate.js#L64-L70
🤖 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 `@worker/src/index.js` around lines 589 - 595, Reject arrays in both the worker
validators at worker/src/index.js lines 589-595 and the CLI validators at
scripts/validate.js lines 64-70 by adding Array.isArray checks to the existing
inputs and outputs object-validation conditions. Keep both validators identical
so they match the workflow schema and cannot diverge.

@o6034005-tech o6034005-tech left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Good

@quickerup
quickerup merged commit ccb4f2c into main Jul 14, 2026
3 checks passed
@quickerup
quickerup deleted the feature/structured-node-inputs-outputs-10442992188653594916 branch July 14, 2026 23:13
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