@manny-est/node-red-flowpilot 0.6.0-beta.1 → 0.6.0
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 +93 -13
- package/README.md +10 -1
- package/flowpilot-core.css +15 -0
- package/flowpilot-node-entry.js +15 -0
- package/flowpilot.js +215 -21
- package/lib/agent-contract.js +8 -3
- package/lib/core/history.js +151 -9
- package/lib/core/init.js +90 -21
- package/lib/core/main.js +120 -26
- package/lib/core/modes.js +222 -18
- package/lib/core/selection-context.js +17 -0
- package/lib/default-system-prompt.js +2 -2
- package/lib/document-system-prompt.js +4 -2
- package/lib/generation-system-prompt.js +2 -2
- package/lib/modify-system-prompt.js +1 -1
- package/lib/prompt-fragments.js +10 -6
- package/lib/provider-anthropic.js +12 -2
- package/lib/provider-openai-compatible.js +14 -2
- package/lib/provider-shape-check.js +1 -1
- package/lib/storage.js +6 -0
- package/package.json +3 -2
package/lib/core/history.js
CHANGED
|
@@ -4,6 +4,85 @@
|
|
|
4
4
|
// a page reload continues the same transcript; reset by clearChat()
|
|
5
5
|
// ("start a fresh conversation" gets a fresh transcript file too).
|
|
6
6
|
// ---------------------------------------------------------------------
|
|
7
|
+
var FP_CONVERSATION_ID_KEY = "fp-conversation-id";
|
|
8
|
+
var FP_RUN_MARKER_KEY = "fp-run-marker";
|
|
9
|
+
|
|
10
|
+
function flowpilotStorageLog(level, event, data) {
|
|
11
|
+
var logger = console[level] || console.log;
|
|
12
|
+
try {
|
|
13
|
+
logger.call(console, "[FlowPilot][storage] " + event, data || {});
|
|
14
|
+
} catch (e) { /* console unavailable */ }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function flowpilotSessionStorage() {
|
|
18
|
+
return window.sessionStorage;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function flowpilotStorageGet(key, reason) {
|
|
22
|
+
try {
|
|
23
|
+
var value = flowpilotSessionStorage().getItem(key);
|
|
24
|
+
flowpilotStorageLog("log", "get", {
|
|
25
|
+
key: key,
|
|
26
|
+
reason: reason || "",
|
|
27
|
+
value: value,
|
|
28
|
+
href: location.href
|
|
29
|
+
});
|
|
30
|
+
return value;
|
|
31
|
+
} catch (e) {
|
|
32
|
+
flowpilotStorageLog("warn", "get-failed", {
|
|
33
|
+
key: key,
|
|
34
|
+
reason: reason || "",
|
|
35
|
+
error: e && e.message ? e.message : String(e),
|
|
36
|
+
href: location.href
|
|
37
|
+
});
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function flowpilotStorageSet(key, value, reason) {
|
|
43
|
+
try {
|
|
44
|
+
flowpilotSessionStorage().setItem(key, value);
|
|
45
|
+
var readBack = flowpilotSessionStorage().getItem(key);
|
|
46
|
+
flowpilotStorageLog("log", "set", {
|
|
47
|
+
key: key,
|
|
48
|
+
reason: reason || "",
|
|
49
|
+
value: value,
|
|
50
|
+
readBack: readBack,
|
|
51
|
+
href: location.href
|
|
52
|
+
});
|
|
53
|
+
return true;
|
|
54
|
+
} catch (e) {
|
|
55
|
+
flowpilotStorageLog("warn", "set-failed", {
|
|
56
|
+
key: key,
|
|
57
|
+
reason: reason || "",
|
|
58
|
+
value: value,
|
|
59
|
+
error: e && e.message ? e.message : String(e),
|
|
60
|
+
href: location.href
|
|
61
|
+
});
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function flowpilotStorageRemove(key, reason) {
|
|
67
|
+
try {
|
|
68
|
+
flowpilotSessionStorage().removeItem(key);
|
|
69
|
+
flowpilotStorageLog("log", "remove", {
|
|
70
|
+
key: key,
|
|
71
|
+
reason: reason || "",
|
|
72
|
+
href: location.href
|
|
73
|
+
});
|
|
74
|
+
return true;
|
|
75
|
+
} catch (e) {
|
|
76
|
+
flowpilotStorageLog("warn", "remove-failed", {
|
|
77
|
+
key: key,
|
|
78
|
+
reason: reason || "",
|
|
79
|
+
error: e && e.message ? e.message : String(e),
|
|
80
|
+
href: location.href
|
|
81
|
+
});
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
7
86
|
function makeConversationId() {
|
|
8
87
|
if (window.crypto && typeof window.crypto.randomUUID === "function") {
|
|
9
88
|
return window.crypto.randomUUID();
|
|
@@ -13,10 +92,68 @@
|
|
|
13
92
|
|
|
14
93
|
function newConversationId() {
|
|
15
94
|
var id = makeConversationId();
|
|
16
|
-
|
|
95
|
+
flowpilotStorageSet(FP_CONVERSATION_ID_KEY, id, "newConversationId");
|
|
17
96
|
return id;
|
|
18
97
|
}
|
|
19
98
|
|
|
99
|
+
function persistConversationId(id, reason) {
|
|
100
|
+
if (!id) { return false; }
|
|
101
|
+
return flowpilotStorageSet(FP_CONVERSATION_ID_KEY, String(id), reason || "persistConversationId");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function clearConversationId(reason) {
|
|
105
|
+
return flowpilotStorageRemove(FP_CONVERSATION_ID_KEY, reason || "clearConversationId");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function readRunMarker() {
|
|
109
|
+
var raw = flowpilotStorageGet(FP_RUN_MARKER_KEY, "readRunMarker");
|
|
110
|
+
if (!raw) { return null; }
|
|
111
|
+
try {
|
|
112
|
+
return JSON.parse(raw);
|
|
113
|
+
} catch (e) {
|
|
114
|
+
flowpilotStorageLog("warn", "run-marker-parse-failed", {
|
|
115
|
+
raw: raw,
|
|
116
|
+
error: e && e.message ? e.message : String(e)
|
|
117
|
+
});
|
|
118
|
+
flowpilotStorageRemove(FP_RUN_MARKER_KEY, "invalid run marker json");
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function writeRunMarker(marker, reason) {
|
|
124
|
+
if (!marker) { return false; }
|
|
125
|
+
return flowpilotStorageSet(FP_RUN_MARKER_KEY, JSON.stringify(marker), reason || "writeRunMarker");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function clearRunMarker(reason) {
|
|
129
|
+
return flowpilotStorageRemove(FP_RUN_MARKER_KEY, reason || "clearRunMarker");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function renderInterruptedRunMessage(appliedCount) {
|
|
133
|
+
addMessage("assistant",
|
|
134
|
+
"⚠ This run was interrupted after step " + appliedCount +
|
|
135
|
+
" — completed steps are applied (Ctrl+Z to undo). Re-send to continue from here.");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function restoreInterruptedRunMarker(expectedConversationId) {
|
|
139
|
+
var marker = readRunMarker();
|
|
140
|
+
if (!marker) { return; }
|
|
141
|
+
flowpilotStorageLog("log", "restore-run-marker", {
|
|
142
|
+
marker: marker,
|
|
143
|
+
expectedConversationId: expectedConversationId || null
|
|
144
|
+
});
|
|
145
|
+
if (expectedConversationId && marker.conversationId && marker.conversationId !== expectedConversationId) {
|
|
146
|
+
flowpilotStorageLog("warn", "run-marker-conversation-mismatch", {
|
|
147
|
+
markerConversationId: marker.conversationId,
|
|
148
|
+
expectedConversationId: expectedConversationId
|
|
149
|
+
});
|
|
150
|
+
clearRunMarker("run marker conversation mismatch");
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
renderInterruptedRunMessage(Number(marker.appliedCount) || 0);
|
|
154
|
+
clearRunMarker("restored interrupted run banner");
|
|
155
|
+
}
|
|
156
|
+
|
|
20
157
|
// CLAUDE-029: whether conversationId above came from an existing
|
|
21
158
|
// sessionStorage entry (a page reload continuing a prior conversation)
|
|
22
159
|
// rather than being freshly minted — drives whether page init rehydrates
|
|
@@ -24,14 +161,19 @@
|
|
|
24
161
|
var conversationIdWasRestored = false;
|
|
25
162
|
|
|
26
163
|
var conversationId = (function () {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
164
|
+
flowpilotStorageLog("log", "conversation-id-init-enter", {
|
|
165
|
+
href: location.href,
|
|
166
|
+
readyState: document.readyState
|
|
167
|
+
});
|
|
168
|
+
var existing = flowpilotStorageGet(FP_CONVERSATION_ID_KEY, "conversationId init");
|
|
169
|
+
if (existing) {
|
|
170
|
+
conversationIdWasRestored = true;
|
|
171
|
+
flowpilotStorageLog("log", "conversation-id-restored", { conversationId: existing });
|
|
172
|
+
return existing;
|
|
173
|
+
}
|
|
174
|
+
var fresh = newConversationId();
|
|
175
|
+
flowpilotStorageLog("log", "conversation-id-created", { conversationId: fresh });
|
|
176
|
+
return fresh;
|
|
35
177
|
})();
|
|
36
178
|
|
|
37
179
|
// ---------------------------------------------------------------------
|
package/lib/core/init.js
CHANGED
|
@@ -14,18 +14,20 @@
|
|
|
14
14
|
"- `/generate` — arm Generate mode\n" +
|
|
15
15
|
"- `/document` — arm Document mode\n" +
|
|
16
16
|
"- `/modify` — arm Modify mode\n" +
|
|
17
|
-
"- `/query` — back to Query (disarm)\n" +
|
|
17
|
+
"- `/query` / `/chat` — back to Query (disarm)\n" +
|
|
18
18
|
"- `/clear` — start a fresh conversation (clears chat and memory)\n" +
|
|
19
19
|
"- `/history` — open the Flight log (past conversations)\n" +
|
|
20
20
|
"- `/settings` — open the Hangar (providers, behavior, safety)\n\n" +
|
|
21
21
|
"Typing a shortcut with extra text, e.g. `/modify add a debug node`, switches mode and leaves the rest in the box so you can review before sending.\n\n" +
|
|
22
22
|
"- `/demo` — load a sample Generate request (a dad joke flow) into the compose box\n" +
|
|
23
23
|
"- `/feedback` — bug report / feature request info\n" +
|
|
24
|
+
"- `/beta` — beta-channel install/revert instructions\n" +
|
|
24
25
|
"- `/build` — describe a goal; I'll plan, propose, and walk an iterative build → deploy → debug → review → fix loop with you\n" +
|
|
25
26
|
"- `/compact` — hide labels on the selected node(s) (icon-only); `/expand` restores them. Instant, no AI involved — one Ctrl+Z undoes it.\n" +
|
|
26
27
|
"- `/disable` — disable the selected node(s) (skipped on Deploy); `/enable` re-enables them. Instant, no AI involved — one Ctrl+Z undoes it.\n" +
|
|
27
28
|
"- `/refresh` — re-render all messages from the in-memory record store (restores interactive Apply buttons if they were lost).\n" +
|
|
28
29
|
"- `/debug` — toggle debug logging (full prompts/replies/decisions to `flowpilot/debug.log`) on/off. Instant, no AI involved.\n\n" +
|
|
30
|
+
"- `/summarize` — summarize older chat history into one compact note, keeping the latest two exchanges intact.\n\n" +
|
|
29
31
|
"### Also worth knowing\n\n" +
|
|
30
32
|
"- Action chips (paper-plane buttons) offer a one-click follow-up — review and send, nothing fires automatically.\n" +
|
|
31
33
|
"- When I ask a clarifying question, I'll often offer quick-reply buttons (plus \"Other\" for your own answer) — clicking one sends it right away.\n" +
|
|
@@ -43,11 +45,30 @@
|
|
|
43
45
|
"human crew reads every report.\n\n" +
|
|
44
46
|
"- **Report an issue**: https://github.com/manny-est/flowpilot/issues\n" +
|
|
45
47
|
"- **Browse the repo**: https://github.com/manny-est/flowpilot\n\n" +
|
|
46
|
-
"A good report travels light but packs the essentials: your
|
|
47
|
-
"version
|
|
48
|
-
"reproduce. That's usually enough
|
|
48
|
+
"A good report travels light but packs the essentials: your FlowPilot " +
|
|
49
|
+
"version (top of Settings), your Node-RED version, the provider/model " +
|
|
50
|
+
"you're flying with, and the steps to reproduce. That's usually enough " +
|
|
51
|
+
"to get a fix off the ground.\n\n" +
|
|
49
52
|
"Safe travels.";
|
|
50
53
|
|
|
54
|
+
var BETA_TEXT = "## Beta channel\n\n" +
|
|
55
|
+
"Thanks for testing FlowPilot on the beta track.\n\n" +
|
|
56
|
+
"**Install the beta:**\n" +
|
|
57
|
+
"```\n" +
|
|
58
|
+
"cd ~/.node-red (or your mounted Node-RED data dir, e.g. /data in Docker)\n" +
|
|
59
|
+
"npm install @manny-est/node-red-flowpilot@beta\n" +
|
|
60
|
+
"```\n" +
|
|
61
|
+
"Then **restart Node-RED** (or the container) — a browser refresh alone " +
|
|
62
|
+
"won't pick it up; FlowPilot's editor UI is cached server-side.\n\n" +
|
|
63
|
+
"**Revert to stable:**\n" +
|
|
64
|
+
"```\n" +
|
|
65
|
+
"cd ~/.node-red (or /data)\n" +
|
|
66
|
+
"npm install @manny-est/node-red-flowpilot@latest\n" +
|
|
67
|
+
"```\n" +
|
|
68
|
+
"Restart again afterward.\n\n" +
|
|
69
|
+
"**Found a bug?** Type `/feedback`, or go straight to " +
|
|
70
|
+
"https://github.com/manny-est/flowpilot/issues — every report helps.";
|
|
71
|
+
|
|
51
72
|
var demoTypeTimer = null;
|
|
52
73
|
|
|
53
74
|
// Registry of all slash commands — drives the autocomplete panel that
|
|
@@ -60,15 +81,20 @@
|
|
|
60
81
|
{ cmd: "/build", desc: "Start a deploy-verify build loop" },
|
|
61
82
|
{ cmd: "/chat", desc: "Switch to Chat mode" },
|
|
62
83
|
{ cmd: "/query", desc: "Add or toggle a Query intent" },
|
|
84
|
+
{ cmd: "/clear", desc: "Start a fresh conversation" },
|
|
85
|
+
{ cmd: "/history", desc: "Open past conversations" },
|
|
86
|
+
{ cmd: "/settings", desc: "Open provider/behavior settings" },
|
|
63
87
|
{ cmd: "/compact", desc: "Compact labels on selected nodes" },
|
|
64
88
|
{ cmd: "/expand", desc: "Expand labels on selected nodes" },
|
|
65
89
|
{ cmd: "/disable", desc: "Disable selected nodes" },
|
|
66
90
|
{ cmd: "/enable", desc: "Enable selected nodes" },
|
|
67
91
|
{ cmd: "/refresh", desc: "Re-render all messages from shadow record store" },
|
|
68
92
|
{ cmd: "/debug", desc: "Toggle debug logging on/off" },
|
|
93
|
+
{ cmd: "/summarize", desc: "Summarize older history into a compact note" },
|
|
69
94
|
{ cmd: "/demo", desc: "Type in a demo prompt" },
|
|
70
95
|
{ cmd: "/help", desc: "Show all available commands" },
|
|
71
|
-
{ cmd: "/feedback", desc: "Show feedback info" }
|
|
96
|
+
{ cmd: "/feedback", desc: "Show feedback info" },
|
|
97
|
+
{ cmd: "/beta", desc: "Beta install/revert instructions" }
|
|
72
98
|
];
|
|
73
99
|
|
|
74
100
|
function bindSlashAutocomplete($promptBox) {
|
|
@@ -235,6 +261,10 @@
|
|
|
235
261
|
addMessage("assistant", FEEDBACK_TEXT);
|
|
236
262
|
if ($promptBox.length) { $promptBox.val(""); }
|
|
237
263
|
break;
|
|
264
|
+
case "/beta":
|
|
265
|
+
addMessage("assistant", BETA_TEXT);
|
|
266
|
+
if ($promptBox.length) { $promptBox.val(""); }
|
|
267
|
+
break;
|
|
238
268
|
case "/refresh":
|
|
239
269
|
refreshView();
|
|
240
270
|
if ($promptBox.length) { $promptBox.val(""); }
|
|
@@ -250,6 +280,10 @@
|
|
|
250
280
|
});
|
|
251
281
|
if ($promptBox.length) { $promptBox.val(""); }
|
|
252
282
|
break;
|
|
283
|
+
case "/summarize":
|
|
284
|
+
summarizeConversationHistory();
|
|
285
|
+
if ($promptBox.length) { $promptBox.val(""); }
|
|
286
|
+
break;
|
|
253
287
|
// Deterministic, no LLM round-trip: just invokes Node-RED's own
|
|
254
288
|
// native "show/hide selected node labels" action (RED.actions
|
|
255
289
|
// "core:show-selected-node-labels" / "core:hide-selected-node-
|
|
@@ -800,6 +834,7 @@
|
|
|
800
834
|
' <div class="fp-status-strip">' +
|
|
801
835
|
' <span id="fp-selection-status" class="fp-selection-status">No nodes selected</span>' +
|
|
802
836
|
' <a href="#" id="fp-preview-nodes" class="fp-preview-link fp-hidden" title="Open this from the main window to see the exact sanitized node JSON">Preview JSON</a>' +
|
|
837
|
+
' <span id="fp-dev-warning-status" class="fp-secrets-status" title="Development/test only. Anything you send may leave this Node-RED instance. Don\'t include credentials or proprietary data; local/private AI recommended.">⚠</span>' +
|
|
803
838
|
' <span id="fp-size-status" class="fp-size-status fp-hidden"></span>' +
|
|
804
839
|
' <span id="fp-secrets-status" class="fp-secrets-status fp-hidden" title="Context may include node config and code. Don\'t send credentials or proprietary data. Local/private AI recommended.">⚠</span>' +
|
|
805
840
|
' <span id="fp-debug-status" class="fp-debug-status fp-hidden"></span>' +
|
|
@@ -961,7 +996,7 @@
|
|
|
961
996
|
} else if (data.event === "conversationList") {
|
|
962
997
|
renderHistoryList(data.conversations || []);
|
|
963
998
|
} else if (data.event === "settingsLoaded") {
|
|
964
|
-
fillSettings(data.settings);
|
|
999
|
+
fillSettings(data.settings, "popout settingsLoaded relay");
|
|
965
1000
|
renderIntents(el("#fp-intents"));
|
|
966
1001
|
updateSelectionStatus();
|
|
967
1002
|
}
|
|
@@ -1004,11 +1039,7 @@
|
|
|
1004
1039
|
' </div>' +
|
|
1005
1040
|
|
|
1006
1041
|
' <div id="fp-chat-panel" class="fp-panel">' +
|
|
1007
|
-
' <div id="fp-
|
|
1008
|
-
' <strong>Development/test only.</strong> ' +
|
|
1009
|
-
' Anything you send may leave this Node-RED instance. ' +
|
|
1010
|
-
' Don\'t include credentials or proprietary data; local/private AI recommended.' +
|
|
1011
|
-
' </div>' +
|
|
1042
|
+
' <div id="fp-update-banner" class="fp-warning fp-hidden"></div>' +
|
|
1012
1043
|
' <div id="fp-messages" class="fp-messages"></div>' +
|
|
1013
1044
|
' <div class="fp-compose">' +
|
|
1014
1045
|
' <div class="fp-action-bar">' +
|
|
@@ -1031,6 +1062,7 @@
|
|
|
1031
1062
|
' <div class="fp-status-strip">' +
|
|
1032
1063
|
' <span id="fp-selection-status" class="fp-selection-status">No nodes selected</span>' +
|
|
1033
1064
|
' <a href="#" id="fp-preview-nodes" class="fp-preview-link fp-hidden" title="Show the exact sanitized node JSON that will be sent">Preview JSON</a>' +
|
|
1065
|
+
' <span id="fp-dev-warning-status" class="fp-secrets-status" title="Development/test only. Anything you send may leave this Node-RED instance. Don\'t include credentials or proprietary data; local/private AI recommended.">⚠</span>' +
|
|
1034
1066
|
' <span id="fp-size-status" class="fp-size-status fp-hidden"></span>' +
|
|
1035
1067
|
' <span id="fp-secrets-status" class="fp-secrets-status fp-hidden" title="Context may include node config and code. Don\'t send credentials or proprietary data. Local/private AI recommended.">⚠</span>' +
|
|
1036
1068
|
' <span id="fp-debug-status" class="fp-debug-status fp-hidden"></span>' +
|
|
@@ -1044,6 +1076,7 @@
|
|
|
1044
1076
|
|
|
1045
1077
|
' <div id="fp-settings-panel" class="fp-panel fp-hidden">' +
|
|
1046
1078
|
' <div class="fp-form">' +
|
|
1079
|
+
' <div id="fp-flowpilot-version" class="fp-consent-hint"></div>' +
|
|
1047
1080
|
|
|
1048
1081
|
' <details class="fp-settings-group" open>' +
|
|
1049
1082
|
' <summary title="Hangar — where your AI providers are configured">Providers</summary>' +
|
|
@@ -1073,6 +1106,11 @@
|
|
|
1073
1106
|
' <input id="fp-model" type="text" list="fp-model-options" placeholder="Model name for this provider">' +
|
|
1074
1107
|
' <datalist id="fp-model-options"></datalist>' +
|
|
1075
1108
|
' <div id="fp-models-hint" class="fp-consent-hint fp-hidden"></div>' +
|
|
1109
|
+
' <label>Context window (tokens, optional)</label>' +
|
|
1110
|
+
' <input id="fp-num-ctx" type="number" min="0" step="1" placeholder="0 = unknown">' +
|
|
1111
|
+
' <div class="fp-consent-hint">If this provider/model has a known context window ' +
|
|
1112
|
+
' (e.g. 128000, 250000 — check the provider’s own docs), set it here so FlowPilot ' +
|
|
1113
|
+
' can warn before a request would overflow it. Leave at 0 if unknown.</div>' +
|
|
1076
1114
|
' <label>Temperature</label>' +
|
|
1077
1115
|
' <input id="fp-temperature" type="number" min="0" max="2" step="0.1" placeholder="0.2">' +
|
|
1078
1116
|
' <div class="fp-consent-hint">Controls randomness. Lower (e.g. 0.2) is more ' +
|
|
@@ -1125,10 +1163,26 @@
|
|
|
1125
1163
|
' <div class="fp-consent-hint">How long to wait for a provider response before ' +
|
|
1126
1164
|
' giving up. Raise this if you\'re running a large local model on slow hardware ' +
|
|
1127
1165
|
' (e.g. Ollama without a GPU) and seeing timeout errors.</div>' +
|
|
1128
|
-
' <
|
|
1166
|
+
' <div class="fp-settings-section">Updates</div>' +
|
|
1167
|
+
' <label class="fp-checkbox-row">' +
|
|
1168
|
+
' <input id="fp-check-for-updates" type="checkbox"> ' +
|
|
1169
|
+
' Check for FlowPilot updates' +
|
|
1170
|
+
' </label>' +
|
|
1171
|
+
' <div class="fp-consent-hint">On by default. Periodically checks npm for a newer ' +
|
|
1172
|
+
' FlowPilot version on your current track (beta or stable) and shows a small ' +
|
|
1173
|
+
' banner if one is available. Uncheck to disable this entirely; no network ' +
|
|
1174
|
+
' request is made when off.</div>' +
|
|
1175
|
+
' <label>Max tokens per model response (agent step)</label>' +
|
|
1129
1176
|
' <input id="fp-agent-turn-max-tokens" type="number" min="1" max="65536" step="1" placeholder="4096">' +
|
|
1130
|
-
' <div class="fp-consent-hint">Hard output limit for
|
|
1131
|
-
' Classic (no-tools) requests are not capped.</div>' +
|
|
1177
|
+
' <div class="fp-consent-hint">Hard output limit for EACH individual tool-calling ' +
|
|
1178
|
+
' step’s model response. Classic (no-tools) requests are not capped.</div>' +
|
|
1179
|
+
' <label>Max total tokens per agent turn</label>' +
|
|
1180
|
+
' <input id="fp-agent-loop-token-ceiling" type="number" min="1" step="1" placeholder="50000">' +
|
|
1181
|
+
' <div class="fp-consent-hint">Cumulative token budget (prompt + response, summed ' +
|
|
1182
|
+
' across every step) for one multi-step agent turn before FlowPilot stops with an ' +
|
|
1183
|
+
' error instead of continuing. This is the number that appears in the "FlowPilot ' +
|
|
1184
|
+
' stopped after using N tokens" error — raise it here if you’re hitting that message ' +
|
|
1185
|
+
' on a model with a large context window.</div>' +
|
|
1132
1186
|
|
|
1133
1187
|
' <div class="fp-settings-section">Agentic build loop</div>' +
|
|
1134
1188
|
' <label>Max build/fix attempts</label>' +
|
|
@@ -1168,12 +1222,10 @@
|
|
|
1168
1222
|
' <div class="fp-settings-section">Risk warnings</div>' +
|
|
1169
1223
|
' <label class="fp-checkbox-row">' +
|
|
1170
1224
|
' <input id="fp-suppress-warnings" type="checkbox"> ' +
|
|
1171
|
-
' Hide the recurring credentials/size warning
|
|
1225
|
+
' Hide the recurring credentials/size warning' +
|
|
1172
1226
|
' </label>' +
|
|
1173
|
-
' <div class="fp-consent-hint">
|
|
1174
|
-
'
|
|
1175
|
-
' Anything you send may leave this Node-RED instance.</div>' +
|
|
1176
|
-
' <input id="fp-suppress-confirm" type="text" placeholder="Type: I understand the risk">' +
|
|
1227
|
+
' <div class="fp-consent-hint">Anything you send may leave this Node-RED ' +
|
|
1228
|
+
' instance. Check this box to hide the warning indicator near Send.</div>' +
|
|
1177
1229
|
|
|
1178
1230
|
' <div class="fp-settings-section">Redaction</div>' +
|
|
1179
1231
|
' <label class="fp-checkbox-row">' +
|
|
@@ -1547,6 +1599,7 @@
|
|
|
1547
1599
|
});
|
|
1548
1600
|
|
|
1549
1601
|
loadSettings();
|
|
1602
|
+
checkForFlowPilotUpdates();
|
|
1550
1603
|
updateSelectionStatus();
|
|
1551
1604
|
showChat();
|
|
1552
1605
|
rehydrateConversationOnLoad();
|
|
@@ -1561,6 +1614,11 @@
|
|
|
1561
1614
|
// render path the History panel's click handler uses) so there is no
|
|
1562
1615
|
// second copy of the message-rendering logic to drift out of sync.
|
|
1563
1616
|
function rehydrateConversationOnLoad() {
|
|
1617
|
+
flowpilotStorageLog("log", "rehydrateConversationOnLoad-enter", {
|
|
1618
|
+
conversationIdWasRestored: conversationIdWasRestored,
|
|
1619
|
+
conversationId: conversationId,
|
|
1620
|
+
href: location.href
|
|
1621
|
+
});
|
|
1564
1622
|
if (!conversationIdWasRestored) { return; }
|
|
1565
1623
|
loadConversation(conversationId, function (msg, xhr) {
|
|
1566
1624
|
// Conversation no longer exists server-side (404) — the
|
|
@@ -1569,10 +1627,21 @@
|
|
|
1569
1627
|
// failure (network hiccup, etc.) leaves it in place in case it
|
|
1570
1628
|
// was transient. Either way: stay quiet, Chat simply stays
|
|
1571
1629
|
// empty exactly as it does today — no error bubble on load.
|
|
1630
|
+
flowpilotStorageLog("warn", "rehydrateConversationOnLoad-error", {
|
|
1631
|
+
conversationId: conversationId,
|
|
1632
|
+
status: xhr && xhr.status,
|
|
1633
|
+
message: msg
|
|
1634
|
+
});
|
|
1572
1635
|
if (xhr && xhr.status === 404) {
|
|
1573
|
-
|
|
1636
|
+
clearConversationId("rehydrate 404");
|
|
1637
|
+
clearRunMarker("rehydrate 404");
|
|
1574
1638
|
}
|
|
1575
|
-
})
|
|
1639
|
+
}, function () {
|
|
1640
|
+
flowpilotStorageLog("log", "rehydrateConversationOnLoad-success", {
|
|
1641
|
+
conversationId: conversationId
|
|
1642
|
+
});
|
|
1643
|
+
restoreInterruptedRunMarker(conversationId);
|
|
1644
|
+
}, { preserveRunMarker: true });
|
|
1576
1645
|
}
|
|
1577
1646
|
|
|
1578
1647
|
window.FlowPilotCore = { initMainWindow: initMainWindow, initPopout: initPopout };
|