langflower 0.1.1 → 0.1.3

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/dist/index.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  mergeProjectAndNodePermissions,
29
29
  resolveProjectPath,
30
30
  walkFiles
31
- } from "./chunk-WQZHA5FM.js";
31
+ } from "./chunk-NIRPHJLO.js";
32
32
  import {
33
33
  __commonJS,
34
34
  __require,
@@ -58487,6 +58487,7 @@ var {
58487
58487
  } = import_index.default;
58488
58488
 
58489
58489
  // packages/cli/dist/start-command.js
58490
+ import { writeSync } from "node:fs";
58490
58491
  import fs23 from "node:fs/promises";
58491
58492
  import path22 from "node:path";
58492
58493
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -59200,6 +59201,11 @@ var runnerConfig = {
59200
59201
  * (not a canvas HITL port — see `runner.permission.ask`).
59201
59202
  */
59202
59203
  "runner.permission.reply": message(),
59204
+ /**
59205
+ * Operator text for a runtime `ask_user` builtin wait inside the tool
59206
+ * loop (not a canvas HITL port — see `runner.askUser.ask`).
59207
+ */
59208
+ "runner.askUser.reply": message(),
59203
59209
  /**
59204
59210
  * Clear the execution feed (work log). Server drops the runner event
59205
59211
  * log and re-broadcasts an empty `executionFeed.snapshot`. No payload.
@@ -59257,6 +59263,16 @@ var runnerConfig = {
59257
59263
  * ask. Every client removes that ask from its UI only on this fact.
59258
59264
  */
59259
59265
  "runner.permission.accepted": message(),
59266
+ /**
59267
+ * Runtime `ask_user` wait for operator text (feed + composer textarea).
59268
+ * Stays inside the internal tool loop — not a graph HITL edge.
59269
+ */
59270
+ "runner.askUser.ask": message(),
59271
+ /**
59272
+ * Server accepted one text reply for a still-pending `ask_user`.
59273
+ * Every client removes that ask from its UI only on this fact.
59274
+ */
59275
+ "runner.askUser.accepted": message(),
59260
59276
  /**
59261
59277
  * Resumable checkpoints for the active workflow (bootstrap + after
59262
59278
  * Stop / discard / complete).
@@ -59916,6 +59932,11 @@ var runnerConfig2 = {
59916
59932
  * (not a canvas HITL port — see `runner.permission.ask`).
59917
59933
  */
59918
59934
  "runner.permission.reply": message(),
59935
+ /**
59936
+ * Operator text for a runtime `ask_user` builtin wait inside the tool
59937
+ * loop (not a canvas HITL port — see `runner.askUser.ask`).
59938
+ */
59939
+ "runner.askUser.reply": message(),
59919
59940
  /**
59920
59941
  * Clear the execution feed (work log). Server drops the runner event
59921
59942
  * log and re-broadcasts an empty `executionFeed.snapshot`. No payload.
@@ -59973,6 +59994,16 @@ var runnerConfig2 = {
59973
59994
  * ask. Every client removes that ask from its UI only on this fact.
59974
59995
  */
59975
59996
  "runner.permission.accepted": message(),
59997
+ /**
59998
+ * Runtime `ask_user` wait for operator text (feed + composer textarea).
59999
+ * Stays inside the internal tool loop — not a graph HITL edge.
60000
+ */
60001
+ "runner.askUser.ask": message(),
60002
+ /**
60003
+ * Server accepted one text reply for a still-pending `ask_user`.
60004
+ * Every client removes that ask from its UI only on this fact.
60005
+ */
60006
+ "runner.askUser.accepted": message(),
59976
60007
  /**
59977
60008
  * Resumable checkpoints for the active workflow (bootstrap + after
59978
60009
  * Stop / discard / complete).
@@ -61026,6 +61057,52 @@ var RunCheckpointSession = class {
61026
61057
  import { RuntimeFacade } from "@langflower/runtime";
61027
61058
  import { Subscription } from "rxjs";
61028
61059
 
61060
+ // packages/server/dist/harness/pending-ask-user-asks.js
61061
+ var ASK_USER_ABORTED = "ask_user aborted.";
61062
+ var PendingAskUserAsks = class {
61063
+ pending = /* @__PURE__ */ new Map();
61064
+ list() {
61065
+ return [...this.pending.values()].map((entry) => entry.payload);
61066
+ }
61067
+ requestAskUser = (runId, nodeId, request, emitAsk) => {
61068
+ const askId = crypto.randomUUID();
61069
+ const payload = {
61070
+ runId,
61071
+ askId,
61072
+ nodeId,
61073
+ question: request.question
61074
+ };
61075
+ return new Promise((resolve, reject) => {
61076
+ this.pending.set(askId, { payload, resolve, reject });
61077
+ emitAsk(payload);
61078
+ });
61079
+ };
61080
+ reply = (payload) => {
61081
+ const entry = this.pending.get(payload.askId);
61082
+ if (entry === void 0) {
61083
+ return false;
61084
+ }
61085
+ if (entry.payload.runId !== payload.runId) {
61086
+ return false;
61087
+ }
61088
+ const text = payload.text.trim();
61089
+ if (text.length === 0) {
61090
+ return false;
61091
+ }
61092
+ this.pending.delete(payload.askId);
61093
+ entry.resolve(text);
61094
+ return true;
61095
+ };
61096
+ /** Fail closed all outstanding asks (interrupt / run end). */
61097
+ failAll = (runId) => {
61098
+ const entries = [...this.pending.entries()].filter(([, entry]) => runId === void 0 || entry.payload.runId === runId);
61099
+ for (const [askId, entry] of entries) {
61100
+ this.pending.delete(askId);
61101
+ entry.reject(new Error(ASK_USER_ABORTED));
61102
+ }
61103
+ };
61104
+ };
61105
+
61029
61106
  // packages/server/dist/harness/pending-permission-asks.js
61030
61107
  var PendingPermissionAsks = class {
61031
61108
  pending = /* @__PURE__ */ new Map();
@@ -61147,6 +61224,8 @@ var LangflowerSession = class {
61147
61224
  runtime = new RuntimeFacade({ log: true });
61148
61225
  /** Feed permission.ask pause/resume for the internal tool loop. */
61149
61226
  permissionAsks = new PendingPermissionAsks();
61227
+ /** Feed ask_user pause/resume for the internal tool loop. */
61228
+ askUserAsks = new PendingAskUserAsks();
61150
61229
  activeWorkflow = null;
61151
61230
  activeWorkflowId;
61152
61231
  currentStatus = "pristine";
@@ -61175,6 +61254,7 @@ var LangflowerSession = class {
61175
61254
  this.subscriptions.add(this.runtime.runner.status$.subscribe((status) => {
61176
61255
  if (status !== "running") {
61177
61256
  this.permissionAsks.denyAll(this.runId !== void 0 ? String(this.runId) : void 0);
61257
+ this.askUserAsks.failAll(this.runId !== void 0 ? String(this.runId) : void 0);
61178
61258
  void this.releaseMcpRuntime();
61179
61259
  }
61180
61260
  this.runnerStatus = status;
@@ -61194,6 +61274,7 @@ var LangflowerSession = class {
61194
61274
  }
61195
61275
  dispose() {
61196
61276
  this.permissionAsks.denyAll();
61277
+ this.askUserAsks.failAll();
61197
61278
  void this.releaseMcpRuntime();
61198
61279
  this.runtime.runner.dispose();
61199
61280
  this.subscriptions.unsubscribe();
@@ -61522,7 +61603,8 @@ var HARNESS_BUILTIN_TOOL_IDS = [
61522
61603
  "write",
61523
61604
  "create",
61524
61605
  "delete",
61525
- "bash"
61606
+ "bash",
61607
+ "ask_user"
61526
61608
  ];
61527
61609
  var PLAN_AGENT_SYSTEM_PROMPT = [
61528
61610
  "You are the Plan agent in a Langflower workflow.",
@@ -61532,6 +61614,9 @@ var PLAN_AGENT_SYSTEM_PROMPT = [
61532
61614
  "",
61533
61615
  "Write plans in Markdown with sections: Goal, Context, Steps, Risks, Open questions.",
61534
61616
  "",
61617
+ "When memory tools are wired, call update_plan with that markdown so the operator",
61618
+ "sees the current plan in the work log. There is no separate Plan mode.",
61619
+ "",
61535
61620
  "When requirements are ambiguous, use ask_user before finalizing the plan."
61536
61621
  ].join("\n");
61537
61622
  var CODER_AGENT_SYSTEM_PROMPT = [
@@ -61541,7 +61626,9 @@ var CODER_AGENT_SYSTEM_PROMPT = [
61541
61626
  "edits. Prefer precise file edits over large rewrites.",
61542
61627
  "",
61543
61628
  "When tests are available, run them to verify your work. Summarize what you changed",
61544
- "in your final response."
61629
+ "in your final response.",
61630
+ "",
61631
+ "If you are not sure, call ask_user instead of guessing."
61545
61632
  ].join("\n");
61546
61633
  var EXPLORER_AGENT_SYSTEM_PROMPT = [
61547
61634
  "You are the Explorer agent in a Langflower workflow.",
@@ -61549,7 +61636,9 @@ var EXPLORER_AGENT_SYSTEM_PROMPT = [
61549
61636
  "Research the topic using web_fetch. Synthesize findings into clear Markdown notes.",
61550
61637
  "Do not modify application source code\u2014only *.md research notes.",
61551
61638
  "",
61552
- "Cite URLs. Separate facts from inference."
61639
+ "Cite URLs. Separate facts from inference.",
61640
+ "",
61641
+ "If you are not sure, call ask_user instead of guessing."
61553
61642
  ].join("\n");
61554
61643
  var allAllow = () => Object.fromEntries(HARNESS_BUILTIN_TOOL_IDS.map((id) => [id, "allow"]));
61555
61644
  var CUSTOM_TOOL_PERMISSIONS = allAllow();
@@ -61585,7 +61674,7 @@ var LLM_ROLE_PRESET_DEFAULTS = {
61585
61674
  },
61586
61675
  plan: {
61587
61676
  systemPrompt: PLAN_AGENT_SYSTEM_PROMPT,
61588
- skillId: "plan",
61677
+ skillId: "spec-architect",
61589
61678
  toolPermissions: PLAN_TOOL_PERMISSIONS
61590
61679
  },
61591
61680
  coder: {
@@ -61647,7 +61736,24 @@ var resolveEffectiveToolPermissions = (rolePreset, toolPermissionsParam, enabled
61647
61736
  }
61648
61737
  return LLM_ROLE_PRESET_DEFAULTS[rolePreset].toolPermissions;
61649
61738
  };
61650
- var toolPermissionsToEnabledIds = (toolPermissions) => Object.entries(toolPermissions).filter(([, decision]) => decision !== "deny").map(([toolId]) => toolId);
61739
+ var toolPermissionsToEnabledIds = (toolPermissions) => {
61740
+ const enabled = [];
61741
+ const seen = /* @__PURE__ */ new Set();
61742
+ for (const id of HARNESS_BUILTIN_TOOL_IDS) {
61743
+ if (toolPermissions[id] !== "deny") {
61744
+ enabled.push(id);
61745
+ seen.add(id);
61746
+ }
61747
+ }
61748
+ for (const [toolId, decision] of Object.entries(toolPermissions)) {
61749
+ if (decision === "deny" || seen.has(toolId)) {
61750
+ continue;
61751
+ }
61752
+ enabled.push(toolId);
61753
+ seen.add(toolId);
61754
+ }
61755
+ return enabled;
61756
+ };
61651
61757
 
61652
61758
  // packages/common-nodes/dist/ai/features/prompt/normalize-max-iterations.js
61653
61759
  var normalizeMaxIterations = (value, options) => {
@@ -62338,14 +62444,6 @@ var bindLlmAgentSession = (ctx, helpers, inventory, options) => {
62338
62444
  };
62339
62445
 
62340
62446
  // packages/common-nodes/dist/tools/inventory-tool-round.js
62341
- var TOOL_LOG_PREVIEW = 400;
62342
- var previewToolLogText = (text) => {
62343
- const trimmed = text.trim();
62344
- if (trimmed.length <= TOOL_LOG_PREVIEW) {
62345
- return trimmed;
62346
- }
62347
- return `${trimmed.slice(0, TOOL_LOG_PREVIEW - 1)}\u2026`;
62348
- };
62349
62447
  var toChatToolDefinitions = (tools) => tools.map((tool) => ({
62350
62448
  type: "function",
62351
62449
  function: {
@@ -63922,10 +64020,11 @@ var prepareAndStream = (state, options, cancel$, cancelSignal) => {
63922
64020
  });
63923
64021
  };
63924
64022
  var isSubAgentToolCall = (name) => name.endsWith("_subagent") || name.endsWith("(subagent)");
64023
+ var isUnboundedWaitToolCall = (name) => name === "ask_user" || isSubAgentToolCall(name);
63925
64024
  var invokeTool = (state, call, options, cancelSignal) => {
63926
64025
  const callLog = emit({
63927
64026
  kind: "toolLog",
63928
- text: `\u2192 ${call.name}(${previewToolLogText(call.arguments)})`
64027
+ text: `\u2192 ${call.name}(${call.arguments})`
63929
64028
  });
63930
64029
  const toolAbort = new AbortController();
63931
64030
  const abortTool = () => {
@@ -63949,7 +64048,7 @@ var invokeTool = (state, call, options, cancelSignal) => {
63949
64048
  })).pipe(finalize2(() => {
63950
64049
  cancelSignal.removeEventListener("abort", abortTool);
63951
64050
  }));
63952
- const toolTimeoutMs = isSubAgentToolCall(call.name) ? 0 : options.recovery.toolTimeoutMs;
64051
+ const toolTimeoutMs = isUnboundedWaitToolCall(call.name) ? 0 : options.recovery.toolTimeoutMs;
63953
64052
  const boundedInvocation$ = toolTimeoutMs > 0 ? invocation$.pipe(timeout2({
63954
64053
  first: toolTimeoutMs
63955
64054
  })) : invocation$;
@@ -63969,7 +64068,7 @@ var toolResultPackets = (state, call, result, options, prefix) => {
63969
64068
  ...prefix,
63970
64069
  emit({
63971
64070
  kind: "toolLog",
63972
- text: `\u2190 ${call.name}: ${previewToolLogText(normalized)}`
64071
+ text: `\u2190 ${call.name}: ${normalized}`
63973
64072
  }),
63974
64073
  transition(next)
63975
64074
  ]);
@@ -65317,7 +65416,7 @@ var PATH_CHOICE_POLICY = {
65317
65416
  { kind: "historySync", messages },
65318
65417
  {
65319
65418
  kind: "toolLog",
65320
- text: `\u2192 ${control.call.name}(${previewToolLogText(control.call.arguments)})`
65419
+ text: `\u2192 ${control.call.name}(${control.call.arguments})`
65321
65420
  },
65322
65421
  control.kind === "accept" ? { kind: "accept", notes } : { kind: "feedback", notes }
65323
65422
  ]
@@ -68256,6 +68355,8 @@ var topLevelHeadings = (text) => parseHeadings(text).filter((heading) => heading
68256
68355
  // packages/tools/dist/memory/memory-paths.js
68257
68356
  import path13 from "node:path";
68258
68357
  var MEMORY_ROOT_RELATIVE = ".langflower/memory";
68358
+ var MEMORY_PLAN_FILE = "history/plan.md";
68359
+ var MEMORY_PLAN_HEADING = "## Plan";
68259
68360
  var memoryRootAbsolute = (projectDir) => path13.join(path13.resolve(projectDir), MEMORY_ROOT_RELATIVE);
68260
68361
  var resolveMemoryFilePath = (projectDir, filePath) => {
68261
68362
  const trimmed = filePath.trim().replace(/\\/g, "/");
@@ -68760,6 +68861,58 @@ var MEMORY_TOOL_CONFIGS = [
68760
68861
  await createMemoryStore(ctx.projectDir).createFile(filePath, initial);
68761
68862
  return json({ file_path: filePath, ok: true });
68762
68863
  }
68864
+ },
68865
+ {
68866
+ toolId: "update_plan",
68867
+ description: "Replace the current plan shown to the operator in the work log. Writes the reserved ## Plan section in history/plan.md. There is no separate Plan mode \u2014 call this whenever the live plan changes. Pass only the markdown body under the heading (Goal, Context, Steps, Risks, Open questions).",
68868
+ inputSchema: {
68869
+ type: "object",
68870
+ properties: {
68871
+ content: {
68872
+ type: "string",
68873
+ description: "Markdown body under ## Plan. Do not include the heading itself."
68874
+ }
68875
+ },
68876
+ required: ["content"]
68877
+ },
68878
+ handler: async (args, ctx) => {
68879
+ const content = requireString(args, "content");
68880
+ await createMemoryStore(ctx.projectDir).updateSection(MEMORY_PLAN_FILE, MEMORY_PLAN_HEADING, content);
68881
+ return json({
68882
+ file_path: MEMORY_PLAN_FILE,
68883
+ heading: MEMORY_PLAN_HEADING,
68884
+ ok: true
68885
+ });
68886
+ }
68887
+ },
68888
+ {
68889
+ toolId: "read_plan",
68890
+ description: "Reads the current operator-visible plan from history/plan.md (## Plan). Returns empty content when the plan file or section does not exist.",
68891
+ inputSchema: {
68892
+ type: "object",
68893
+ properties: {},
68894
+ required: []
68895
+ },
68896
+ handler: async (_args, ctx) => {
68897
+ try {
68898
+ const content = await createMemoryStore(ctx.projectDir).readSection(MEMORY_PLAN_FILE, MEMORY_PLAN_HEADING);
68899
+ return json({
68900
+ file_path: MEMORY_PLAN_FILE,
68901
+ content,
68902
+ exists: true
68903
+ });
68904
+ } catch (error) {
68905
+ const message2 = error instanceof Error ? error.message : String(error);
68906
+ if (message2.includes("Memory file not found") || message2.includes("Heading")) {
68907
+ return json({
68908
+ file_path: MEMORY_PLAN_FILE,
68909
+ content: "",
68910
+ exists: false
68911
+ });
68912
+ }
68913
+ throw error;
68914
+ }
68915
+ }
68763
68916
  }
68764
68917
  ];
68765
68918
 
@@ -68956,25 +69109,68 @@ Typical uses:
68956
69109
  });
68957
69110
 
68958
69111
  // packages/common-nodes/dist/memory/memory-tools/node.js
68959
- import { defineToolRegistrations as defineToolRegistrations2 } from "@langflower/node-sdk";
68960
- var memoryToolsNode = defineToolRegistrations2({
69112
+ import { defineReactiveNode as defineReactiveNode32, TOOL_HANDLE_WIRE_TYPE as TOOL_HANDLE_WIRE_TYPE5 } from "@langflower/node-sdk";
69113
+ import { statefulConnection, statefulObservable as statefulObservable3 } from "@rx-evo/stateful-observable";
69114
+ import { of as of13 } from "rxjs";
69115
+ var memoryToolsNode = defineReactiveNode32({
68961
69116
  type: "common-memory-tools",
68962
69117
  displayName: "Memory Tools",
68963
69118
  category: "Tools",
68964
69119
  description: `
68965
- Give an agent tools to read and write the project wiki (tree, search, append, update, create).
69120
+ Give an agent tools to read and write the project wiki (tree, search, append, update, create) and to show the current plan in the work log.
68966
69121
 
68967
- Wire **tools** into an LLM. Notes live under the project's memory folder.
69122
+ Wire **tools** into an LLM. Notes live under the project's memory folder. Call **update_plan** to print the live plan \u2014 there is no separate Plan mode.
68968
69123
  `.trim(),
68969
- tools: MEMORY_TOOL_CONFIGS
69124
+ uiSchema: [],
69125
+ bind(_ctx, { configureOutput }) {
69126
+ const planOut = statefulConnection();
69127
+ const tools$ = statefulObservable3({
69128
+ loader: () => of13(MEMORY_TOOL_CONFIGS.map((tool) => {
69129
+ const handle = {
69130
+ toolId: tool.toolId,
69131
+ name: tool.name ?? tool.toolId,
69132
+ description: tool.description,
69133
+ inputSchema: tool.inputSchema,
69134
+ invoke: tool.handler
69135
+ };
69136
+ if (tool.toolId !== "update_plan") {
69137
+ return handle;
69138
+ }
69139
+ return {
69140
+ ...handle,
69141
+ invoke: async (args, ctx) => {
69142
+ const result = await tool.handler(args, ctx);
69143
+ try {
69144
+ const markdown = await createMemoryStore(ctx.projectDir).readSection(MEMORY_PLAN_FILE, MEMORY_PLAN_HEADING);
69145
+ planOut.connect(of13(markdown));
69146
+ } catch {
69147
+ }
69148
+ return result;
69149
+ }
69150
+ };
69151
+ }))
69152
+ });
69153
+ return {
69154
+ inputs: [],
69155
+ outputs: [
69156
+ configureOutput("tools", tools$, {
69157
+ wireType: TOOL_HANDLE_WIRE_TYPE5
69158
+ }),
69159
+ configureOutput("plan", planOut, {
69160
+ wireType: "string",
69161
+ feed: { role: "result" }
69162
+ })
69163
+ ]
69164
+ };
69165
+ }
68970
69166
  });
68971
69167
 
68972
69168
  // packages/common-nodes/dist/langflower-tools/node.js
68973
- import { defineReactiveNode as defineReactiveNode32, TOOL_HANDLE_WIRE_TYPE as TOOL_HANDLE_WIRE_TYPE5 } from "@langflower/node-sdk";
69169
+ import { defineReactiveNode as defineReactiveNode33, TOOL_HANDLE_WIRE_TYPE as TOOL_HANDLE_WIRE_TYPE6 } from "@langflower/node-sdk";
68974
69170
 
68975
69171
  // packages/common-nodes/dist/langflower-tools/emit-registration-tools.js
68976
- import { statefulObservable as statefulObservable3 } from "@rx-evo/stateful-observable";
68977
- import { of as of13 } from "rxjs";
69172
+ import { statefulObservable as statefulObservable4 } from "@rx-evo/stateful-observable";
69173
+ import { of as of14 } from "rxjs";
68978
69174
  var peekNodeContext = (source) => {
68979
69175
  let peeked;
68980
69176
  const sub = source.value$.subscribe((value) => {
@@ -68983,8 +69179,8 @@ var peekNodeContext = (source) => {
68983
69179
  sub.unsubscribe();
68984
69180
  return typeof peeked === "object" && peeked !== null ? peeked : void 0;
68985
69181
  };
68986
- var emitRegistrationTools = (ctx, tools) => statefulObservable3({
68987
- loader: () => of13(tools.map((tool) => ({
69182
+ var emitRegistrationTools = (ctx, tools) => statefulObservable4({
69183
+ loader: () => of14(tools.map((tool) => ({
68988
69184
  toolId: tool.toolId,
68989
69185
  name: tool.name ?? tool.toolId,
68990
69186
  description: tool.description,
@@ -69057,7 +69253,7 @@ ${message2}`;
69057
69253
  })
69058
69254
  }
69059
69255
  ];
69060
- var langflowerToolsNode = defineReactiveNode32({
69256
+ var langflowerToolsNode = defineReactiveNode33({
69061
69257
  type: "common-langflower-tools",
69062
69258
  displayName: "Langflower Tools",
69063
69259
  category: "Tools",
@@ -69071,14 +69267,14 @@ On starter, Helper and Writer already have this wired.
69071
69267
  return {
69072
69268
  inputs: [],
69073
69269
  outputs: [
69074
- configureOutput("tools", emitRegistrationTools(ctx, LANGFLOWER_BUS_TOOL_CONFIGS), { wireType: TOOL_HANDLE_WIRE_TYPE5 })
69270
+ configureOutput("tools", emitRegistrationTools(ctx, LANGFLOWER_BUS_TOOL_CONFIGS), { wireType: TOOL_HANDLE_WIRE_TYPE6 })
69075
69271
  ]
69076
69272
  };
69077
69273
  }
69078
69274
  });
69079
69275
 
69080
69276
  // packages/common-nodes/dist/tools/tool-collection/node.js
69081
- import { defineReactiveNode as defineReactiveNode33, TOOL_HANDLE_WIRE_TYPE as TOOL_HANDLE_WIRE_TYPE6 } from "@langflower/node-sdk";
69277
+ import { defineReactiveNode as defineReactiveNode34, TOOL_HANDLE_WIRE_TYPE as TOOL_HANDLE_WIRE_TYPE7 } from "@langflower/node-sdk";
69082
69278
  import { map as map19 } from "rxjs";
69083
69279
  var mergeToolHandlesLastWins = (wired) => {
69084
69280
  const flattened = Array.isArray(wired) ? flattenToolHandles(wired) : flattenToolHandles(wired === void 0 || wired === null ? [] : [wired]);
@@ -69088,7 +69284,7 @@ var mergeToolHandlesLastWins = (wired) => {
69088
69284
  }
69089
69285
  return [...byId.values()];
69090
69286
  };
69091
- var toolCollectionNode = defineReactiveNode33({
69287
+ var toolCollectionNode = defineReactiveNode34({
69092
69288
  type: "common-tool-collection",
69093
69289
  displayName: "Tool collection",
69094
69290
  category: "Tools",
@@ -69101,7 +69297,7 @@ Optional \u2014 you can still plug many tool packs straight into the agent.
69101
69297
  bind(_ctx, { makeInput, configureOutput }) {
69102
69298
  const tools = makeInput("tools", {
69103
69299
  name: "tools",
69104
- wireType: TOOL_HANDLE_WIRE_TYPE6,
69300
+ wireType: TOOL_HANDLE_WIRE_TYPE7,
69105
69301
  multi: "combine",
69106
69302
  defaultValue: []
69107
69303
  });
@@ -69110,7 +69306,7 @@ Optional \u2014 you can still plug many tool packs straight into the agent.
69110
69306
  inputs: [tools],
69111
69307
  outputs: [
69112
69308
  configureOutput("tools", merged$, {
69113
- wireType: TOOL_HANDLE_WIRE_TYPE6
69309
+ wireType: TOOL_HANDLE_WIRE_TYPE7
69114
69310
  })
69115
69311
  ]
69116
69312
  };
@@ -69118,8 +69314,8 @@ Optional \u2014 you can still plug many tool packs straight into the agent.
69118
69314
  });
69119
69315
 
69120
69316
  // packages/common-nodes/dist/tools/tool-invoke/node.js
69121
- import { defineReactiveNode as defineReactiveNode34, TOOL_HANDLE_WIRE_TYPE as TOOL_HANDLE_WIRE_TYPE7, withLoading as withLoading11 } from "@langflower/node-sdk";
69122
- import { concatMap as concatMap6, EMPTY as EMPTY7, from as from10, of as of14, throwError as throwError10 } from "rxjs";
69317
+ import { defineReactiveNode as defineReactiveNode35, TOOL_HANDLE_WIRE_TYPE as TOOL_HANDLE_WIRE_TYPE8, withLoading as withLoading11 } from "@langflower/node-sdk";
69318
+ import { concatMap as concatMap6, EMPTY as EMPTY7, from as from10, of as of15, throwError as throwError10 } from "rxjs";
69123
69319
  var isArgsObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
69124
69320
  var flattenWiredHandles = (wired) => {
69125
69321
  const flattened = Array.isArray(wired) ? flattenToolHandles(wired) : flattenToolHandles(wired === void 0 || wired === null ? [] : [wired]);
@@ -69163,7 +69359,7 @@ var parseInvokeArgs = (raw) => {
69163
69359
  return { ok: true, args: raw };
69164
69360
  };
69165
69361
  var findHandle = (tools, toolId) => tools.find((tool) => tool.toolId === toolId || tool.toolId.length === 0 && tool.name === toolId);
69166
- var toolInvokeNode = defineReactiveNode34({
69362
+ var toolInvokeNode = defineReactiveNode35({
69167
69363
  type: "common-tool-invoke",
69168
69364
  displayName: "Tool invoke",
69169
69365
  category: "Tools",
@@ -69179,7 +69375,7 @@ Typical uses:
69179
69375
  let lastCallKey;
69180
69376
  const tools = makeInput("tools", {
69181
69377
  name: "tools",
69182
- wireType: TOOL_HANDLE_WIRE_TYPE7,
69378
+ wireType: TOOL_HANDLE_WIRE_TYPE8,
69183
69379
  required: true
69184
69380
  });
69185
69381
  const toolId = makeInput("toolId", {
@@ -69226,7 +69422,7 @@ Typical uses:
69226
69422
  return throwError10(() => new Error(`Tool \xAB${payload.toolId}\xBB is not in the wired inventory.`));
69227
69423
  }
69228
69424
  lastCallKey = callKey;
69229
- return of14({
69425
+ return of15({
69230
69426
  handle,
69231
69427
  args: parsed.args,
69232
69428
  projectDir: payload.projectDir,
@@ -69249,7 +69445,7 @@ Typical uses:
69249
69445
  });
69250
69446
 
69251
69447
  // packages/common-nodes/dist/embeddings/embed-text/node.js
69252
- import { defineReactiveNode as defineReactiveNode35, withLoading as withLoading12 } from "@langflower/node-sdk";
69448
+ import { defineReactiveNode as defineReactiveNode36, withLoading as withLoading12 } from "@langflower/node-sdk";
69253
69449
  import { map as map20, switchMap as switchMap11 } from "rxjs";
69254
69450
 
69255
69451
  // packages/common-nodes/dist/embeddings/from-embedding.js
@@ -69307,7 +69503,7 @@ var formatEmbedPreview = (dim, vector) => {
69307
69503
  const suffix = vector.length > PREVIEW_FLOATS ? ", \u2026" : "";
69308
69504
  return `dim=${dim} [${shown.join(", ")}${suffix}]`;
69309
69505
  };
69310
- var embedTextNode = defineReactiveNode35({
69506
+ var embedTextNode = defineReactiveNode36({
69311
69507
  type: "common-embed-text",
69312
69508
  displayName: "Embed text",
69313
69509
  category: "Embeddings",
@@ -69365,7 +69561,7 @@ Typical uses:
69365
69561
  });
69366
69562
 
69367
69563
  // packages/common-nodes/dist/embeddings/embed-similarity/node.js
69368
- import { defineReactiveNode as defineReactiveNode36 } from "@langflower/node-sdk";
69564
+ import { defineReactiveNode as defineReactiveNode37 } from "@langflower/node-sdk";
69369
69565
  var toNumberVector = (value, label) => {
69370
69566
  if (!Array.isArray(value)) {
69371
69567
  throw new Error(`${label} must be a JSON number array`);
@@ -69408,7 +69604,7 @@ var cosineSimilarity = (left, right) => {
69408
69604
  }
69409
69605
  return sum;
69410
69606
  };
69411
- var embedSimilarityNode = defineReactiveNode36({
69607
+ var embedSimilarityNode = defineReactiveNode37({
69412
69608
  type: "common-embed-similarity",
69413
69609
  displayName: "Embed similarity",
69414
69610
  category: "Embeddings",
@@ -69444,7 +69640,7 @@ Typical uses:
69444
69640
  });
69445
69641
 
69446
69642
  // packages/common-nodes/dist/embeddings/embed-provider/node.js
69447
- import { defineReactiveNode as defineReactiveNode37, withLoading as withLoading13, EMBED_HANDLE_WIRE_TYPE } from "@langflower/node-sdk";
69643
+ import { defineReactiveNode as defineReactiveNode38, withLoading as withLoading13, EMBED_HANDLE_WIRE_TYPE } from "@langflower/node-sdk";
69448
69644
  import { distinctUntilChanged as distinctUntilChanged3, map as map21, switchMap as switchMap12 } from "rxjs";
69449
69645
  var embedPanelUiSchema2 = [
69450
69646
  {
@@ -69513,7 +69709,7 @@ var buildEmbedHandle = (options) => {
69513
69709
  }
69514
69710
  };
69515
69711
  };
69516
- var embedProviderNode = defineReactiveNode37({
69712
+ var embedProviderNode = defineReactiveNode38({
69517
69713
  type: "common-embed-provider",
69518
69714
  displayName: "Embed provider",
69519
69715
  category: "Embeddings",
@@ -69684,7 +69880,7 @@ async function buildSessionBootstrap(session, langflowerConfigService, resolveDe
69684
69880
  }
69685
69881
 
69686
69882
  // packages/server/dist/workflow/apply-editor-mutation.js
69687
- import { of as of15 } from "rxjs";
69883
+ import { of as of16 } from "rxjs";
69688
69884
 
69689
69885
  // packages/server/dist/workflow/workflow-persisted-inputs.js
69690
69886
  var valuesEqual = (left, right) => JSON.stringify(left) === JSON.stringify(right);
@@ -69859,7 +70055,7 @@ var materializeRuntimeNode = (projectDir, node, resolveDefinition) => {
69859
70055
  continue;
69860
70056
  }
69861
70057
  if (Object.hasOwn(node.inputs, config.portId)) {
69862
- input.connect(of15(node.inputs[config.portId]));
70058
+ input.connect(of16(node.inputs[config.portId]));
69863
70059
  continue;
69864
70060
  }
69865
70061
  if (config.defaultValue === void 0) {
@@ -69868,7 +70064,7 @@ var materializeRuntimeNode = (projectDir, node, resolveDefinition) => {
69868
70064
  if (config.defaultValue === null) {
69869
70065
  continue;
69870
70066
  }
69871
- input.connect(of15(config.defaultValue));
70067
+ input.connect(of16(config.defaultValue));
69872
70068
  }
69873
70069
  return {
69874
70070
  nodeId: node.id,
@@ -77207,6 +77403,9 @@ var emitBootstrap = async (client, context, session, checkpoints, draftControlle
77207
77403
  for (const ask of session.permissionAsks.list()) {
77208
77404
  clientEmit(client, "runner.permission.ask", ask);
77209
77405
  }
77406
+ for (const ask of session.askUserAsks.list()) {
77407
+ clientEmit(client, "runner.askUser.ask", ask);
77408
+ }
77210
77409
  const paletteResult = await context.paletteService.reload(context.projectDir);
77211
77410
  clientEmit(client, "palette.snapshot", paletteResult.payload);
77212
77411
  const customSnapshot = context.customPaletteService.getSnapshot();
@@ -78049,7 +78248,8 @@ var createToolHarness = (options) => {
78049
78248
  ...options.config.harness?.denyPaths !== void 0 ? { denyPaths: options.config.harness.denyPaths } : {},
78050
78249
  ...options.config.harness?.allowedRoots !== void 0 ? { allowedRoots: options.config.harness.allowedRoots } : {},
78051
78250
  ...hasPermissionRules ? { permission: options.permission } : {},
78052
- ...options.requestPermission !== void 0 ? { requestPermission: options.requestPermission } : {}
78251
+ ...options.requestPermission !== void 0 ? { requestPermission: options.requestPermission } : {},
78252
+ ...options.askUser !== void 0 ? { askUser: options.askUser } : {}
78053
78253
  });
78054
78254
  };
78055
78255
  var LIVE_WIRED_TOOLS_NODE_TYPES = /* @__PURE__ */ new Set([
@@ -78076,7 +78276,8 @@ var buildExecutionContext = async (context, runId, node, hooks, preloadedConfig,
78076
78276
  projectRoot: context.projectDir,
78077
78277
  config,
78078
78278
  permission,
78079
- requestPermission: (request) => hooks.requestPermission(hooks.runId, hooks.nodeId, request, hooks.emitPermissionAsk)
78279
+ requestPermission: (request) => hooks.requestPermission(hooks.runId, hooks.nodeId, request, hooks.emitPermissionAsk),
78280
+ askUser: (request) => hooks.requestAskUser(hooks.runId, hooks.nodeId, request, hooks.emitAskUserAsk)
78080
78281
  });
78081
78282
  const webFetch = createWebFetch({
78082
78283
  ...config.harness?.allowedHosts !== void 0 ? { allowedHosts: config.harness.allowedHosts } : {}
@@ -78160,7 +78361,7 @@ var applyObservableContextSeeds = (session, seeds) => {
78160
78361
  }
78161
78362
  return valueSeeds;
78162
78363
  };
78163
- var buildContextSeeds = async (session, context, runId, emitPermissionAsk, requestLangflowerBus, getLiveWiredTools2) => {
78364
+ var buildContextSeeds = async (session, context, runId, emitPermissionAsk, emitAskUserAsk, requestLangflowerBus, getLiveWiredTools2) => {
78164
78365
  const workflow = session.activeWorkflow;
78165
78366
  if (workflow === null) {
78166
78367
  return {};
@@ -78197,6 +78398,8 @@ var buildContextSeeds = async (session, context, runId, emitPermissionAsk, reque
78197
78398
  nodeId: node.id,
78198
78399
  requestPermission: session.permissionAsks.requestPermission,
78199
78400
  emitPermissionAsk,
78401
+ requestAskUser: session.askUserAsks.requestAskUser,
78402
+ emitAskUserAsk,
78200
78403
  ...requestLangflowerBus !== void 0 ? { requestLangflowerBus } : {},
78201
78404
  ...getLiveWiredTools2 !== void 0 ? { getLiveWiredTools: getLiveWiredTools2 } : {}
78202
78405
  }, config, runMcp?.handles, secrets);
@@ -78269,6 +78472,9 @@ var wireRunnerHandlers = (bridge, context, session, checkpoints) => {
78269
78472
  const emitPermissionAsk = (payload) => {
78270
78473
  bridgeEmit(bridge, "runner.permission.ask", payload);
78271
78474
  };
78475
+ const emitAskUserAsk = (payload) => {
78476
+ bridgeEmit(bridge, "runner.askUser.ask", payload);
78477
+ };
78272
78478
  const requestLangflowerBus = createLangflowerToolsRpc(bridge);
78273
78479
  const liveWiredTools = (agentNodeId) => getLiveWiredTools(session, agentNodeId);
78274
78480
  subscription.add(session.runtime.runner.events$.subscribe((event) => {
@@ -78304,7 +78510,7 @@ var wireRunnerHandlers = (bridge, context, session, checkpoints) => {
78304
78510
  const [clientInitialPayload, clientRunId] = raw.payload;
78305
78511
  const resolvedRunId = clientRunId ?? crypto.randomUUID();
78306
78512
  session.runnerStatus = "running";
78307
- const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, resolvedRunId, emitPermissionAsk, requestLangflowerBus, liveWiredTools));
78513
+ const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, resolvedRunId, emitPermissionAsk, emitAskUserAsk, requestLangflowerBus, liveWiredTools));
78308
78514
  const initialPayload = mergeSeeds(contextSeeds, clientInitialPayload);
78309
78515
  if (session.activeWorkflow !== null) {
78310
78516
  checkpoints.beginRun(resolvedRunId, session.activeWorkflow);
@@ -78331,7 +78537,7 @@ var wireRunnerHandlers = (bridge, context, session, checkpoints) => {
78331
78537
  const [nodeId, clientInitialPayload, clientRunId] = raw.payload;
78332
78538
  const resolvedRunId = clientRunId ?? crypto.randomUUID();
78333
78539
  session.runnerStatus = "running";
78334
- const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, resolvedRunId, emitPermissionAsk, requestLangflowerBus, liveWiredTools));
78540
+ const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, resolvedRunId, emitPermissionAsk, emitAskUserAsk, requestLangflowerBus, liveWiredTools));
78335
78541
  const initialPayload = mergeSeeds(contextSeeds, clientInitialPayload);
78336
78542
  if (session.activeWorkflow !== null) {
78337
78543
  checkpoints.beginRun(resolvedRunId, session.activeWorkflow);
@@ -78410,7 +78616,7 @@ var wireRunnerHandlers = (bridge, context, session, checkpoints) => {
78410
78616
  return;
78411
78617
  }
78412
78618
  session.runnerStatus = "running";
78413
- const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, checkpoint.runId, emitPermissionAsk, requestLangflowerBus, liveWiredTools));
78619
+ const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, checkpoint.runId, emitPermissionAsk, emitAskUserAsk, requestLangflowerBus, liveWiredTools));
78414
78620
  checkpoints.hydrateFromCheckpoint(checkpoint, workflow);
78415
78621
  const resumeOptions = checkpoints.resumeOptionsFromCheckpoint(checkpoint);
78416
78622
  const resumed = session.runtime.runner.resume({
@@ -78459,7 +78665,7 @@ var wireRunnerHandlers = (bridge, context, session, checkpoints) => {
78459
78665
  if (wasIdle) {
78460
78666
  const resolvedRunId = crypto.randomUUID();
78461
78667
  session.runnerStatus = "running";
78462
- const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, resolvedRunId, emitPermissionAsk, requestLangflowerBus, liveWiredTools));
78668
+ const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, resolvedRunId, emitPermissionAsk, emitAskUserAsk, requestLangflowerBus, liveWiredTools));
78463
78669
  if (session.activeWorkflow !== null) {
78464
78670
  checkpoints.beginRun(resolvedRunId, session.activeWorkflow);
78465
78671
  }
@@ -78487,6 +78693,18 @@ var wireRunnerHandlers = (bridge, context, session, checkpoints) => {
78487
78693
  bridgeEmit(bridge, "runner.permission.accepted", raw.payload);
78488
78694
  }
78489
78695
  }));
78696
+ subscription.add(bridge["runner.askUser.reply"].subscribe((raw) => {
78697
+ if (!isInboundEvent(raw)) {
78698
+ return;
78699
+ }
78700
+ const connected = findClientById(bridge, raw.clientId);
78701
+ if (connected === void 0) {
78702
+ return;
78703
+ }
78704
+ if (session.askUserAsks.reply(raw.payload)) {
78705
+ bridgeEmit(bridge, "runner.askUser.accepted", raw.payload);
78706
+ }
78707
+ }));
78490
78708
  subscription.add(bridge["runner.executionFeed.clear.requested"].subscribe((raw) => {
78491
78709
  if (!isInboundEvent(raw)) {
78492
78710
  return;
@@ -80168,6 +80386,11 @@ var parseListenPort = (raw) => {
80168
80386
  }
80169
80387
  return port;
80170
80388
  };
80389
+ var formatReadyLine = (input) => `LANGFLOWER_READY ${JSON.stringify({
80390
+ url: input.url,
80391
+ port: input.port,
80392
+ projectDir: input.projectDir
80393
+ })}`;
80171
80394
  var startProject = async (projectDirArg, opts) => {
80172
80395
  const projectDir = path22.resolve(projectDirArg);
80173
80396
  if (!await hasLangflowerProject(projectDir)) {
@@ -80191,8 +80414,17 @@ var startProject = async (projectDirArg, opts) => {
80191
80414
  console.warn(`Warning: --dev with --port ${String(opts.port)}: ng serve proxy still targets http://127.0.0.1:${String(DEFAULT_PORT)}/ws`);
80192
80415
  }
80193
80416
  } else {
80194
- await open_default(`http://127.0.0.1:${port}`);
80195
- console.log(`Langflower running at http://127.0.0.1:${port}`);
80417
+ const url = `http://127.0.0.1:${port}`;
80418
+ if (opts.noOpen !== true) {
80419
+ await open_default(url);
80420
+ }
80421
+ console.log(`Langflower running at ${url}`);
80422
+ writeSync(1, `${formatReadyLine({
80423
+ url,
80424
+ port,
80425
+ projectDir
80426
+ })}
80427
+ `);
80196
80428
  }
80197
80429
  console.log(`Project: ${projectDir}`);
80198
80430
  };
@@ -80201,6 +80433,7 @@ var runStartAction = async (projectDir, opts) => {
80201
80433
  const port = opts.port !== void 0 ? parseListenPort(opts.port) : void 0;
80202
80434
  await startProject(projectDir, {
80203
80435
  dev: opts.dev === true,
80436
+ noOpen: opts.open === false,
80204
80437
  ...port !== void 0 ? { port } : {}
80205
80438
  });
80206
80439
  } catch (error) {
@@ -80213,15 +80446,20 @@ var PORT_OPTION = [
80213
80446
  "-p, --port <number>",
80214
80447
  "HTTP listen port (overrides .langflower/config.json for this run)"
80215
80448
  ];
80449
+ var NO_OPEN_OPTION = [
80450
+ "--no-open",
80451
+ "Do not open the system browser after listen"
80452
+ ];
80453
+ var applyStartOptions = (command) => command.option("--dev", "Dev mode: API-only server, UI served by ng serve").option(...PORT_OPTION).option(...NO_OPEN_OPTION);
80216
80454
  var registerStartCommand = (program2) => {
80217
- program2.argument("[project-dir]", "Project directory", process.cwd()).option("--dev", "Dev mode: API-only server, UI served by ng serve").option(...PORT_OPTION).action(runStartAction);
80218
- program2.command("start").description("Start Langflower server and open UI in browser (alias)").argument("[project-dir]", "Project directory", process.cwd()).option("--dev", "Dev mode: API-only server, UI served by ng serve").option(...PORT_OPTION).action(runStartAction);
80455
+ applyStartOptions(program2.argument("[project-dir]", "Project directory", process.cwd())).action(runStartAction);
80456
+ applyStartOptions(program2.command("start").description("Start Langflower server and open UI in browser (alias)").argument("[project-dir]", "Project directory", process.cwd())).action(runStartAction);
80219
80457
  };
80220
80458
 
80221
80459
  // packages/cli/dist/cli.js
80222
80460
  var registerEvalCommand = (program2) => {
80223
80461
  program2.command("eval").description("Run a golden / fixture eval pack and fail closed when score < threshold").argument("<pack-dir>", "Directory containing pack.json").option("--project <dir>", "Project root for harness path fence (default: pack-dir)").option("--replay <file>", "JSON map of caseId \u2192 agent output (optional offline / CI agent)").action(async (packDirArg, opts) => {
80224
- const { runEvalCommand } = await import("./chunk-526FJL62.js");
80462
+ const { runEvalCommand } = await import("./chunk-AO33IM2J.js");
80225
80463
  await runEvalCommand(packDirArg, opts);
80226
80464
  });
80227
80465
  };