Documentation / Conception / Guides pratiques / Use an agent in a workflow

Use an agent in a workflow

An agent — a prompt + LLM provider/model + typed ports + tools — is projected as an ordinary node type, agent.<slug>, kind agent (libs/engine-core/src/engine/agents.ts, agentToNodeMeta). Once it's loaded on the instance, wiring it into a graph is no different from wiring any other node: same palette, same connections: grammar, same static validation. This recipe covers that wiring. It assumes the agent itself already exists — either contributed by a plugin's contributes.agents or a legacy instance-local agents/*.agent.yaml (see Author an LLM agent) — and that you already know the basics of connecting ports (see Wire ports and The dataflow model).

Don't confuse an agent node with the editor's "✨ Assistant IA" panel, which uses an LLM to draft or edit the workflow graph itself — a different feature, covered in Use the AI assistant.

Find the agent's node type id and ports

  1. Open the workflow editor's palette and look under the Agents IA category (libs/engine-core/src/engine/agents.ts: category: "Agents IA") — every loaded agent appears there, alongside built-in and plugin nodes (see Use the visual editor). If you're editing YAML by hand instead, call GET /api/catalog or GET /api/agents on the running instance to list the same node type ids.
  2. The id is agent.<slug(name)>: the agent's name, lower-cased, accents stripped, non-alphanumerics collapsed to - (apps/api/src/plugins.ts, slug; the legacy instance-local path derives it from the .agent.yaml filename instead — agentNodeTypeId in libs/engine-core/src/engine/agents.ts). "Revue gériatrique de l'ordonnance" becomes agent.revue-geriatrique-de-l-ordonnance (external-plugins/geriatrie/plugin.yaml).
  3. Read the port names off the palette entry's hover text or the catalog entry's description, which is generated as Agent <provider>/<model>. Entrées (<name>: <Type>, …) → sorties (<name>: <Type>, …). plus Outils : <label>, … when the agent has tools. An agent can declare more than one named input and output port, each independently typed and optionally a list — it isn't always a single input/output pair. Compare two real agents:
    • agent.revue-geriatrique-de-l-ordonnance — one input port literally named input (type Prescription), one output named output (type DeprescribingAssessment): the older single-port shorthand (input:/output: as plain type names) normalizes to ports named exactly input/output (libs/shared/src/plugin/manifest.ts, AgentContribSchema preprocess).
    • agent.extraction-de-symptomes-transmission-ide (external-plugins/demo-softway/plugin.yaml) — one input named transmission (String), one output named symptoms (String, list: true): the named-ports form, so you wire .transmission and .symptoms, not .input/.output.

Add the node

  1. In the visual editor, click the agent's entry in the Agents IA palette group — it's added to the canvas and selected, exactly like any other node (apps/config-plane/app/components/WorkflowEditor.tsx, the palette onClick/addNode).

  2. In YAML, add an entry under nodes: with type: agent.<slug> and any node id you like:

    nodes:
      review_assessment:
        type: agent.revue-geriatrique-de-l-ordonnance
    
  3. If the agent's plugin isn't installed on this instance yet, install it first — see Declare and install plugins.

Wire its ports

An agent node's ports are checked for connection compatibility the same way as any node's — output type must be assignable to input type, required inputs must end up connected or given a fixed value. Nothing here is agent-specific; follow Wire ports for split-pin fields, params⇄ports, and transform.break/transform.make/transform.convert for type mismatches. Wire each named port by name, from the upstream node's matching output to the agent's input, and from the agent's output onward:

# content/clinical-demo/workflows/deprescription-geriatrique.workflow.yaml
nodes:
  load_prescription: { type: order.load-prescription }
  review_assessment: { type: agent.revue-geriatrique-de-l-ordonnance }
  choose_candidate:   { type: agent.selection-du-candidat-prioritaire }
  taper_plan:         { type: agent.plan-de-sevrage-medicamenteux }
connections:
  - { from: trigger.prescriptionRef,        to: load_prescription.prescriptionRef }
  - { from: load_prescription.prescription, to: review_assessment.input }
  - { from: review_assessment.output,       to: choose_candidate.input }
  - { from: choose_candidate.output,        to: taper_plan.input }

Chain several agents

Feeding one agent's output straight into the next agent's input is ordinary fan-out/convergence wiring — nothing special beyond matching types. The full chain above runs five agents back to back, each consuming the previous one's typed output (content/clinical-demo/workflows/deprescription-geriatrique.workflow.yaml); the same output can also fan out to more than one downstream agent, as taper_plan's output does to both counseling and follow_up in that file.

Ambient context reaches an agent's tools automatically

An agent node itself declares no context requirement (agentToNodeMeta: context: []) — you don't need to add anything to the workflow's context: list just because you added an agent node. But the ambient context (patient, encounter, …) the workflow already carries is passed through to every tool the agent calls at run time (libs/engine-core/src/engine/catalog.ts: the agent's run builds each tool's invoke with the node's own context) — so a tool like patient.load-demographics still resolves the right patient without you wiring anything extra into the agent node.

Validate before running

meridian-plugin validate does not know about agent nodes — it reports any agent.* node as an unknown type, because the CLI only registers metadata from the manifests you pass it explicitly (libs/plugin-cli/src/commands/validate.ts). For a workflow that includes agent nodes, check it on a running instance instead, where the catalog already includes every loaded agent — see Validate a workflow and Simulate a workflow.

Try it without paying for LLM calls

Once the graph has at least one agent node, the editor's simulation panel shows an agents réels ("real agents") checkbox (apps/config-plane/app/components/WorkflowEditor.tsx, SimulatePanel, hasAgents). Leave it unchecked to run the simulation with a deterministic mock in place of every agent — useful for checking the graph's shape and wiring — or check it to exercise the real prompt/tool loop against a provider, which is billed. See Simulate a workflow for the rest of that flow.

Run it for real

Executing an agent node needs the instance's agent port bound to a runner adapter (normally @posos/llm) with a matching provider API key in the environment — otherwise the run fails explicitly rather than falling back to a mock (external-plugins/llm/adapters/runner.ts). That binding is instance configuration, not something this workflow declares:

ports:
  agent: { adapter: llm }

See Author an LLM agent for the full binding and the per-provider environment variable names, and Configure ports and adapters for wiring instance ports in general. Once it's bound, kick off and follow the run like any other workflow — see Run and resolve and Monitor executions.

If a run fails with "pas de réponse finale après N tours" (the agent exhausted its maxIterations without producing a result), that's a property of the agent's own definition, not of how you wired it here — see Author an LLM agent to adjust it.

Without a pre-registered agent: agent.dynamic and agent.inline

Two core nodes (palette group Agents) cover the cases where the agent is not — or not yet — a registered one:

  • Agent (choisi au runtime) (agent.dynamic): the agent input names a REGISTERED agent (name or agent.<slug> id) and can be wired, so the graph decides at runtime which agent runs; inputs carries the agent's input record (Any), and the whole output record is emitted on result (Any — its shape depends on the agent picked, so wire it into a transform.format or another Any consumer). The inspector offers a selector when the input is not wired.
  • Agent (défini dans le nœud) (agent.inline): the full agent definition — provider, model, prompt, max iterations, tools, typed inputs/outputs — lives in the node's config; the typed fields become the node's ports, so wiring and validation work exactly as with a registered agent. Use it for a one-off agent without declaring it first; promote it to a registered agent (plugin or Agents page) when it earns reuse.

Both execute through the same runner and tool wiring as registered agent nodes — simulation (mock or real) and provider keys behave identically.

A registered agent's definition is validated by its schema when it loads; an inline one has no such pass, so the node checks what it can when it runs: a provider outside the supported list and an unknown type name on an input or output field fail with an explicit message, rather than reaching the runner as garbage. Declaring at least one typed output and a model is likewise required.

75 documents10 sectionssource : /docs · généré au build