Skip to content

feat(workflows): make the chat and code-assistant templates real - #2496

Open
Hoang130203 wants to merge 1 commit into
Osmantic:mainfrom
Hoang130203:feat/n8n-chat-endpoint-workflows
Open

feat(workflows): make the chat and code-assistant templates real#2496
Hoang130203 wants to merge 1 commit into
Osmantic:mainfrom
Hoang130203:feat/n8n-chat-endpoint-workflows

Conversation

@Hoang130203

Copy link
Copy Markdown

Summary

ods/CONTRIBUTING.md asks for "Workflow templates — pre-built n8n workflows
that solve actual problems people have."
The two llama-server-only entries in
the catalog were not that. Both were:

{
  "nodes": [
    { "type": "n8n-nodes-base.manualTrigger", "parameters": {} },
    { "type": "n8n-nodes-base.stickyNote",
      "parameters": { "content": "## Chat API Endpoint\n\nThis is a template workflow for REST API chat completions.\n\nCustomize the nodes below to match your setup." } }
  ],
  "connections": {}
}

An empty canvas and a note telling you to build it yourself — while the
dashboard advertises "Chat API Endpoint — REST API for chat completions" with
"setupTime": "1 minute".

(For what it is worth, all 18 catalog entries are currently in this state. I am
starting with the two that need only llama-server, so the dependency surface
is as small as possible.)

What they do now

chat-endpoint — turns llama-server into a small REST API.

Webhook POST /webhook/ods-chat
  -> Read Request      (message | prompt, optional system/temperature/max_tokens)
  -> Message Present?  (IF)
       true  -> llama-server /v1/chat/completions -> Return Reply  (200 JSON)
       false -> Return 400
curl -X POST http://localhost:5678/webhook/ods-chat \
  -H 'Content-Type: application/json' \
  -d '{"message": "Explain RAG in one sentence."}'

code-assistant — same shape, tuned for code.

Webhook POST /webhook/ods-code
  -> Read Request           (task, code, optional language)
  -> Task And Code Present? (IF)
       true  -> llama-server with a code-review system prompt, temperature 0.2
             -> Return Answer (200 JSON)
       false -> Return 400

Design points worth reviewing:

  • Both call http://llama-server:8080 — the manifest's in-network port,
    not the published external_port_default (11434). n8n is on ods-network
    with everything else, so the request never leaves the Docker network. Same
    reasoning as the rest of the stack talking service-to-service.
  • Temperature is pinned at 0.2 for code-assistant and defaults to 0.7 for
    chat, overridable per request.
  • A missing/empty body field returns a 400 with a message naming the field,
    rather than letting the HTTP node fail with a provider error the caller
    cannot interpret.
  • The sticky note in each is now a working curl example instead of a
    placeholder.

AI Assistance

AI assisted with drafting the node graphs, the system prompts, and this
description. I chose the endpoints and ports against the service manifests,
built the validation harness described below, and fixed the one real defect it
found before pushing.

Release Lane

  • Stable hotfix targeting release/2.6.x
  • Mainline change targeting main
  • Next-minor work targeting the next feature/minor release
  • Not sure; reviewer should help classify

Stable hotfix reason:

n/a

Changed Surface

  • Docs only
  • Tests only
  • Dashboard UI
  • Dashboard API / host agent
  • Installer / bootstrap / lifecycle
  • Docker Compose / service manifests
  • Model routing / Hermes / capabilities
  • Network exposure / auth / proxy
  • Dependencies / runtime wiring

(Two JSON files under config/n8n/. These are import payloads for n8n; no ODS
code reads them at runtime. The catalog entries, categories, dependencies, ids
and filenames are unchanged.)

Risk And Validation

  • Risk level: Low
  • Validation run:
    • git diff --check
    • Markdown/link sanity for docs
    • Focused tests listed below
    • Dashboard lint/test/build
    • Extension audit / compose validation
    • Release-grade fleet or scoped hardware validation
    • Stable-lane patch validation, if targeting release/2.6.x

Commands/results:

# Both files validated against the exact node package ODS ships.
# compose.yaml pins n8nio/n8n:2.6.4; `npm view n8n@2.6.4 dependencies.n8n-nodes-base`
# -> 2.6.2, so that is the version I checked against.

