@manny-est/node-red-flowpilot 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,100 @@
2
2
 
3
3
  All notable changes to FlowPilot are documented here.
4
4
 
5
+ ## [0.5.2] - 2026-08-04
6
+
7
+ This release continues the 0.5.x line. Phase 10's agentic Modify redesign
8
+ (WRITE-tool loop, per-call consent gates, `ask_user`) is developed
9
+ separately and is not included here — it ships under its own beta line
10
+ until it's ready to replace this one.
11
+
12
+ ### Added
13
+ - **Anthropic provider support**: FlowPilot can now talk directly to the
14
+ Anthropic API (Claude models) alongside any OpenAI-compatible endpoint.
15
+ A new Provider Type dropdown in Settings switches between them; message
16
+ format, tool-call translation, and streaming (SSE) are handled
17
+ transparently by a dedicated adapter. Leave Base URL blank to use
18
+ `api.anthropic.com`.
19
+ - **Reasoning model support**: FlowPilot detects reasoning models
20
+ (Nemotron, DeepSeek, QwQ, and any model returning `reasoning_content` or
21
+ `<think>` blocks) and shows a live collapsing "Thinking…" block during
22
+ streaming, or a pre-collapsed one on the agent-loop path.
23
+ - **Auto-preflight on model change**: switching models and sending a
24
+ message silently probes capabilities first — no more manual "Test
25
+ Provider" click after every model swap.
26
+ - **`/refresh` command**: re-renders the message panel from the in-memory
27
+ record store without losing conversation history — restores interactive
28
+ Apply buttons and review panels that went stale after a long session.
29
+ - **Build loop — consent gates for side-effecting steps, checkpoint
30
+ questions, context-aware start from a selection, and an explicit
31
+ done/fail confirmation** instead of silently stopping.
32
+ - **Modify — todo/plan checklist rendering**: multi-item Modify requests
33
+ now show a checklist that resolves as verification confirms each item
34
+ landed, instead of a single opaque pass/fail.
35
+ - **Config node support**: config nodes (MQTT brokers, TLS configs, etc.)
36
+ are now exposed in context and can be created/connected by Modify.
37
+ - **Server-side validator/repair layer**: malformed model output is
38
+ caught and, where possible, automatically repaired before it reaches
39
+ the canvas.
40
+
41
+ ### Fixed
42
+ - **Build loop — status-only evidence false negatives**: a live, working
43
+ node could be declared "disconnected"/broken off a single coarse
44
+ node-status read, with no way to confirm otherwise. Evidence is now
45
+ tagged by source (`debug` vs. `status`); when only status-line evidence
46
+ is available and it doesn't clearly prove success or failure, the build
47
+ loop asks a direct yes/no confirmation instead of guessing.
48
+ - **Modify's wire verification** read a node's stale `.wires` array
49
+ instead of the live link registry — a wire added earlier in the same
50
+ editing session could be reported as "did not land" even though it was
51
+ actually there. Verification now reads from `RED.nodes.eachLink`.
52
+ - **Phantom output port on newly-created nodes**: a model-supplied
53
+ `wires` array that disagreed with a node type's real port count (e.g.
54
+ a stray empty port on a 0-output type like `http response`) rendered a
55
+ visible port anchor that shouldn't exist. The array length is now
56
+ reconciled against the node's real output count on insertion.
57
+ - **New-node layout scatter**: the collision-avoidance grid still placed
58
+ two nodes at the same vertical level; switched to a single-column
59
+ layout (one node per row, wrap to a new column after 5 rows).
60
+ - **`newWires` endpoint aliases**: a model response using `fromId`/`toId`
61
+ instead of `from`/`to` on a `newWires` entry is now repaired
62
+ automatically instead of both endpoints silently appearing missing.
63
+ - **`.fp-chip-card-alt` background**: the secondary "Just add to canvas"
64
+ chip relied on its surrounding message bubble being dark to read as
65
+ part of the same chip-card family as the primary action above it —
66
+ bubbles follow Node-RED's light editor theme by default, so it rendered
67
+ as a plain white box instead.
68
+ - Redaction round-trip poisoning, token-credential redaction gaps, and
69
+ several redaction echo/false-positive fixes across Modify and the build
70
+ loop's review step.
71
+ - Group data corruption from a stray `changes` patch touching a group's
72
+ membership array directly; mixed-membership group create/extend
73
+ corruption.
74
+ - Invalid port wiring (wiring to/from a port index that doesn't exist)
75
+ now guarded instead of silently applied.
76
+ - New-node insertion collision avoidance tuned for faster, more reliable
77
+ separation on dense flows.
78
+ - Several build-loop review false positives (metadata-field echoes,
79
+ debug/function/mqtt node misclassification, stale in-progress status
80
+ read as a real error).
81
+ - Partial id-validation no longer discards an entire valid Modify batch
82
+ over one bad node id.
83
+
84
+ ## [0.5.1] - 2026-07-24
85
+
86
+ ### Added
87
+ - **`/refresh` command**: re-renders the entire message panel from an in-memory record store without clearing conversation history. Restores interactive Apply buttons and review panels that may have become stale after a long session or a pop-out sync. Type `/refresh` at any time.
88
+ - **Reasoning model support**: FlowPilot detects reasoning models (Nemotron, DeepSeek, QwQ, and any model returning `reasoning_content` or `<think>` blocks) at pre-flight and handles them correctly throughout. Streaming: a live collapsing "Thinking…" block shows reasoning tokens as they arrive, then auto-collapses when the real response begins. Non-streaming (agent loop): a pre-collapsed thinking block renders alongside the final response. Both the SGLang/Nemotron (`delta.reasoning_content`) and llama.cpp/LocalAI (`<think>…</think>` in `delta.content`) formats are supported. Token count shown on collapse.
89
+ - **Auto-preflight on model change**: changing the model field and sending a message now triggers a silent capability probe before the request goes out — no need to click "Test Provider" after every model switch. A notice appears in the chat thread confirming the probe result (model name, tool support, reasoning flag). Settings are saved automatically as part of the probe so the backend uses the new model. The provider status line also updates live as you type the model name.
90
+
91
+ ### Fixed
92
+ - **Pre-flight `probedModel` not reaching frontend**: after a `/test` run, `probedModel` was saved to disk but never mirrored into the in-memory provider profile, so the auto-probe condition (`probedModel !== currentModel`) could never fire after a page reload. The `/test` response now includes `probedModel` in the `capability` object and `handleSendResult` mirrors it into `currentSettings.providers`.
93
+ - **Reasoning content scrolling**: the live thinking block now scrolls to bottom on each streaming delta so long reasoning chains stay visible as they arrive.
94
+
95
+ ### Internal
96
+ - Phase 10 Workstream 0A: shadow record store added across `main.js`, `apply-review.js`, `modes.js`, `init.js` — addMessage/addModifyReview/addGeneratedReview/renderActionChip/renderClarifyingQuestion/renderLoopCheckpoint/renderLoopStepper all create typed records; rerenderRecord dispatches each kind on refresh.
97
+ - Phase 10 Workstream 0B: DOM elements now carry `data-fp-record-id` (record id) instead of inline JSON payloads in `data-fp-apply-*` attributes. Four separate pop-out bind functions consolidated into a single `bindReviewApplyButtons`; four separate parent postMessage handlers replaced by a unified `applyByRecordId` handler that dispatches on the record's subkind.
98
+
5
99
  ## [0.5.0] - 2026-07-06
6
100
 
7
101
  ### Added
package/README.md CHANGED
@@ -6,9 +6,10 @@ FlowPilot: AI assistance for Node-RED, designed for builders who want help
6
6
  without giving up control.
7
7
 
8
8
  FlowPilot is an AI-powered development assistant that lives in the Node-RED
9
- editor sidebar. It talks to any OpenAI-compatible API (OpenAI, LocalAI,
10
- Ollama, etc.) and helps you generate, modify, document, and discuss your
11
- flows — without ever acting behind your back.
9
+ editor sidebar. It talks natively to Anthropic (Claude models) or to any
10
+ OpenAI-compatible API (OpenAI, LocalAI, Ollama, etc.) and helps you
11
+ generate, modify, document, and discuss your flows — without ever acting
12
+ behind your back.
12
13
 
13
14
  ![FlowPilot sidebar](https://github.com/manny-est/flowpilot/releases/download/v0.2.1/sidebar-chat-overview.png)
14
15
 
@@ -29,8 +30,8 @@ installation, the sidebar UI, and a chapter on every feature.
29
30
  - **Undo first** — every change goes through Node-RED's native undo
30
31
  (Ctrl+Z), including multi-part changes (insertions + rewires + new nodes)
31
32
  as a single step.
32
- - **Open architecture** — provider-agnostic, OpenAI-compatible REST. No
33
- lock-in to one AI platform.
33
+ - **Open architecture** — provider-agnostic: native Anthropic support, or
34
+ any OpenAI-compatible REST endpoint. No lock-in to one AI platform.
34
35
  - **Simple and lightweight** — favors simple, maintainable solutions over
35
36
  speculative complexity.
36
37
 
@@ -129,11 +130,24 @@ under `<node-red-userDir>/flowpilot/`:
129
130
  - `chats/` — lightweight per-session chat logs
130
131
  - `backups/` — pre-change backups
131
132
 
132
- ## Provider setup (example: LocalAI)
133
+ ## Provider setup
133
134
 
134
135
  Open the FlowPilot sidebar, click the settings (gear) icon, and add a
135
- provider:
136
+ provider.
136
137
 
138
+ **Anthropic (Claude models):**
139
+
140
+ - Provider type: `Anthropic`
141
+ - Provider name: `Claude` (or any label)
142
+ - Base URL: leave blank (uses `api.anthropic.com`)
143
+ - API key: your Anthropic API key. If it returns an
144
+ `anthropic-workspace-id is required` error, create a new key in the
145
+ Anthropic Console scoped to a single workspace.
146
+ - Model: e.g. `claude-opus-5`, or click **Refresh models**
147
+
148
+ **Example: LocalAI (OpenAI-compatible):**
149
+
150
+ - Provider type: `OpenAI-compatible`
137
151
  - Provider name: `LocalAI` (or any label)
138
152
  - Base URL: `http://localhost:8080`
139
153
  - API key: blank unless your instance requires one
package/USER-GUIDE.md CHANGED
@@ -103,23 +103,32 @@ saved transcript permanently.
103
103
 
104
104
  ## Set a Provider
105
105
 
106
- FlowPilot talks to any **OpenAI-compatible** API OpenAI itself, LocalAI,
107
- Ollama (with its OpenAI-compatible endpoint), LM Studio, etc.
106
+ FlowPilot talks to **Anthropic** (Claude models) natively, or to any
107
+ **OpenAI-compatible** API OpenAI itself, LocalAI, Ollama (with its
108
+ OpenAI-compatible endpoint), LM Studio, etc.
108
109
 
109
110
  1. Open **Settings** (gear icon).
110
111
  2. Under **Providers**, click **+ Add** if you need a new provider slot
111
112
  (one is created for you by default).
112
- 3. Fill in:
113
- - **Provider Name** — any label, e.g. `LocalAI` or `OpenAI`.
114
- - **Base URL** — e.g. `http://localhost:8080` or `https://api.openai.com`.
115
- If Node-RED is running in Docker, `localhost` refers to the *Node-RED
116
- container*, not the Docker host use the provider's container name, a
117
- Docker network alias, or a host IP (e.g. `http://172.17.0.1:8080`)
118
- instead.
119
- - **API Key** leave blank unless your provider requires one.
120
- - **Model** type a model name, or click **Refresh models** to fetch the
121
- provider's available models (via `GET /v1/models`) and pick from the
122
- list.
113
+ 3. Pick a **Provider Type**: `OpenAI-compatible` (the default) or
114
+ `Anthropic`.
115
+ 4. Fill in:
116
+ - **Provider Name** any label, e.g. `LocalAI`, `OpenAI`, or `Claude`.
117
+ - **Base URL**
118
+ - OpenAI-compatible: e.g. `http://localhost:8080` or
119
+ `https://api.openai.com`. If Node-RED is running in Docker,
120
+ `localhost` refers to the *Node-RED container*, not the Docker
121
+ hostuse the provider's container name, a Docker network alias,
122
+ or a host IP (e.g. `http://172.17.0.1:8080`) instead.
123
+ - Anthropic: leave blank to use `api.anthropic.com` — only set this
124
+ if you're routing through a proxy or gateway.
125
+ - **API Key** — for OpenAI-compatible, leave blank unless your provider
126
+ requires one. For Anthropic, this is required. If your key returns
127
+ an `anthropic-workspace-id is required` error, it wasn't scoped to a
128
+ single workspace when created — go to the Anthropic Console, create a
129
+ new key, and choose a specific workspace at creation time.
130
+ - **Model** — type a model name, or click **Refresh models** to fetch
131
+ the provider's available models and pick from the list.
123
132
  - **Temperature** — a starting value of `0.2` works well for most uses.
124
133
 
125
134
  ![Provider settings: Base URL, API key, model, and temperature fields](https://github.com/manny-est/flowpilot/releases/download/v0.2.1/sidebar-settings-providers.png)
@@ -15,6 +15,7 @@
15
15
 
16
16
  .fp-header-row {
17
17
  display: flex;
18
+ flex-wrap: wrap;
18
19
  align-items: center;
19
20
  gap: 12px;
20
21
  }
@@ -49,8 +50,12 @@
49
50
  .fp-view-buttons {
50
51
  display: flex;
51
52
  gap: 6px;
52
- position: relative;
53
- top: 2px;
53
+ /* Own row below the logo/title/subtitle at default (narrow) sidebar
54
+ width — sharing the row with .fp-heading left too little space for
55
+ "AI flow assistant" to fit on one line, so it wrapped across three. */
56
+ flex: 1 0 100%;
57
+ justify-content: flex-end;
58
+ margin-top: 8px;
54
59
  }
55
60
 
56
61
  .fp-panel {
@@ -103,6 +108,65 @@
103
108
  border-color: rgba(80, 130, 255, 0.35);
104
109
  }
105
110
 
111
+ /* Reasoning / thinking block — shown for models that emit reasoning_content
112
+ (e.g. Nemotron, DeepSeek-R1). Sits above the assistant response bubble.
113
+ Expanded while the model thinks; collapses automatically when content starts. */
114
+ .fp-thinking {
115
+ margin-bottom: 8px;
116
+ border-radius: 8px;
117
+ border: 1px solid rgba(120, 100, 220, 0.25);
118
+ background: rgba(100, 80, 200, 0.05);
119
+ overflow: hidden;
120
+ }
121
+
122
+ .fp-thinking summary {
123
+ display: flex;
124
+ align-items: center;
125
+ gap: 6px;
126
+ padding: 7px 12px;
127
+ cursor: pointer;
128
+ font-size: 11px;
129
+ font-weight: 600;
130
+ letter-spacing: 0.04em;
131
+ color: var(--red-ui-secondary-text-color, #888);
132
+ user-select: none;
133
+ list-style: none;
134
+ }
135
+
136
+ .fp-thinking summary::-webkit-details-marker { display: none; }
137
+
138
+ .fp-thinking summary::before {
139
+ content: "▶";
140
+ font-size: 8px;
141
+ display: inline-block;
142
+ transition: transform 0.15s ease;
143
+ color: var(--red-ui-secondary-text-color, #aaa);
144
+ flex-shrink: 0;
145
+ }
146
+
147
+ .fp-thinking[open] summary::before {
148
+ transform: rotate(90deg);
149
+ }
150
+
151
+ .fp-thinking-tokens {
152
+ margin-left: auto;
153
+ font-size: 10px;
154
+ font-weight: 400;
155
+ opacity: 0.55;
156
+ }
157
+
158
+ .fp-thinking-body {
159
+ padding: 4px 12px 10px 12px;
160
+ font-family: monospace;
161
+ font-size: 11px;
162
+ line-height: 1.5;
163
+ color: var(--red-ui-secondary-text-color, #999);
164
+ opacity: 0.8;
165
+ white-space: pre-wrap;
166
+ max-height: 180px;
167
+ overflow-y: auto;
168
+ }
169
+
106
170
  .fp-error {
107
171
  background: rgba(255, 80, 80, 0.12);
108
172
  border-color: rgba(255, 80, 80, 0.65);
@@ -307,6 +371,81 @@
307
371
  font-size: 16px;
308
372
  }
309
373
 
374
+ /* Secondary/escape-hatch variant: muted dark background, muted text.
375
+ Same hover glow as fp-chip-card so it reads as part of the same family
376
+ without competing visually with the primary action above it. Explicit
377
+ background, not transparent — .fp-message's surrounding bubble follows
378
+ Node-RED's light editor theme variable by default, so "transparent"
379
+ showed through as plain white instead of blending into a dark parent
380
+ that doesn't actually exist. */
381
+ .fp-chip-card.fp-chip-card-alt {
382
+ background: #171e25;
383
+ border-color: #2a333c;
384
+ color: #8a96a3;
385
+ }
386
+ .fp-chip-card.fp-chip-card-alt .fp-chip-title {
387
+ color: #8a96a3;
388
+ font-weight: 500;
389
+ }
390
+ .fp-chip-card.fp-chip-card-alt:hover {
391
+ border-color: #46d39a;
392
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 0 0 1px #46d39a, 0 0 14px -2px #46d39a;
393
+ color: #dfe6ee;
394
+ }
395
+ .fp-chip-card.fp-chip-card-alt:hover .fp-chip-title {
396
+ color: #fff;
397
+ }
398
+ .fp-chip-card.fp-chip-card-alt .fp-chip-go {
399
+ color: #4a5662;
400
+ }
401
+ .fp-chip-card.fp-chip-card-alt:hover .fp-chip-go {
402
+ color: #46d39a;
403
+ }
404
+
405
+ /* WS4 build consent gate (Proceed/Skip): sits inline in a question-row,
406
+ side by side, so it stays .fp-chip-card's compact pill-shaped sibling
407
+ rather than that pattern's full-width stacked card layout. Reuses the
408
+ same cockpit accent/muted color language so both read as one family. */
409
+ .fp-consent-chip {
410
+ display: inline-flex;
411
+ align-items: center;
412
+ padding: 6px 14px;
413
+ border-radius: 999px;
414
+ font-size: 12.5px;
415
+ font-weight: 600;
416
+ cursor: pointer;
417
+ white-space: nowrap;
418
+ background: #141a21;
419
+ border: 1px solid #2c3742;
420
+ color: #dfe6ee;
421
+ transition: border-color .12s ease, box-shadow .12s ease;
422
+ }
423
+
424
+ .fp-consent-chip:hover:not(:disabled) {
425
+ border-color: #46d39a;
426
+ box-shadow: 0 0 0 1px #46d39a, 0 0 10px -2px #46d39a;
427
+ }
428
+
429
+ .fp-consent-chip:active:not(:disabled) {
430
+ transform: translateY(1px);
431
+ }
432
+
433
+ .fp-consent-chip:disabled {
434
+ cursor: default;
435
+ opacity: 0.75;
436
+ }
437
+
438
+ .fp-consent-chip-primary {
439
+ border-color: rgba(70, 211, 154, 0.35);
440
+ color: #46d39a;
441
+ }
442
+
443
+ .fp-consent-chip-alt {
444
+ background: transparent;
445
+ border-color: #2a333c;
446
+ color: #8a96a3;
447
+ }
448
+
310
449
  .fp-chip-hint {
311
450
  margin-top: 4px;
312
451
  font-size: 12px;
@@ -537,6 +676,52 @@
537
676
  justify-content: flex-end;
538
677
  }
539
678
 
679
+ /* W4 todo spine. Single-item plans render as a status line (.fp-todo-status);
680
+ multi-item plans render as a card (.fp-todo-card) with a checklist inside. */
681
+ .fp-todo-status {
682
+ display: inline-block;
683
+ font-size: 12px;
684
+ padding: 3px 10px;
685
+ margin: 0 0 4px 0;
686
+ border-radius: 12px;
687
+ max-width: 100%;
688
+ overflow: hidden;
689
+ text-overflow: ellipsis;
690
+ white-space: nowrap;
691
+ }
692
+ .fp-todo-pending, .fp-todo-active {
693
+ background: var(--red-ui-secondary-background, #eee);
694
+ color: var(--red-ui-secondary-text-color, #888);
695
+ }
696
+ .fp-todo-done {
697
+ background: rgba(34, 139, 34, 0.12);
698
+ color: #1a7a1a;
699
+ }
700
+ .fp-todo-failed {
701
+ background: rgba(200, 40, 40, 0.10);
702
+ color: #b22222;
703
+ }
704
+ .fp-todo-card {
705
+ padding: 6px 10px;
706
+ margin: 0 0 4px 0;
707
+ background: var(--red-ui-secondary-background, #eee);
708
+ border-radius: 6px;
709
+ font-size: 13px;
710
+ }
711
+ .fp-todo-list {
712
+ list-style: none;
713
+ padding: 0;
714
+ margin: 0;
715
+ }
716
+ .fp-todo-item {
717
+ padding: 1px 0;
718
+ line-height: 1.5;
719
+ }
720
+ .fp-todo-item-pending { color: var(--red-ui-secondary-text-color, #999); }
721
+ .fp-todo-item-active { font-weight: 600; color: var(--red-ui-text-color, #333); }
722
+ .fp-todo-item-done { color: #1a7a1a; }
723
+ .fp-todo-item-failed { color: #b22222; }
724
+
540
725
  .fp-json-toolbar {
541
726
  display: flex;
542
727
  justify-content: flex-end;