Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
220 changes: 141 additions & 79 deletions nodes/src/nodes/agent_crewai/README.md

Large diffs are not rendered by default.

150 changes: 74 additions & 76 deletions nodes/src/nodes/agent_langchain/README.md
Original file line number Diff line number Diff line change
@@ -1,109 +1,107 @@
# agent_langchain

A RocketRide agent node that runs a single tool-calling agent loop using LangChain.
A RocketRide agent node for answering questions with a LangChain agent loop and
the LLM and tools wired into the pipeline. Choose it when a single agent should
use LangChain's structured tool-call flow, rather than coordinate CrewAI
subagents.

## What it does

Receives a question on the `questions` lane, runs a LangChain agent loop (via `langchain.agents.create_agent`) against the connected LLM and tool nodes, and emits the final answer on the `answers` lane.

Uses **langchain** and **langchain-core**, installed lazily from `requirements.txt` when the pipeline starts (not at config time). The LangChain framework never talks to a model provider directly: it drives a thin chat-model adapter that delegates every completion to the LLM node connected on the `llm` channel, and a tool adapter that routes every tool call through the engine's control-plane invoke to the connected tool nodes.

The node is registered with `classType: ["agent", "tool"]`, so besides answering questions from the lane it also exposes itself as a `run_agent` tool that parent agents can invoke for hierarchical orchestration.

Failures are graceful: if the agent run raises, the error message is emitted as the answer content with a `RocketRide.agent.error.v1` entry on the payload's `stack` instead of crashing the pipeline.

---

## Configuration
## About LangChain

### Lanes
LangChain is a framework for building applications that combine language models
with tools and message-based workflows. This node uses its agent and chat-model
interfaces while keeping model and tool execution on RocketRide connections.

| Lane | Direction | Description |
|-------------|-----------|-------------------------------------------------------|
| `questions` | in | Incoming `Question` objects that trigger an agent run |
| `answers` | out | Final answer text produced by the agent |

The node also streams progress events over the `thinking` SSE lane during a run: agent start, LLM call start/completion/error, tool call start/completion/error, and agent think/finish notifications.

### Fields

| Field | Type | Description |
|---|---|---|
| `agent_description` | string | Default empty. What does this agent do? Describe its purpose and capabilities, this helps parent agents select and invoke it correctly. |
| `instructions` | array | Additional instructions to guide the agent. |
| `profile` | string | Default "default". |

A single `default` profile exists (`agent_langchain.profile`), containing both fields.
## What it does

---
The node accepts a question on `questions`, runs a LangChain agent using the
connected LLM and any connected tools, then writes the final text to `answers`.
It is also available to a parent agent as a tool. The LLM adapter asks the model
for a JSON envelope that represents either a tool call or a final answer, then
converts it into LangChain's structured message form. Choose this node for that
single-agent LangChain flow; use the CrewAI manager when work must be delegated
to configured specialist subagents.

## Connections

| Channel | Required | Description |
|---------|----------------|---------------------------------------------------------|
| `llm` | yes (min: 1) | LLM the agent thinks with |
| `tool` | no (min: 0) | Tools available to the agent (via control-plane invoke) |

---
| Connection | Required | Description |
| --- | --- | --- |
| `llm` | yes | LLM used by the agent. |
| `tool` | no | Tools available to the agent through control-plane invocation. |

## Tool calling: JSON envelope protocol
The `llm` connection is required. With no `tool` connection, the agent can
still produce a final answer, but has no pipeline tools to call.

RocketRide's LLM seam is text-only, but LangChain agents expect a chat model that returns structured `tool_calls`. The node bridges this with a JSON envelope protocol: on every turn the LLM is instructed to output exactly one JSON object, either
## Lanes

```json
{"type":"tool_call","name":"server.tool","args":{...}}
```
| Lane in | Lane out | Description |
| --- | --- | --- |
| `questions` | `answers` | Run the agent for each incoming question and emit its final answer. |

or
During a run, the node sends `thinking` SSE updates for agent startup,
LLM activity, and tool-call activity.

```json
{"type":"final","content":"..."}
```
## As a tool

The envelope is parsed into an `AIMessage` with structured `tool_calls`, so the protocol works with any LLM that can follow JSON instructions; native function-calling support is not required. Up to three attempts are made per turn: after each malformed output the model is re-prompted with a correction notice, and if all attempts fail the raw text is returned as the final answer for that turn.
The registered tool name is `<nodeId>.run_agent`, where `<nodeId>` is this
node's pipeline ID; it has no separately configured server-name prefix.

