langflower 0.0.9 → 0.0.10

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.
Files changed (91) hide show
  1. package/package.json +2 -2
  2. package/ui-dist/index.html +2 -2
  3. package/ui-dist/main-Z7CPFXFA.js +313 -0
  4. package/ui-dist/styles-2TMDAUD7.css +1 -0
  5. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-reducer.js +0 -12
  6. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.d.ts +2 -7
  7. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.js +1 -1
  8. package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.d.ts +0 -3
  9. package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.js +22 -36
  10. package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.d.ts +1 -7
  11. package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.js +12 -35
  12. package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.d.ts +3 -10
  13. package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.js +9 -14
  14. package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.d.ts +0 -3
  15. package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.js +2 -15
  16. package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.d.ts +1 -0
  17. package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.js +1 -0
  18. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.d.ts +1 -1
  19. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.js +1 -1
  20. package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.d.ts +1 -0
  21. package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.js +1 -0
  22. package/vendor/common-nodes/dist/ai/nodes/critique/node.d.ts +3 -3
  23. package/vendor/common-nodes/dist/ai/nodes/critique/node.js +5 -18
  24. package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.d.ts +3 -3
  25. package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.js +3 -10
  26. package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.d.ts +3 -3
  27. package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.js +2 -9
  28. package/vendor/common-nodes/dist/ai/nodes/review/node.d.ts +3 -3
  29. package/vendor/common-nodes/dist/ai/nodes/review/node.js +5 -18
  30. package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.d.ts +5 -5
  31. package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.js +211 -96
  32. package/vendor/common-nodes/dist/catalog.js +2 -0
  33. package/vendor/common-nodes/dist/mcp/mcp-http/node.d.ts +4 -4
  34. package/vendor/common-nodes/dist/mcp/mcp-http/node.js +9 -10
  35. package/vendor/common-nodes/dist/mcp/mcp-stdio/node.d.ts +4 -4
  36. package/vendor/common-nodes/dist/mcp/mcp-stdio/node.js +9 -10
  37. package/vendor/common-nodes/dist/tools/collect-agent-tool-handles.d.ts +4 -4
  38. package/vendor/common-nodes/dist/tools/collect-agent-tool-handles.js +3 -11
  39. package/vendor/common-nodes/dist/tools/inventory-tool-round.d.ts +0 -10
  40. package/vendor/common-nodes/dist/tools/inventory-tool-round.js +0 -84
  41. package/vendor/common-nodes/dist/tools/tool-collection/node.d.ts +20 -0
  42. package/vendor/common-nodes/dist/tools/tool-collection/node.js +42 -0
  43. package/vendor/common-nodes/package.json +1 -5
  44. package/vendor/compiler/package.json +1 -1
  45. package/vendor/node-sdk/dist/node-factory/define-llm-node/default-llm-ports.d.ts +3 -7
  46. package/vendor/node-sdk/dist/node-factory/define-llm-node/default-llm-ports.js +4 -44
  47. package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.d.ts +3 -5
  48. package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.js +3 -5
  49. package/vendor/node-sdk/dist/node-factory/define-llm-node/llm-inventory-wire.d.ts +1 -0
  50. package/vendor/node-sdk/dist/node-factory/define-llm-node/llm-inventory-wire.js +1 -0
  51. package/vendor/node-sdk/dist/node-factory/define-mcp/mcp-handle.d.ts +3 -4
  52. package/vendor/node-sdk/dist/node-factory/define-mcp/mcp-handle.js +1 -1
  53. package/vendor/node-sdk/dist/node-factory/define-reactive-node/types.d.ts +2 -4
  54. package/vendor/node-sdk/dist/node-factory/define-reactive-node/ui-schema-inference.d.ts +1 -1
  55. package/vendor/node-sdk/package.json +1 -1
  56. package/vendor/runtime/dist/port-feed-override.d.ts +13 -0
  57. package/vendor/runtime/dist/port-feed-override.js +21 -0
  58. package/vendor/runtime/dist/port-signal-from-response.d.ts +15 -0
  59. package/vendor/runtime/dist/port-signal-from-response.js +48 -0
  60. package/vendor/runtime/dist/runtime-runner.d.ts +8 -3
  61. package/vendor/runtime/dist/runtime-runner.js +102 -81
  62. package/vendor/runtime/dist/runtime.d.ts +3 -2
  63. package/vendor/runtime/dist/runtime.js +1 -1
  64. package/vendor/runtime/dist/testing/workflows/workflow-events.d.ts +2 -0
  65. package/vendor/runtime/dist/testing/workflows/workflow-events.js +7 -5
  66. package/vendor/runtime/dist/types.d.ts +25 -8
  67. package/vendor/runtime/dist/types.js +3 -0
  68. package/vendor/runtime/package.json +1 -1
  69. package/vendor/server/dist/bridge/build-execution-context.js +3 -3
  70. package/vendor/server/dist/bridge/get-live-wired-tools.d.ts +3 -2
  71. package/vendor/server/dist/bridge/get-live-wired-tools.js +8 -5
  72. package/vendor/server/dist/bridge/wire-runner-handlers.js +2 -2
  73. package/vendor/server/dist/bridge/wire-workflow-handlers.js +23 -9
  74. package/vendor/server/dist/checkpoint/run-checkpoint-session.js +3 -3
  75. package/vendor/server/dist/session/reset-session-execution-feed.d.ts +6 -0
  76. package/vendor/server/dist/session/reset-session-execution-feed.js +8 -0
  77. package/vendor/server/skeleton/nodes/my-nodes/package.json +1 -1
  78. package/vendor/server/skeleton/skills/langflower-helper/SKILL.md +36 -22
  79. package/vendor/server/skeleton/skills/langflower-helper/architecture.md +7 -1
  80. package/vendor/server/skeleton/skills/langflower-helper/layout.md +3 -2
  81. package/vendor/server/skeleton/skills/langflower-workflow-writer/SKILL.md +12 -8
  82. package/vendor/server/skeleton/workflows/kb-create.json +15 -43
  83. package/vendor/server/skeleton/workflows/kb-navigate.json +8 -22
  84. package/vendor/server/skeleton/workflows/simple-coder.json +18 -46
  85. package/vendor/server/skeleton/workflows/starter.json +8 -22
  86. package/vendor/shared/dist/execution/derive-run-settle-outcome.js +2 -2
  87. package/vendor/shared/dist/execution/derive-run-settle-outcome.test.js +11 -8
  88. package/vendor/shared/dist/langflower-ws-waits.d.ts +3 -1
  89. package/vendor/shared/dist/langflower-ws-waits.js +2 -2
  90. package/ui-dist/main-2JJGCNTD.js +0 -313
  91. package/ui-dist/styles-EOXODOI7.css +0 -1