$ node verify.js 01-chat-endpoint.json 07-code-assistant.json
n8n-nodes-base version: 2.6.2
node types loaded: 417
  checked 01-chat-endpoint.json: 7 nodes
  checked 07-code-assistant.json: 7 nodes

ALL WORKFLOWS VALID

# The harness loads every node class out of n8n-nodes-base and asserts, per node:
#   - the `type` string resolves to a real node
#   - `typeVersion` is one the node declares
#   - every parameter key set is a property the node actually declares
#   - node names are unique
#   - every connection source and target names a node in the file
#
# It caught a genuine mistake before I pushed: I had put `responseCode` at the
# top level of respondToWebhook, where it belongs under `options`:
#
#   FAIL 01-chat-endpoint.json: n8n-nodes-base.respondToWebhook has no parameter 'responseCode'
#   FAIL 07-code-assistant.json: n8n-nodes-base.respondToWebhook has no parameter 'responseCode'
#
# Also clean against the current 2.15.1 for forward compatibility.

$ python3 -c "import json; [json.load(open(f)) for f in (...)]"
01-chat-endpoint.json  nodes=7 connections=4
07-code-assistant.json nodes=7 connections=4

Caveat, and the one thing I could not do: Docker is not running on my dev
host, so I could not stand up n8n + llama-server and fire a real request end to
end. Everything above is static validation against the real node definitions —
it proves the files import and that no node has an invented parameter or
version, but it does not prove the llama-server response shape flows through
the expression in Return Reply at runtime. That expression reads
$json.choices[0].message.content, which is the standard OpenAI-compatible
chat response llama.cpp's server returns, and is the same path
scripts/ods-test-functional.sh asserts on. If you would like a live run
before merging, say so and I will get one on a machine with Docker.

Operational Change Check

These files are import payloads for n8n. Nothing in the installer, compose
stack, ods-cli, or dashboard-api executes them — dashboard-api only reads
catalog.json for the Workflows page listing, and the file itself is sent to
n8n's import API when the user clicks install. No existing install is affected
until a user chooses to import.

  • This is not an operational change.
  • This is an operational change and validation is recorded above.
  • This is an operational change and validation is intentionally deferred for:

Notes For Reviewers

On the model id. Both workflows send "model": "local-model". llama.cpp's
server ignores the field and serves whatever model it was started with, so any
string works — but if you would rather these read the configured LLM_MODEL,
n8n would need it in its environment (compose.yaml does not pass it today).
Say the word and I will send that as a separate change rather than smuggling an
env addition into a workflow PR.

On webhook paths. I used ods-chat and ods-code. They are unregistered
until a user activates the workflow, and I checked no other catalog workflow
claims them. If you have a naming convention for ODS-shipped webhooks, tell me
and I will rename.

Should the remaining 16 follow? I would like to keep going — the voice ones
(whisper, tts) and the RAG ones (qdrant, embeddings) are the obvious next
batch. Tell me if you would rather they land as one large PR than as a series,
or if the whole idea needs an issue first.

Related: #2495 adds a catalog contract test whose connection-graph assertions
cover files like these. Independent change, no overlapping lines.

config/n8n/01-chat-endpoint.json and 07-code-assistant.json were
placeholders: a manualTrigger, a sticky note reading "Customize the nodes
below to match your setup", and "connections": {}. Importing either gave
you an empty canvas, while the dashboard advertised them as "Chat API
Endpoint — REST API for chat completions, setupTime: 1 minute".

Both are now working workflows:

  chat-endpoint   Webhook POST /webhook/ods-chat -> validate body ->
                  llama-server /v1/chat/completions -> JSON reply.
                  Optional system / temperature / max_tokens overrides.

  code-assistant  Webhook POST /webhook/ods-code -> require task + code ->
                  llama-server with a code-review system prompt at
                  temperature 0.2 -> JSON answer.

Both reach llama-server at its in-network address (llama-server:8080,
the manifest's `port`, not the published external port) so the traffic
never leaves the Docker network. Both answer 400 with a useful message
when the body is missing required fields, instead of failing inside the
HTTP node.

The sticky note in each is now a working curl example rather than a
placeholder.
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.

1 participant