Each connected tool is wrapped as a LangChain `BaseTool` whose argument schema is built dynamically from the tool's real JSON input schema (falling back to a generic `input` field when no usable schema is available), so tool parameters are preserved end-to-end across LangChain versions.
| Function | Description |
| --- | --- |
| `<nodeId>.run_agent` | Run this LangChain agent for a delegated query and return its agent result. |

---
The input must be an object with required non-empty `query: string` and optional
`context: object`. The node stores supplied context as a
`RocketRide.agent.tool_context.v1` context entry. The call returns
`{content, meta, stack}` to its caller instead of writing to `answers`.
Non-object input, a blank query, or a non-object context raises `ValueError`.
If the LLM does not produce a parsable envelope after three attempts, the
adapter supplies an explanatory final message rather than a tool call.

## Using as a tool

The node exposes a `run_agent` tool (invocable as `<nodeId>.run_agent`) so parent agents can delegate work to it in hierarchical pipelines.
## Configuration

| Direction | Shape |
|-----------|-------------------------------------|
| Input | `{query: string, context?: object}` |
| Output | `{content, meta, stack}` |
The only profile is `default`: connect an LLM first, then add tools only when
the agent needs to take actions or retrieve information. Most pipelines can
leave the profile selection alone and set the fields that shape delegation and
answering behavior.

`query` must be a non-empty string. An optional `context` object is attached to the question as a `RocketRide.agent.tool_context.v1` JSON block. When invoked as a tool the answer payload is returned to the caller and not written to the `answers` lane.
### Agent description

The tool's description automatically includes the configured `agent_description`, which is how a parent agent decides whether this agent fits a sub-task.
This text is added to the registered `run_agent` tool description when it is
non-empty. Set it when another agent may choose this node, describing the
specialist job and the kinds of requests it should receive; leave it empty when
the node is only driven from its `questions` lane. A concrete description such
as “Summarizes retrieved policy documents” gives a parent a usable routing cue.

---
### Instructions

## Answer payload
Use the instruction list for additional guidance supplied by this node's
configuration. Keep each entry narrowly scoped to the work the agent should do
or the constraints it must honor. Put enduring routing information in **Agent
description** instead, because that is the text exposed to parent agents.

Every run produces a payload with:
### Require tool call

- `content`: the final answer text (or the error message on failure)
- `meta`: `framework` (`langchain`), `agent_id`, `run_id`, `started_at`, `ended_at`, `tool_calls` (number of tools invoked this run), and `task_id` when available
- `stack`: a `RocketRide.agent.raw.v1` entry carrying the raw framework output, a `RocketRide.agent.guard.v1` entry when the `require_tool_call` guard trips, or a `RocketRide.agent.error.v1` entry on failure
This option is off by default. Turn it on for a workflow where an answer must
follow at least one real tool invocation, for example a response that must be
grounded in a connected store. Leave it off when the agent can validly answer
without a tool; enabled runs that answer without a tool fail with the declared
guard error.

When the run is triggered from the `questions` lane, only `content` is written to the `answers` lane; the full payload is what `run_agent` callers receive.
## Notes

---
### JSON tool-call protocol

## Fabrication guard
RocketRide's LLM seam is text-based, while the LangChain agent expects
structured tool calls. On each model turn, the adapter requests exactly one
JSON object: `{"type":"tool_call","name":"server.tool","args":{...}}` or
`{"type":"final","content":"..."}`. It retries malformed output twice with
a correction prompt; after the third invalid response it returns an explanatory
AI message. Connected tools receive dynamically built argument schemas from
their declared input schemas, with a generic `input` field as the fallback.

Smaller or weaker planning models occasionally **narrate** a multi-step tool chain in
prose instead of actually calling the tools, producing a plausible-looking but ungrounded
answer. The optional **Require tool call** (`require_tool_call`) config field guards against
this: when enabled, any run that produces an answer without invoking at least one tool fails
with a `RocketRide.agent.guard.v1` error instead of delivering the ungrounded text. It is off by
default; enable it for determinism-critical pipelines. The guard counts real tool invocations
only — internal/local reads (for example the wave agent’s `memory.peek`) do not satisfy it.
## Upstream docs

---
- [LangChain documentation](https://docs.langchain.com/)

<!-- ROCKETRIDE:GENERATED:PARAMS START -->
<!-- Generated by nodes:docs-generate. Do not edit by hand. -->
Expand Down
Loading
Loading