@@ -1,6 +1,7 @@
1
1
  import { Subscription } from 'rxjs';
2
2
  import { listResumableCheckpoints } from '../checkpoint/list-resumable-checkpoints.js';
3
3
  import { WorkflowCheckpointStore } from '../checkpoint/workflow-checkpoint-store.js';
4
+ import { resetSessionExecutionFeed } from '../session/reset-session-execution-feed.js';
4
5
  import { buildSaveCurrentPayload } from '../workflow/build-save-current-payload.js';
5
6
  import { copyWorkflowToSession } from '../workflow/copy-workflow-to-session.js';
6
7
  import { createEmptyWorkflowInSession } from '../workflow/create-empty-workflow-in-session.js';
@@ -10,11 +11,17 @@ import { bridgeEmit, clientEmit } from './bridge-outbound.js';
10
11
  import { findClientById } from './client-index.js';
11
12
  import { isInboundEvent } from './inbound-guards.js';
12
13
  /**
13
- * Composer: clear selection → current snapshot → optional catalog sync.
14
- * Sibling steps — handlers do not call these in nested order themselves.
14
+ * Composer: optional feed reset → clear selection → current snapshot →
15
+ * optional catalog sync. Sibling steps — handlers do not nest these.
15
16
  */
16
17
  const syncAfterWorkflowMutation = async (bridge, context, session, client, options) => {
17
- // 1. Clear selection (and notify tabs if it was set)
18
+ // 1. Document switch: empty feed before the new catalog so the UI never
19
+ // paints the previous run under the next workflow's nodes.
20
+ if (options.resetFeed === true) {
21
+ resetSessionExecutionFeed(session);
22
+ bridgeEmit(bridge, 'executionFeed.snapshot', session.buildExecutionFeed());
23
+ }
24
+ // 2. Clear selection (and notify tabs if it was set)
18
25
  if (options.clearSelection) {
19
26
  const hadSelection = session.selectedNodeId !== null;
20
27
  session.selectedNodeId = null;
@@ -22,19 +29,19 @@ const syncAfterWorkflowMutation = async (bridge, context, session, client, optio
22
29
  bridgeEmit(bridge, 'editor.nodeSelected', { node: null });
23
30
  }
24
31
  }
25
- // 2. Authoritative current-workflow slice (session-shared — fan out)
32
+ // 3. Authoritative current-workflow slice (session-shared — fan out)
26
33
  bridgeEmit(bridge, 'workflow.current.snapshot', {
27
34
  activeWorkflow: session.activeWorkflow,
28
35
  currentStatus: { status: session.currentStatus },
29
36
  });
30
- // 3. Resumable checkpoints for the active workflow (explicit boundaries)
37
+ // 4. Resumable checkpoints for the active workflow (explicit boundaries)
31
38
  const workflowId = session.activeWorkflowId ?? null;
32
39
  const checkpoints = await listResumableCheckpoints(new WorkflowCheckpointStore(context.projectDir), workflowId, session.activeWorkflow);
33
40
  bridgeEmit(bridge, 'runner.checkpoints.snapshot', {
34
41
  workflowId,
35
42
  checkpoints,
36
43
  });
37
- // 4. Catalog sync
44
+ // 5. Catalog sync
38
45
  if (options.catalog.kind === 'broadcast') {
39
46
  const workflows = await context.workflowService.list();
40
47
  bridgeEmit(bridge, 'workflow.list.snapshot', { workflows });
@@ -67,11 +74,13 @@ export const wireWorkflowHandlers = (bridge, context, session) => {
67
74
  return;
68
75
  }
69
76
  let clearSelection = false;
77
+ let resetFeed = false;
70
78
  if (!session.isGraphLocked()) {
71
79
  // 1. Load document into session
72
80
  const loaded = await loadWorkflowIntoSession(session, context.workflowService, context.projectDir, raw.payload.workflowId, context.resolveDefinition);
73
81
  // 2. Persist current-workflow id when load succeeded
74
82
  if (loaded.ok) {
83
+ resetFeed = true;
75
84
  await context.langflowerConfigService.setCurrentWorkflowId(raw.payload.workflowId);
76
85
  if (loaded.repaired) {
77
86
  const nodeCount = loaded.droppedNodeIds.length;
@@ -101,7 +110,7 @@ export const wireWorkflowHandlers = (bridge, context, session) => {
101
110
  });
102
111
  }
103
112
  // 3. Sync outbound
104
- await syncAfterWorkflowMutation(bridge, context, session, connected, { clearSelection, catalog: { kind: 'none' } });
113
+ await syncAfterWorkflowMutation(bridge, context, session, connected, { clearSelection, catalog: { kind: 'none' }, resetFeed });
105
114
  }));
