Skip to content

feat: add inject-message action for testing deployed flows - #441

Merged
Steve-Mcl merged 2 commits into
mainfrom
feat/427-inject-automation
Oct 20, 2026
Merged

Steve-Mcl merged 2 commits into
mainfrom
feat/427-inject-automation

Conversation

@Steve-Mcl

Copy link
Copy Markdown
Contributor

Description

Adds automation/inject-message, which lets an agent push a test message into a deployed node and read the result back from the debug sidebar. It no longer has to add an inject node, deploy, and ask the user to click it. Part of #427.

  1. Editor action automation/inject-message takes { id, msg? }. It refuses unknown nodes, nodes with no input port (inject, link in, config nodes), disabled nodes and tabs, nodes inside a subflow definition, and nodes with undeployed changes, since the runtime would otherwise use its old copy. These checks only give the agent a useful error. The runtime does the enforcing.
  2. Runtime route POST /nr-assistant/inject needs write permission. On every call it checks the team's AI Flow Deploy setting through getAutoDeployPolicy(), with no caching. If that check fails, the route treats the setting as off. When the setting is off it returns injected: false with the new code INJECT_NOT_ALLOWED, and nothing is delivered. Otherwise it looks the node up with RED.nodes.getNode, replaces any _msgid with a new one, calls node.receive(), and returns { injected: true, msgid }.
  3. Audit: each inject writes an nr-assistant.inject audit event with the node id, type, name, z and flow name, plus the msgid and a summary of the msg: property types, topic and size, never values. The flow name comes from NR_FLOW_NAME, so on older Node-RED versions it is left out and forge falls back to the flow id.

Testing

Tested end to end on a local instance through the MCP tool:

  • With AI Flow Deploy off, the inject was refused with INJECT_NOT_ALLOWED.
  • With it on, { payload: 21 } into a function that doubles the payload gave 42 at the downstream debug node.
  • A 12-property msg with nested objects, arrays and null went through the same way.

Notes

Related Issue(s)

Checklist

  • I have read the contribution guidelines
  • Suitable unit/system level tests have been added and they pass
  • Documentation has been updated
    • Upgrade instructions
    • Configuration details
    • Concepts
  • Changes flowforge.yml?
    • Issue/PR raised on FlowFuse/helm to update ConfigMap Template
    • Issue/PR raised on FlowFuse/CloudProject to update values for Staging/Production
  • Link to Changelog Entry PR, or note why one is not needed.

Labels

  • Includes a DB migration? -> add the area:migration label

@Steve-Mcl
Steve-Mcl requested a review from andypalmi October 19, 2026 17:36
@Steve-Mcl Steve-Mcl linked an issue Oct 19, 2026 that may be closed by this pull request
Comment thread lib/assistant.js

@andypalmi andypalmi 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.

Thanks, this reads well and the test coverage is great. A few things:

Undeployed changes downstream

  1. _getInjectTargetError only checks changed on the target node. If a node further down the flow has undeployed edits, the runtime runs the old version and the agent reads debug output that doesn't match the editor. Should we check downstream too?
  2. Two options I can see: refuse when RED.nodes.dirty() is true (simple, but an edit on an unrelated tab also blocks it), or walk RED.nodes.getAllDownstreamNodes(node) and check changed on those. I'd lean towards downstream, also following link out (link mode) and link call into their link in nodes, since getAllDownstreamNodes stops at link nodes. What do you think, and would you refuse or return a warning listing the changed nodes?

Topic in the audit entry
3. summarizeMsg logs the topic value itself, while the rest of the summary keeps to types only. Topics can carry identifying data (e.g. customers/acme/orders). Do we need the value there? properties.topic already records its type.

Policy check failure (follow-up)
4. getAutoDeployPolicy() returns false when forge can't be reached, so an outage shows up as INJECT_NOT_ALLOWED and the agent asks the user to enable a setting that may already be on. Deploy has the same behaviour.
5. Would a follow-up make sense where the check returns three states (allowed, not allowed, check failed), still failing closed? Inject would return something like POLICY_CHECK_FAILED, and /deploy-policy something like { autoDeploy: false, checkFailed: true } mapped to a new DEPLOY_POLICY_UNAVAILABLE code in the editor. Happy to open an issue for it.

@Steve-Mcl

Copy link
Copy Markdown
Contributor Author

_getInjectTargetError only checks changed on the target node. If a node further down the flow has undeployed edits, the runtime runs the old version and the agent reads debug output that doesn't match the editor. Should we check downstream too?

No, this is no different to a user injecting a fully deployed inject against a locally modified flow. I do this myself - I inject knowing the debug will be generated from what the server has so I can use the output to correct downstream code. Perhaps a later iteration could adopt a parameter to ensure downstream is deployed (or workspace is not dirty) if desired. Also, it would never cover things like link-separated or mqtt-separated flows on a workspace so has limited benefits. Lets K.I.S.S for now. I wouldnt be against the AI knowing (via signals/skills) that the workspace is dirty so it can inform the user that the editor does not match server (so inject may not produce what they think) however this is base node-red knowledge!


summarizeMsg logs the topic value itself, while the rest of the summary keeps to types only. Topics can carry identifying data (e.g. customers/acme/orders). Do we need the value there? properties.topic already records its type

Needed - no, but thought it would be useful for audit purposes. Should we remove?


Policy check failure (follow-up)
4. getAutoDeployPolicy() returns false when forge can't be reached, so an outage shows up as INJECT_NOT_ALLOWED and the agent asks the user to enable a setting that may already be on. Deploy has the same behaviour.
5. Would a follow-up make sense where the check returns three states (allowed, not allowed, check failed), still failing closed? Inject would return something like POLICY_CHECK_FAILED, and /deploy-policy something like { autoDeploy: false, checkFailed: true } mapped to a new DEPLOY_POLICY_UNAVAILABLE code in the editor. Happy to open an issue for it.

If we are happy to move forward then yes please - raise as follow ups @andypalmi

@Steve-Mcl
Steve-Mcl merged commit f71c55f into main Oct 20, 2026
9 checks passed
@Steve-Mcl
Steve-Mcl deleted the feat/427-inject-automation branch October 20, 2026 09:49
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.

Inject automation: inject-message automation and runtime endpoint

2 participants