106
115
  subscription.add(bridge['workflow.saveCurrent.requested'].subscribe(async (raw) => {
107
116
  if (!isInboundEvent(raw)) {
@@ -163,11 +172,13 @@ export const wireWorkflowHandlers = (bridge, context, session) => {
163
172
  return;
164
173
  }
165
174
  let clearSelection = false;
175
+ let resetFeed = false;
166
176
  if (!session.isGraphLocked()) {
167
- await createEmptyWorkflowInSession(session, context.workflowService, context.projectDir, context.resolveDefinition);
177
+ const created = await createEmptyWorkflowInSession(session, context.workflowService, context.projectDir, context.resolveDefinition);
168
178
  clearSelection = true;
179
+ resetFeed = created;
169
180
  }
170
- await syncAfterWorkflowMutation(bridge, context, session, connected, { clearSelection, catalog: { kind: 'none' } });
181
+ await syncAfterWorkflowMutation(bridge, context, session, connected, { clearSelection, catalog: { kind: 'none' }, resetFeed });
171
182
  }));
172
183
  subscription.add(bridge['workflow.copy.requested'].subscribe(async (raw) => {
173
184
  if (!isInboundEvent(raw)) {
@@ -179,16 +190,19 @@ export const wireWorkflowHandlers = (bridge, context, session) => {
179
190
  }
180
191
  let catalogChanged = false;
181
192
  let clearSelection = false;
193
+ let resetFeed = false;
182
194
  if (!session.isGraphLocked()) {
183
195
  const copied = await copyWorkflowToSession(session, context.workflowService, context.projectDir, raw.payload.workflowId, context.resolveDefinition);
184
196
  if (copied && session.activeWorkflowId !== undefined) {
185
197
  catalogChanged = true;
198
+ resetFeed = true;
186
199
  await context.langflowerConfigService.setCurrentWorkflowId(session.activeWorkflowId);
187
200
  }
188
201
  clearSelection = true;
189
202
  }
190
203
  await syncAfterWorkflowMutation(bridge, context, session, connected, {
191
204
  clearSelection,
205
+ resetFeed,
192
206
  catalog: catalogChanged
193
207
  ? { kind: 'broadcast' }
194
208
  : { kind: 'none' },
@@ -62,11 +62,11 @@ export class RunCheckpointSession {
62
62
  event[0] !== 'out') {
63
63
  return false;
64
64
  }
65
- const [, nodeIdRaw, portId, state, value] = event;
66
- if (state !== 'value' || typeof portId !== 'string') {
65
+ const [, nodeIdRaw, portId, response] = event;
66
+ if (!('value' in response) || typeof portId !== 'string') {
67
67
  return false;
68
68
  }
69
- const jsonValue = toCheckpointJsonValue(value);
69
+ const jsonValue = toCheckpointJsonValue(response.value);
70
70
  if (jsonValue === undefined) {
71
71
  this.unsupportedValue = `${String(nodeIdRaw)}.${portId}`;
72
72
  return false;
@@ -0,0 +1,6 @@
1
+ import type { LangflowerSession } from './langflower-session.js';
2
+ /**
3
+ * Drop the session run log so `buildExecutionFeed()` returns null.
4
+ * Call only when the runner is idle (document switch or user Clear).
5
+ */
6
+ export declare const resetSessionExecutionFeed: (session: LangflowerSession) => void;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Drop the session run log so `buildExecutionFeed()` returns null.
3
+ * Call only when the runner is idle (document switch or user Clear).
4
+ */
5
+ export const resetSessionExecutionFeed = (session) => {
6
+ session.runtime.runner.clearEventLog();
7
+ session.runId = undefined;
8
+ };
@@ -5,7 +5,7 @@
5
5
  "type": "module",
6
6
  "peerDependencies": {
7
7
  "@langflower/node-sdk": "0.1.0",
8
- "@rx-evo/stateful-observable": "^0.5.2",
8
+ "@rx-evo/stateful-observable": "^0.6.0",
9
9
  "rxjs": "^7.8.1"
10
10
  }
11
11
  }
@@ -116,7 +116,11 @@ do not say coding pipelines “don’t exist” or are unavailable.
116
116
  - **Can:** Chat Input graphs start from the composer **Start** control. Plain
117
117
  **Run** stays disabled for those graphs.
118
118
  - **Can:** While running — Hard **Stop**, soft **Pause**, HITL and
119
- `permission.ask` in the composer.
119
+ `permission.ask` in the composer. Work log **clears** on successful
120
+ workflow load / create / copy (not rename).
121
+ - **Cannot:** Switch, rename, delete, copy, or create a workflow while a run
122
+ is active — Stop first. Same lock: inspector / canvas inline / palette
123
+ drag (`cursor-not-allowed`).
120
124
  - **Cannot:** Tell users to press plain **Run** to start a Chat Input graph.
121
125
  - **Cannot:** Claim the feed after reload must be **richer** than live.
122
126
  - **Cannot:** Claim `basic-coder` proves chat-dense mood for the full
@@ -132,16 +136,16 @@ do not say coding pipelines “don’t exist” or are unavailable.
132
136
 
133
137
  ### 6. Coding workflows
134
138
 
135
- | Name | Fact |
136
- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
137
- | `starter` | Onboarding chat + this skill + Writer Sub-Agent (`langflower-workflow-writer` + `langflower-node-writer`) — default open after seed |
138
- | Skeleton stubs | `simple-coder`, `advanced-coder`, `kb-create`, `kb-navigate`, … seeded on first-run; with provider → Start |
139
- | `simple-coder` | Plan⇄HITL→Coder⇄HITL→Finish smoke spine + `common-memory-tools` on Plan/Coder/Researcher/Worker; Researcher Sub-Agent under Plan, Worker under Coder — **not** full multi-loop `coding-agent` |
140
- | `kb-create` | Memory / project wiki create: Orchestrator **indexes** the repo with `glob`/`read`, persists `history/work-queue.md`, then **serially** spawns Explorer → Composer **one unit at a time**; `common-memory-tools` writes `core/*` + `modules/*`; Review rejects non-empty Pending or thin overviews |
141
- | `kb-navigate` | Memory navigate: Navigator + Searcher + memory tree/grep/section tools; HITL Review Gate for follow-ups |
142
- | `basic-coder` | Basic coding harness (Plan⇄HITL→Coder⇄HITL→Finish) — not a toy, **not** full multi-loop `coding-agent` |
143
- | `coding-agent` | Clarify HITL → red team → plan gate → coder → QA → `common-review` → result HITL; **graph** orders stages |
144
- | Status | Use-case **Partial**; real-LLM Implementable bar open; Fake CI ≠ end-user proof — **not** “no templates” |
139
+ | Name | Fact |
140
+ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
141
+ | `starter` | Onboarding chat + this skill + Writer Sub-Agent (`langflower-workflow-writer` + `langflower-node-writer`) — default open after seed |
142
+ | Skeleton stubs | `simple-coder`, `advanced-coder`, `kb-create`, `kb-navigate`, … seeded on first-run; with provider → Start |
143
+ | `simple-coder` | Plan⇄HITL→Coder⇄HITL→Finish smoke spine + `common-memory-tools` on Plan/Coder/Researcher/Worker; Researcher Sub-Agent under Plan, Worker under Coder — **not** full multi-loop `coding-agent` |
144
+ | `kb-create` | Memory / project wiki create: Orchestrator **indexes** the repo with `glob`/`read`, persists `history/work-queue.md`, then **serially** calls Explorer → Composer **one unit at a time**; `common-memory-tools` writes `core/*` + `modules/*`; Review rejects non-empty Pending or thin overviews |
145
+ | `kb-navigate` | Memory navigate: Navigator + Searcher + memory tree/grep/section tools; HITL Review Gate for follow-ups |
146
+ | `basic-coder` | Basic coding harness (Plan⇄HITL→Coder⇄HITL→Finish) — not a toy, **not** full multi-loop `coding-agent` |
147
+ | `coding-agent` | Clarify HITL → red team → plan gate → coder → QA → `common-review` → result HITL; **graph** orders stages |
148
+ | Status | Use-case **Partial**; real-LLM Implementable bar open; Fake CI ≠ end-user proof — **not** “no templates” |
145
149
 
146
150
  ### 7. Run lifecycle
147
151
 
@@ -161,8 +165,12 @@ These four are **not** the same thing.
161
165
  - **Can:** Harness builtins + `permission.ask` Allow/Deny for those builtins.
162
166
  Wired pack / MCP tools (including memory writes and **Langflower Tools**)
163
167
  do **not** ask — authoring the edge is consent. Write Allow does **not**
164
- grant bash. Agents receive **McpHandle**s; system MCP starts only for ids
165
- enabled on nodes in the active workflow.
168
+ grant bash. MCP **nodes** wire `tools` → agent `tools` (`ToolHandle[]`).
169
+ Optional **Tool collection** (`common-tool-collection`) can merge several
170
+ `tools` wires into one before the agent. Direct multi-wire into the agent
171
+ still works. System MCP from `langflower.jsonc` starts only for ids enabled
172
+ on nodes in the active workflow; those tools land on `EC.toolHandles`,
173
+ never as raw config.
166
174
  - **Can:** `compile_custom_nodes` exists only when **Langflower Tools**
167
175
  (`common-langflower-tools`) is wired into that agent’s `tools` port
168
176
  (starter Helper / Writer). Same intent as Custom → **Update**. Recompile
@@ -180,16 +188,21 @@ These four are **not** the same thing.
180
188
  ### 9. Sub-Agent and swarm
181
189
 
182
190
  Sub-Agent is an **explicit canvas node** for **control and observability**
183
- (own toolLog/response, visible spawn, `nodeId` filter) — not magic inside one
184
- LLM turn.
185
-
186
- - **Can:** First-class Sub-Agent node + spawn registration / `subagentResult`.
187
- Default swarm spawns are **serial**. Wiki/memory create (`kb-create`) uses
188
- **serial** scoped spawns driven by a persisted work queue — not parallel
191
+ (own toolLog/response, visible specialist) — not magic inside one LLM turn.
192
+
193
+ - **Can:** First-class Sub-Agent node. Wire Sub-Agent
194
+ `subagent-registration` → parent `tools` (one edge). The parent calls the
195
+ specialist tool (`Writer(subagent)` / `toolId` `Writer_subagent`) with a
196
+ `task`
197
+ (optional `skillId` from the Inspector Skills enum). That call closes the
198
+ parent work-log visit; the specialist streams as its own card. Default swarm
199
+ invokes are **serial**. Wiki/memory create (`kb-create`) uses **serial**
200
+ scoped specialist calls driven by a persisted work queue — not parallel
189
201
  whole-repo fan-out.
190
202
  - **Cannot / not yet:** Hide Sub-Agent work only inside a single LLM turn with
191
203
  no graph node (anti-pattern). Parallel fan-out as the **default**. Nested
192
- **workflow files** (far future).
204
+ **workflow files** (far future). Do not look for `spawn_subagent` or
205
+ registration / spawn / result ports — those wires are gone.
193
206
 
194
207
  ### 10. Other demos
195
208
 
@@ -218,7 +231,8 @@ When the user asks to “create a project wiki”, “build a knowledge base”,
218
231
  → Orchestrator (`common-openai-llm` + builtins `glob`/`read`/`grep` + wired
219
232
  `common-memory-tools`) → Sub-Agents Explorer (read) + Composer (write) →
220
233
  `common-review` with readiness criteria → Finish. Persist a work queue in
221
- memory **before** deep survey; `spawn_subagent` **one unit at a time**.
234
+ memory **before** deep survey; call the Explorer / Composer specialist
235
+ tools **one unit at a time**.
222
236
  - **Cannot:** Recommend one LLM that “reads the whole repo once and dumps a
223
237
  wiki”. Claim vector/embedding KB as base. Claim Obsidian vault helpers as
224
238
  shipped.
@@ -248,7 +262,7 @@ When the user asks to “create a project wiki”, “build a knowledge base”,
248
262
 
249
263
  When the user asks to add or change a custom node from this starter chat:
250
264
 
251
- 1. Spawn Writer (or edit `.langflower/nodes/<pack>/*.ts` yourself).
265
+ 1. Call Writer (or edit `.langflower/nodes/<pack>/*.ts` yourself).
252
266
  2. Call **`compile_custom_nodes`** (no args). Report `status` / `nodeTypes` /
253
267
  `errors` from the tool text. Pack failures also write
254
268
  `COMPILATION_ERRORS.md`.
@@ -76,7 +76,13 @@ Project product data for Langflower lives under **`.langflower/`**.
76
76
 
77
77
  - LLM / agent nodes use **skills** and harness tools as wired in the graph.
78
78
  - **Sub-Agent** is an **explicit canvas node** for control and observability
79
- (own toolLog/response, visible spawn) — not hidden work inside one LLM turn.
79
+ (own toolLog/response). Wire `subagent-registration` into the parent
80
+ `tools` — not hidden work inside one LLM turn. The announced tool is
81
+ `{name}(subagent)` (`toolId` slug `Name_subagent`). Calling that tool closes
82
+ the parent work-log visit; the specialist streams as its own card, and
83
+ the parent continues in a new visit below. Optional **Tool collection**
84
+ (`common-tool-collection`) can merge several `tools` wires; direct
85
+ multi-wire into the agent still works.
80
86
  - **Graph order** stages the pipeline; the model does not invent the stage
81
87
  sequence outside the graph.
82
88
  - Project memory / wiki create is **queue-driven**: index with harness `glob`,
@@ -26,9 +26,10 @@ Facts for UI chrome and on-disk paths. Prefer this file over guessing.
26
26
  | Allow or Deny `permission.ask` | Composer permission controls |
27
27
  | Soft-pause last feed agent / continue | Composer **Pause** (per-node) / Send or Resume (soft pause ≠ Hard Stop) |
28
28
  | Hard-stop a run | Composer **Stop** |
29
- | Edit selected node params / ports | Select node → right aside **inspector** (not Settings) |
29
+ | Edit selected node params / ports | Select node → right aside **inspector** (not Settings). Read-only while a run is active — Stop first. |
30
+ | Add a node from the palette | Drag from the left palette onto the canvas. Disabled while a run is active (`cursor-not-allowed`) — Stop first. |
30
31
  | Add or reload custom nodes | Pack under `.langflower/nodes/<pack>/`. On starter, Helper / Writer call `compile_custom_nodes` (Langflower Tools is wired). Else Custom → **Update**. Hot-swap already-placed types; already-wired custom tools work later in the same run. New types: user places from Custom (no auto-place / auto-wire mid-run). |
31
- | Switch workflow | Topbar workflow list |
32
+ | Switch workflow | Topbar workflow list. Load / New / Copy / rename / Delete are locked while a run is active — Stop first. |
32
33
  | Open Settings without leaving canvas | Gear — Settings in right aside |
33
34
  | Find sample coding graphs | Skeleton / demo-project workflow files — **manual copy** into project, then load → Start. No Sample workflows catalog UI. |
34
35
  | Project instructions for agents | `.langflower/instructions.md` |
@@ -2,7 +2,8 @@
2
2
  name: Langflower workflow writer
3
3
  description: >-
4
4
  Guides authors writing and editing `.langflower/workflows/*.json` graphs
5
- (catalog node types, real ports, Soft↔Hard loops, Sub-Agent L0 wiring).
5
+ (catalog node types, real ports, Soft↔Hard loops, Sub-Agent
6
+ `subagent-registration` wiring).
6
7
  ---
7
8
 
8
9
  # Langflower workflow writer
@@ -55,11 +56,13 @@ Schema: `.langflower/schemas/workflow.schema.json`. Samples:
55
56
  | Node type | Key ports |
56
57
  | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
57
58
  | `common-chat-input` | out `message` (no wireable in) |
58
- | `common-openai-llm` / `common-fake-llm` | in `userPrompt`, `systemPrompt`, `feedback`, `subagentRegistration`, `subagentResult`; out `response`, `subagent`, … |
59
+ | `common-openai-llm` / `common-fake-llm` | in `userPrompt`, `systemPrompt`, `feedback`, `tools`; out `response`, `toolLog`, … |
60
+ | `common-mcp-stdio` / `common-mcp-http` | out **`tools`** — wire into an agent `tools` port (not a separate `mcp` port) |
61
+ | `common-tool-collection` | in **`tools`** (multi combine) → out **`tools`** — optional hub; duplicate `toolId` last-wins. Direct pack → agent still OK |
59
62
  | `common-hitl-review-gate` | in `result`; out `response`, `feedback` |
60
63
  | `common-merge` | in/out **`value`** only (not `step` / `output`) |
61
- | `common-review` | in `task`, `result`, `systemPrompt`; out `response`, `feedback` |
62
- | `common-sub-agent` | out `registration`, `result`; in `task`, `systemPrompt` |
64
+ | `common-review` | in `task`, `result`, `systemPrompt`, `tools`; out `response`, `feedback` |
65
+ | `common-sub-agent` | out **`subagent-registration`** (one specialist handle) → parent `tools`; in `systemPrompt`, `tools` |
63
66
  | `common-finish` | in `value` |
64
67
  | `common-string` | in/out `value` |
65
68
  | `common-langflower-tools` | out **`tools`** only — wire into an agent `tools` port to opt in to **`compile_custom_nodes`** (unsafe; starter Helper / Writer already wired). Not ambient. Canvas add/remove node or edge tools are **not** shipped. |
@@ -75,13 +78,14 @@ Typical HITL revise loop:
75
78
  Do **not** feed Merge output into both gates and LLM feedback on every tick
76
79
  without a clear phase split.
77
80
 
78
- ## Sub-Agent L0 (registration + spawn)
81
+ ## Sub-Agent (one registration wire)
79
82
 
80
83
  Mirror `.langflower/workflows/kb-navigate.json`:
81
84
 
82
- - Sub-Agent `registration` → parent `subagentRegistration`
83
- - Parent `subagent` → Sub-Agent `task`
84
- - Sub-Agent `result` → parent `subagentResult`
85
+ - Sub-Agent `subagent-registration` → parent `tools`
86
+ - Parent calls the specialist tool (`task`, optional `skillId` enum)
87
+ - Do **not** draw `registration` / `subagent` / `task` / `result` /
88
+ `subagentResult` — those ports are gone
85
89
 
86
90
  ## Load repair (product fact)
87
91
 
@@ -60,7 +60,7 @@
60
60
  "maxFeedbackTurns": 8
61
61
  },
62
62
  "inputs": {
63
- "systemPrompt": "You are the Orchestrator for building a DETAILED project memory map (project wiki) under `.langflower/memory/`.\n\nGoal: grounding a coding agent can use to implement features without rediscovering the repo. A thin whole-repo skim is NOT enough.\n\n## Required memory layout (all under `.langflower/memory/`)\n\n1) `core/overview.md` — purpose, primary user, ships vs not, how to run\n2) `core/layout.md` — directory / package map with ownership\n3) `core/architecture.md` — runtime flow, boundaries, key ADRs / invariants\n4) `core/build-test.md` — install, build, typecheck, unit vs integration, verify\n5) `core/entrypoints.md` — CLI / server / UI / MCP paths and ports\n6) `core/conventions.md` — coding rules agents must follow\n7) `modules/<area>.md` — one file per major package/area (responsibility, layout, contracts, neighbors, pitfalls)\n8) `history/work-queue.md` — indexed work units (Pending / In progress / Done)\n9) `history/build-log.md` — chronological survey/write notes (append_memory_log)\n\nOptional when material exists: `core/config.md`, `core/workflows-skills.md`.\n\n## Process (STRICT order — serial spawn_subagent)\n\n### Phase A — Index first (before any deep Explorer/Composer spawn)\n\n1) Use `glob` + `read` on package.json workspaces, top-level dirs, README*, AGENTS.md, docs/** (or equivalents). List every workspace package / major area and each mandatory `core/*` topic.\n2) Persist `.langflower/memory/history/work-queue.md` via create_memory_file / update_memory_section with ## Pending, ## In progress, ## Done. Each Pending item: id, path(s) to survey, target memory file (`modules/<area>.md` or `core/<name>.md`), status.\n3) Do NOT spawn Explorer/Composer for a vague “survey the whole repo” after the queue exists.\n\n### Phase B — One-unit loop\n\n1) Pick ONE Pending unit → move to In progress in work-queue.md.\n2) spawn_subagent Explorer with a task that names ONLY that unit (paths, expected depth, target memory file).\n3) spawn_subagent Composer for ONLY that unit’s target file/sections (pass Explorer findings).\n4) Mark the unit Done; append_memory_log on history/build-log.md.\n5) Repeat until Pending is empty (or explicit justified skips with evidence in the queue).\n\n### Phase C — Exit / Review feedback\n\n- Emit readiness only when Pending is empty AND mandatory files have real ## sections with concrete paths/commands/types.\n- Module pages MUST cover every indexed package/area from the queue.\n- On Review feedback: re-open specific queue items — do not restart a vague whole-repo pass.\n- Cite evidence (paths + section headings) in the readiness report."
63
+ "systemPrompt": "You are the Orchestrator for building a DETAILED project memory map (project wiki) under `.langflower/memory/`.\n\nGoal: grounding a coding agent can use to implement features without rediscovering the repo. A thin whole-repo skim is NOT enough.\n\n## Required memory layout (all under `.langflower/memory/`)\n\n1) `core/overview.md` — purpose, primary user, ships vs not, how to run\n2) `core/layout.md` — directory / package map with ownership\n3) `core/architecture.md` — runtime flow, boundaries, key ADRs / invariants\n4) `core/build-test.md` — install, build, typecheck, unit vs integration, verify\n5) `core/entrypoints.md` — CLI / server / UI / MCP paths and ports\n6) `core/conventions.md` — coding rules agents must follow\n7) `modules/<area>.md` — one file per major package/area (responsibility, layout, contracts, neighbors, pitfalls)\n8) `history/work-queue.md` — indexed work units (Pending / In progress / Done)\n9) `history/build-log.md` — chronological survey/write notes (append_memory_log)\n\nOptional when material exists: `core/config.md`, `core/workflows-skills.md`.\n\n## Process (STRICT order — serial specialist tool calls)\n\n### Phase A — Index first (before any deep Explorer/Composer spawn)\n\n1) Use `glob` + `read` on package.json workspaces, top-level dirs, README*, AGENTS.md, docs/** (or equivalents). List every workspace package / major area and each mandatory `core/*` topic.\n2) Persist `.langflower/memory/history/work-queue.md` via create_memory_file / update_memory_section with ## Pending, ## In progress, ## Done. Each Pending item: id, path(s) to survey, target memory file (`modules/<area>.md` or `core/<name>.md`), status.\n3) Do NOT call Explorer/Composer for a vague “survey the whole repo” after the queue exists.\n\n### Phase B — One-unit loop\n\n1) Pick ONE Pending unit → move to In progress in work-queue.md.\n2) Call the Explorer specialist tool with a task that names ONLY that unit (paths, expected depth, target memory file).\n3) Call the Composer specialist tool for ONLY that unit’s target file/sections (pass Explorer findings).\n4) Mark the unit Done; append_memory_log on history/build-log.md.\n5) Repeat until Pending is empty (or explicit justified skips with evidence in the queue).\n\n### Phase C — Exit / Review feedback\n\n- Emit readiness only when Pending is empty AND mandatory files have real ## sections with concrete paths/commands/types.\n- Module pages MUST cover every indexed package/area from the queue.\n- On Review feedback: re-open specific queue items — do not restart a vague whole-repo pass.\n- Cite evidence (paths + section headings) in the readiness report."
64
64
  },
65
65
  "ui": {
66
66
  "position": {
@@ -212,48 +212,6 @@
212
212
  "toNodeId": "review",
213
213
  "toPort": ["tools", 0]
214
214
  },
215
- {
216
- "edgeId": "e-reg-explorer",
217
- "fromNodeId": "explorer",
218
- "fromPort": ["registration", 0],
219
- "toNodeId": "orchestrator",
220
- "toPort": ["subagentRegistration", 0]
221
- },
222
- {
223
- "edgeId": "e-reg-composer",
224
- "fromNodeId": "composer",
225
- "fromPort": ["registration", 0],
226
- "toNodeId": "orchestrator",
227
- "toPort": ["subagentRegistration", 1]
228
- },
229
- {
230
- "edgeId": "e-spawn-explorer",
231
- "fromNodeId": "orchestrator",
232
- "fromPort": ["subagent", 0],
233
- "toNodeId": "explorer",
234
- "toPort": ["task", 0]
235
- },
236
- {
237
- "edgeId": "e-spawn-composer",
238
- "fromNodeId": "orchestrator",
239
- "fromPort": ["subagent", 0],
240
- "toNodeId": "composer",
241
- "toPort": ["task", 0]
242
- },
243
- {
244
- "edgeId": "e-result-explorer",
245
- "fromNodeId": "explorer",
246
- "fromPort": ["result", 0],
247
- "toNodeId": "orchestrator",
248
- "toPort": ["subagentResult", 0]
249
- },
250
- {
251
- "edgeId": "e-result-composer",
252
- "fromNodeId": "composer",
253
- "fromPort": ["result", 0],
254
- "toNodeId": "orchestrator",
255
- "toPort": ["subagentResult", 1]
256
- },
257
215
  {
258
216
  "edgeId": "e-orch-review-result",
259
217
  "fromNodeId": "orchestrator",
@@ -281,6 +239,20 @@
281
239
  "fromPort": ["response", 0],
282
240
  "toNodeId": "done",
283
241
  "toPort": ["value", 0]
242
+ },
243
+ {
244
+ "edgeId": "e-tools-explorer",
245
+ "fromNodeId": "explorer",
246
+ "fromPort": ["subagent-registration", 0],
247
+ "toNodeId": "orchestrator",
248
+ "toPort": ["tools", 1]
249
+ },
250
+ {
251
+ "edgeId": "e-tools-composer",
252
+ "fromNodeId": "composer",
253
+ "fromPort": ["subagent-registration", 0],
254
+ "toNodeId": "orchestrator",
255
+ "toPort": ["tools", 2]
284
256
  }
285
257
  ]
286
258
  }
@@ -53,7 +53,7 @@
53
53
  "maxFeedbackTurns": 6
54
54
  },
55
55
  "inputs": {
56
- "systemPrompt": "You answer questions about this project grounded in project memory.\n\nConvention: markdown under `.langflower/memory/` (built by the kb-create / Memory create workflow). Memory is also readable with harness file tools on `.langflower/memory/…`.\n\nBefore answering, use get_memory_tree / search_memory_grep / read_memory_section (yourself or via spawn_subagent Searcher). Prefer memory hits over guessing. If memory is empty or hits are weak, say so and offer to run Memory create (kb-create) — do not invent.\n\nWhen HITL feedback arrives, revise the answer — do not ignore it. Keep answers short and cite memory file paths / headings when available."
56
+ "systemPrompt": "You answer questions about this project grounded in project memory.\n\nConvention: markdown under `.langflower/memory/` (built by the kb-create / Memory create workflow). Memory is also readable with harness file tools on `.langflower/memory/…`.\n\nBefore answering, use get_memory_tree / search_memory_grep / read_memory_section (yourself or via the Searcher specialist tool). Prefer memory hits over guessing. If memory is empty or hits are weak, say so and offer to run Memory create (kb-create) — do not invent.\n\nWhen HITL feedback arrives, revise the answer — do not ignore it. Keep answers short and cite memory file paths / headings when available."
57
57
  },
58
58
  "ui": {
59
59
  "position": {
@@ -125,27 +125,6 @@
125
125
  "toNodeId": "searcher",
126
126
  "toPort": ["tools", 0]
127
127
  },
128
- {
129
- "edgeId": "e-reg-searcher",
130
- "fromNodeId": "searcher",
131
- "fromPort": ["registration", 0],
132
- "toNodeId": "navigator",
133
- "toPort": ["subagentRegistration", 0]
134
- },
135
- {
136
- "edgeId": "e-spawn-searcher",
137
- "fromNodeId": "navigator",
138
- "fromPort": ["subagent", 0],
139
- "toNodeId": "searcher",
140
- "toPort": ["task", 0]
141
- },
142
- {
143
- "edgeId": "e-result-searcher",
144
- "fromNodeId": "searcher",
145
- "fromPort": ["result", 0],
146
- "toNodeId": "navigator",
147
- "toPort": ["subagentResult", 0]
148
- },
149
128
  {
150
129
  "edgeId": "e-nav-review",
151
130
  "fromNodeId": "navigator",
@@ -159,6 +138,13 @@
159
138
  "fromPort": ["feedback", 0],
160
139
  "toNodeId": "navigator",
161
140
  "toPort": ["feedback", 0]
141
+ },
142
+ {
143
+ "edgeId": "e-tools-searcher",
144
+ "fromNodeId": "searcher",
145
+ "fromPort": ["subagent-registration", 0],
146
+ "toNodeId": "navigator",
147
+ "toPort": ["tools", 1]
162
148
  }
163
149
  ]
164
150
  }