@agentdocumentformat/cli 0.8.2 → 0.8.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.
@@ -58,11 +58,15 @@ import {
58
58
  wrapper_default
59
59
  } from "./chunk-F5ELW46V.mjs";
60
60
  import {
61
+ AskAnswerError,
62
+ formatAskAnswers,
61
63
  formatOwnerCommandRow,
62
64
  formatTurnErrorRow,
65
+ normalizeAskAnswers,
63
66
  parseLoopToDisplay,
64
- providerContextCategory
65
- } from "./chunk-7JZXMDDF.mjs";
67
+ providerContextCategory,
68
+ summarizeAsk
69
+ } from "./chunk-WPT3FAFX.mjs";
66
70
  import {
67
71
  AiSdkProvider,
68
72
  createClaudeSubscriptionProvider,
@@ -60900,17 +60904,24 @@ var InputSchema24 = external_exports.object({
60900
60904
  };
60901
60905
 
60902
60906
  // src/main/tools/built-in/ask.tool.ts
60903
- var InputSchema25 = external_exports.object({
60904
- question: external_exports.string().min(1).describe("The question to ask the human operator. Be specific about what you need to proceed.")
60907
+ var OptionSchema = external_exports.object({
60908
+ label: external_exports.string().min(1).describe('Short choice text, e.g. "Postgres".'),
60909
+ description: external_exports.string().optional().describe('One line on what picking it means, e.g. "Needs a server; better for concurrent writes".')
60910
+ }), QuestionSchema = external_exports.object({
60911
+ question: external_exports.string().min(1).describe("The full question."),
60912
+ options: external_exports.array(OptionSchema).min(1).optional().describe('Choices to pick from. Omit for a free-text answer. "Other" is always offered.'),
60913
+ multiple: external_exports.boolean().optional().describe("Allow picking several options.")
60914
+ }), AskInputSchema = external_exports.object({
60915
+ questions: external_exports.array(QuestionSchema).min(1).describe("One or more questions, shown together as a form. The human may skip any of them.")
60905
60916
  }), AskTool = class {
60906
60917
  name = "ask";
60907
- description = "Ask the human operator a question and wait for their response. The turn pauses until the human replies. In autonomous mode, only use this when critically blocked and cannot proceed without human input.";
60908
- inputSchema = InputSchema25;
60918
+ description = 'Ask the human operator one or more questions as a form and wait for their answers. The turn pauses until they submit. Free-text question: {"question": "Anything I should avoid?"}. Choice question: {"question": "Which database?", "options": [{"label": "Postgres", "description": "Needs a server"}, {"label": "SQLite", "description": "Single file"}]}. Answers come back as Q:/A: pairs; skipped questions read "(skipped)". In autonomous mode, only use this when critically blocked and cannot proceed without human input.';
60919
+ inputSchema = AskInputSchema;
60909
60920
  category = "general";
60910
60921
  async execute(input, _workspace) {
60911
- let { question } = input;
60922
+ let { questions } = input;
60912
60923
  return {
60913
- content: JSON.stringify({ ask_question: question }),
60924
+ content: JSON.stringify({ ask_questions: questions }),
60914
60925
  isError: !1,
60915
60926
  endTurn: !1
60916
60927
  };
@@ -65598,7 +65609,7 @@ var AgentExecutor = class _AgentExecutor extends EventEmitter3 {
65598
65609
  this._lastTargetState = null, this.getState() !== "stopped" && this.abort(), this.emitEvent({ type: "state_changed", payload: { state: "off" }, timestamp: Date.now() });
65599
65610
  return;
65600
65611
  }
65601
- this.state === "thinking" || this.state === "tool_use" ? this._lastTargetState = targetState : (this.state = "idle", this.cancelScheduledRecovery("state_transition"), this.pendingTriggers = [], this.emitEvent({ type: "state_changed", payload: { state: targetState }, timestamp: Date.now() }));
65612
+ this.state === "thinking" || this.state === "tool_use" || this.state === "awaiting_ask" ? this._lastTargetState = targetState : (this.state = "idle", this.cancelScheduledRecovery("state_transition"), this.pendingTriggers = [], this.emitEvent({ type: "state_changed", payload: { state: targetState }, timestamp: Date.now() }));
65602
65613
  }
65603
65614
  /** Returns pending HIL approval requests so the renderer can restore UI after navigation. */
65604
65615
  getPendingApprovals() {
@@ -65705,16 +65716,17 @@ var AgentExecutor = class _AgentExecutor extends EventEmitter3 {
65705
65716
  * with prose, so the hub row carries no resolve callback and the UI offers
65706
65717
  * "jump to the agent" rather than a verdict.
65707
65718
  */
65708
- trackPendingAsk(requestId, question, resolve20) {
65709
- this.pendingAsks.set(requestId, { resolve: resolve20, question }), approvalHub.register({
65719
+ trackPendingAsk(requestId, questions, resolve20) {
65720
+ this.pendingAsks.set(requestId, { resolve: resolve20, questions }), approvalHub.register({
65710
65721
  id: this.notificationKeyFor(requestId),
65711
65722
  kind: "ask",
65712
65723
  requestId,
65713
65724
  filePath: this.approvalFilePath(),
65714
65725
  agentName: this.config.name,
65715
65726
  loop: this.approvalLoopName(),
65716
- preview: summarizeQuestion(question),
65717
- question,
65727
+ preview: summarizeQuestion(summarizeAsk(questions)),
65728
+ question: summarizeAsk(questions),
65729
+ questions,
65718
65730
  requestedAt: Date.now()
65719
65731
  });
65720
65732
  }
@@ -65723,7 +65735,7 @@ var AgentExecutor = class _AgentExecutor extends EventEmitter3 {
65723
65735
  let entries = [...this.pendingAsks.entries()];
65724
65736
  this.pendingAsks.clear();
65725
65737
  for (let [requestId, pending] of entries)
65726
- approvalHub.unregister(this.notificationKeyFor(requestId)), pending.resolve("");
65738
+ approvalHub.unregister(this.notificationKeyFor(requestId)), pending.resolve(pending.questions.map(() => null));
65727
65739
  }
65728
65740
  /**
65729
65741
  * Why an approval prompt is shown and whether "Always approve" is allowed.
@@ -66077,38 +66089,44 @@ var AgentExecutor = class _AgentExecutor extends EventEmitter3 {
66077
66089
  getPendingAsks() {
66078
66090
  let result = [];
66079
66091
  for (let [requestId, pending] of this.pendingAsks)
66080
- result.push({ requestId, question: pending.question });
66092
+ result.push({ requestId, question: summarizeAsk(pending.questions), questions: pending.questions });
66081
66093
  return result;
66082
66094
  }
66083
66095
  /**
66084
66096
  * Request human input for an ask tool call. Emits an `ask_request`
66085
66097
  * event and pauses the executor until the user responds via `resolveAsk`.
66086
66098
  */
66087
- requestAsk(question) {
66088
- let requestId = `ask_${++this.askCounter}`;
66089
- return this.setState("awaiting_ask"), this.emitEvent({
66099
+ requestAsk(questions) {
66100
+ let requestId = `ask_${++this.askCounter}`, question = summarizeAsk(questions);
66101
+ this.setState("awaiting_ask"), this.emitEvent({
66090
66102
  type: "ask_request",
66091
- payload: { requestId, question },
66103
+ payload: { requestId, question, questions },
66092
66104
  timestamp: Date.now()
66093
- }), this.emitRuntimeEvent("ask.requested", { request_id: requestId, question }), new Promise((resolve20) => {
66094
- this.trackPendingAsk(requestId, question, resolve20);
66105
+ }), this.emitRuntimeEvent("ask.requested", { request_id: requestId, question, questions });
66106
+ let answers = new Promise((resolve20) => {
66107
+ this.trackPendingAsk(requestId, questions, resolve20);
66095
66108
  });
66109
+ return { requestId, answers };
66096
66110
  }
66097
66111
  /**
66098
- * Resolve a pending ask request. Called from the IPC handler
66099
- * when the human types an answer.
66112
+ * Resolve a pending ask request with one answer per question (`null` =
66113
+ * skipped). Throws AskAnswerError when the payload does not fit the form;
66114
+ * the ask stays pending.
66100
66115
  */
66101
- resolveAsk(requestId, answer) {
66116
+ resolveAsk(requestId, answers) {
66102
66117
  let pending = this.pendingAsks.get(requestId);
66103
66118
  if (pending) {
66119
+ let normalized = normalizeAskAnswers(pending.questions, answers);
66104
66120
  this.pendingAsks.delete(requestId), approvalHub.unregister(this.notificationKeyFor(requestId), "answered");
66105
- let text = typeof answer == "string" ? answer : "";
66121
+ let answered = normalized.filter((a) => a !== null).length, text = answered > 0 ? formatAskAnswers(pending.questions, normalized) : "";
66106
66122
  this.emitRuntimeEvent("ask.resolved", {
66107
66123
  request_id: requestId,
66108
- has_response: text.length > 0,
66124
+ has_response: answered > 0,
66125
+ answered,
66126
+ skipped: normalized.length - answered,
66109
66127
  response_length: text.length,
66110
- ...text.length > 0 ? { preview: text.slice(0, 200) } : {}
66111
- }), pending.resolve(answer);
66128
+ ...text.length > 0 ? { preview: sliceWellFormed(text, 0, 200) } : {}
66129
+ }), pending.resolve(normalized);
66112
66130
  }
66113
66131
  }
66114
66132
  hasPendingSuspend() {
@@ -66678,25 +66696,34 @@ Provider response: ${validation.error}` : "");
66678
66696
  },
66679
66697
  timestamp: Date.now()
66680
66698
  }), toolBlock.name === "ask") {
66681
- let askInput = toolBlock.input, answer = await this.requestAsk(askInput.question);
66699
+ let parsed = AskInputSchema.safeParse(toolBlock.input);
66700
+ if (!parsed.success) {
66701
+ let content2 = `Invalid ask input: ${parsed.error.issues.map((i) => `${i.path.join(".") || "input"}: ${i.message}`).join("; ")}`;
66702
+ toolResults.push({ type: "tool_result", tool_use_id: toolBlock.id, content: content2, is_error: !0 }), this.emitEvent({
66703
+ type: "tool_call_result",
66704
+ payload: { name: "ask", id: toolBlock.id, result: { content: content2, isError: !0 } },
66705
+ timestamp: Date.now()
66706
+ }), this.emitSyntheticToolEvents("ask", toolBlock.id, toolBlock.input, { content: content2, isError: !0 });
66707
+ continue;
66708
+ }
66709
+ let { questions } = parsed.data, ask = this.requestAsk(questions), answers = await ask.answers;
66682
66710
  if (this._interruptRestart || this._ownerStateTransitionRequested) break;
66683
- this.setState("tool_use"), toolResults.push({
66711
+ this.setState("tool_use");
66712
+ let content = formatAskAnswers(questions, answers);
66713
+ toolResults.push({
66684
66714
  type: "tool_result",
66685
66715
  tool_use_id: toolBlock.id,
66686
- content: `Human answered: ${answer}`,
66716
+ content,
66687
66717
  is_error: !1
66688
66718
  }), this.emitEvent({
66689
66719
  type: "ask_response",
66690
- payload: { question: askInput.question, answer },
66720
+ payload: { requestId: ask.requestId, result: content },
66691
66721
  timestamp: Date.now()
66692
66722
  }), this.emitEvent({
66693
66723
  type: "tool_call_result",
66694
- payload: { name: "ask", id: toolBlock.id, result: { content: `Human answered: ${answer}`, isError: !1 } },
66724
+ payload: { name: "ask", id: toolBlock.id, result: { content, isError: !1 } },
66695
66725
  timestamp: Date.now()
66696
- }), this.emitSyntheticToolEvents("ask", toolBlock.id, toolBlock.input, {
66697
- content: `Human answered: ${answer}`,
66698
- isError: !1
66699
- });
66726
+ }), this.emitSyntheticToolEvents("ask", toolBlock.id, toolBlock.input, { content, isError: !1 });
66700
66727
  continue;
66701
66728
  }
66702
66729
  if (!toolSnapshot.enabledNames.has(toolBlock.name)) {
@@ -70024,7 +70051,7 @@ function urlRecipientError(recipient) {
70024
70051
  }
70025
70052
 
70026
70053
  // src/main/tools/built-in/msg-send.tool.ts
70027
- var InputSchema26 = external_exports.object({
70054
+ var InputSchema25 = external_exports.object({
70028
70055
  recipient: external_exports.string().min(1).optional().describe('DID of the recipient agent (e.g., "did:key:..."). Required unless parent_id is provided, in which case the runtime resolves recipient from the inbox message. For adapter recipients use the format "type:id" (e.g., "telegram:123").'),
70029
70056
  address: external_exports.string().url().optional().describe('Delivery URL for mesh recipients (e.g., "http://127.0.0.1:7295/agents/agent-handle/inbox"). Required unless parent_id is provided or sending to an adapter recipient.'),
70030
70057
  content: external_exports.string().min(1).describe("The message content to send."),
@@ -70055,7 +70082,7 @@ function resolveParentReplyAddress(parentMsg) {
70055
70082
  var SendMessageTool = class {
70056
70083
  name = "msg_send";
70057
70084
  description = `Send a message to another agent. Modes: (1) recipient DID + address for direct remote send; (2) parent_id to reply (runtime resolves recipient and address from the inbox row); (3) bare handle with no address \u2014 works only for locally-registered agents on this runtime; the runtime resolves the address from the handle and enforces the recipient's visibility tier. For remote agents, always provide an explicit address from agent_discover. Adapter recipients use "type:id" (e.g. "telegram:123").`;
70058
- inputSchema = InputSchema26;
70085
+ inputSchema = InputSchema25;
70059
70086
  category = "communication";
70060
70087
  sendFn;
70061
70088
  checkFn;
@@ -70159,7 +70186,7 @@ var SendMessageTool = class {
70159
70186
  };
70160
70187
 
70161
70188
  // src/main/tools/built-in/agent-discover.tool.ts
70162
- var VisibilityEnum = external_exports.enum(["directory", "localhost", "lan", "public", "off"]), InputSchema27 = external_exports.object({
70189
+ var VisibilityEnum = external_exports.enum(["directory", "localhost", "lan", "public", "off"]), InputSchema26 = external_exports.object({
70163
70190
  scope: external_exports.enum(["local", "all"]).optional().default("local").describe('Discovery scope. "local" (default) returns only agents on this runtime. "all" also includes remote peers found via mDNS, tailnet sweep, or manual peer entries.'),
70164
70191
  visibility: external_exports.array(VisibilityEnum).optional().describe("If provided, return only agents whose declared visibility tier is in this list."),
70165
70192
  handle: external_exports.string().optional().describe("Optional case-insensitive substring match on the agent handle."),
@@ -70168,7 +70195,7 @@ var VisibilityEnum = external_exports.enum(["directory", "localhost", "lan", "pu
70168
70195
  }), AgentDiscoverTool = class {
70169
70196
  name = "agent_discover";
70170
70197
  description = `Discover agents reachable from this agent. Returns signed agent cards (did, handle, description, endpoints, public_key, policies, visibility, source, runtime_did) plus each local agent's live "status" line \u2014 poll this to watch what peers are working on without messaging them. The visibility tier of each card indicates how broadly the agent is exposed. Filter by visibility tier, handle substring, or description substring. Use scope="local" (default) for same-runtime only; "all" also includes remote peers found via mDNS, tailnet sweep, or manual peer entries \u2014 the source field says which (silently empty when discovery is unavailable).`;
70171
- inputSchema = InputSchema27;
70198
+ inputSchema = InputSchema26;
70172
70199
  category = "communication";
70173
70200
  getDirectoryFn;
70174
70201
  getRemoteDirectoryFn;
@@ -70314,7 +70341,7 @@ function resolveLoopPool(accessor) {
70314
70341
  }
70315
70342
 
70316
70343
  // src/main/tools/built-in/loop-send.tool.ts
70317
- var LOOP_SEND_MAX_CHARS = 48e3, InputSchema28 = external_exports.object({
70344
+ var LOOP_SEND_MAX_CHARS = 48e3, InputSchema27 = external_exports.object({
70318
70345
  to_loop: external_exports.string().min(1).describe(
70319
70346
  'Name of the loop to deliver to, from loop_list. "main" is the membrane-facing loop.'
70320
70347
  ),
@@ -70327,7 +70354,7 @@ var LOOP_SEND_MAX_CHARS = 48e3, InputSchema28 = external_exports.object({
70327
70354
  }), LoopSendTool = class {
70328
70355
  name = "loop_send";
70329
70356
  description = "Send a message to another cognition loop of this same agent. Use loop_list to see the loops and their goals. The message is appended to that loop's stream stamped with your loop name; without wake it is read the next time that loop runs. With wake, an idle target runs a turn immediately and a busy one reads it at its next step, mid-turn. The message stays inside the agent (use msg_send to reach another agent or a person).";
70330
- inputSchema = InputSchema28;
70357
+ inputSchema = InputSchema27;
70331
70358
  category = "self";
70332
70359
  getPool;
70333
70360
  constructor(getPool) {
@@ -70377,10 +70404,10 @@ var LOOP_SEND_MAX_CHARS = 48e3, InputSchema28 = external_exports.object({
70377
70404
  };
70378
70405
 
70379
70406
  // src/main/tools/built-in/loop-list.tool.ts
70380
- var InputSchema29 = external_exports.object({}), LoopListTool = class {
70407
+ var InputSchema28 = external_exports.object({}), LoopListTool = class {
70381
70408
  name = "loop_list";
70382
70409
  description = 'List the cognition loops of this agent \u2014 name, goal, whether each is enabled, and whether it is running right now. Includes "main" (the loop that faces the outside world) and marks which one you are. Use it to pick a target for loop_send.';
70383
- inputSchema = InputSchema29;
70410
+ inputSchema = InputSchema28;
70384
70411
  category = "self";
70385
70412
  getPool;
70386
70413
  constructor(getPool) {
@@ -70446,7 +70473,7 @@ var LoopConfigInputSchema = external_exports.object({
70446
70473
  tools: external_exports.array(external_exports.string().min(1)).max(LOOP_TOOLS_MAX).optional().describe(
70447
70474
  `Absolute allow-list, intersected with your enabled tools; nothing implicit. Omit for ${DEFAULT_NEW_LOOP_TOOLS.join(" + ")}; [] for a mute loop. Include sys_set_state to yield.`
70448
70475
  )
70449
- }).describe("Loop definition. Full definition for create; partial patch for update."), InputSchema30 = external_exports.object({
70476
+ }).describe("Loop definition. Full definition for create; partial patch for update."), InputSchema29 = external_exports.object({
70450
70477
  // No `list`: that is `loop_list`, an ordinary tool you hold like every other
70451
70478
  // loop does. Two ways to enumerate the same roster was one too many.
70452
70479
  action: external_exports.enum(["create", "get", "update", "delete"]).describe(
@@ -70461,7 +70488,7 @@ function errorResult(content) {
70461
70488
  var LoopManageTool = class {
70462
70489
  name = "loop_manage";
70463
70490
  description = "Create, inspect, update and delete this agent's inner cognition loops: named streams inside you that share your file, identity and credentials but run their own stream with their own goal and a subset of your tools. Use loop_list to see which loops exist; this tool changes them. Deleting a loop archives its stream to the audit log first. Only the main loop can call this, and loops cannot create loops.";
70464
- inputSchema = InputSchema30;
70491
+ inputSchema = InputSchema29;
70465
70492
  category = "self";
70466
70493
  requireApproval = !1;
70467
70494
  getPool;
@@ -70678,7 +70705,7 @@ Excluded for now: ${disabled.join(", ")} \u2014 ${disabled.length === 1 ? "that
70678
70705
  };
70679
70706
 
70680
70707
  // src/main/tools/built-in/ws-connect.tool.ts
70681
- var InputSchema31 = external_exports.object({
70708
+ var InputSchema30 = external_exports.object({
70682
70709
  id: external_exports.string().optional().describe("ID of a configured connection to start"),
70683
70710
  url: external_exports.string().url().optional().describe("WebSocket URL for ad-hoc connection"),
70684
70711
  did: external_exports.string().optional().describe("Expected remote DID"),
@@ -70690,7 +70717,7 @@ var InputSchema31 = external_exports.object({
70690
70717
  }), WsConnectTool = class {
70691
70718
  name = "ws_connect";
70692
70719
  description = "Start a WebSocket connection. Either provide an ID of a configured connection, or a URL for an ad-hoc connection.";
70693
- inputSchema = InputSchema31;
70720
+ inputSchema = InputSchema30;
70694
70721
  category = "communication";
70695
70722
  connectFn;
70696
70723
  getSecurityConfig;
@@ -70725,13 +70752,13 @@ var InputSchema31 = external_exports.object({
70725
70752
  };
70726
70753
 
70727
70754
  // src/main/tools/built-in/ws-disconnect.tool.ts
70728
- var InputSchema32 = external_exports.object({
70755
+ var InputSchema31 = external_exports.object({
70729
70756
  connection_id: external_exports.string().optional().describe("Connection ID to close"),
70730
70757
  id: external_exports.string().optional().describe("Config ID to disconnect")
70731
70758
  }), WsDisconnectTool = class {
70732
70759
  name = "ws_disconnect";
70733
70760
  description = "Close a WebSocket connection by connection_id or config id.";
70734
- inputSchema = InputSchema32;
70761
+ inputSchema = InputSchema31;
70735
70762
  category = "communication";
70736
70763
  disconnectFn;
70737
70764
  constructor(disconnectFn) {
@@ -70754,12 +70781,12 @@ var InputSchema32 = external_exports.object({
70754
70781
  };
70755
70782
 
70756
70783
  // src/main/tools/built-in/ws-connections.tool.ts
70757
- var InputSchema33 = external_exports.object({
70784
+ var InputSchema32 = external_exports.object({
70758
70785
  direction: external_exports.enum(["inbound", "outbound"]).optional().describe("Filter by direction")
70759
70786
  }), WsConnectionsTool = class {
70760
70787
  name = "ws_connections";
70761
70788
  description = "List active WebSocket connections (both inbound and outbound).";
70762
- inputSchema = InputSchema33;
70789
+ inputSchema = InputSchema32;
70763
70790
  category = "communication";
70764
70791
  listFn;
70765
70792
  constructor(listFn) {
@@ -70782,7 +70809,7 @@ var InputSchema33 = external_exports.object({
70782
70809
  };
70783
70810
 
70784
70811
  // src/main/tools/built-in/ws-send.tool.ts
70785
- var InputSchema34 = external_exports.object({
70812
+ var InputSchema33 = external_exports.object({
70786
70813
  connection_id: external_exports.string().describe("Target connection ID"),
70787
70814
  data: external_exports.union([
70788
70815
  external_exports.string(),
@@ -70792,7 +70819,7 @@ var InputSchema34 = external_exports.object({
70792
70819
  }), WsSendTool = class {
70793
70820
  name = "ws_send";
70794
70821
  description = "Send text or binary data over an active WebSocket connection. Awaits socket drain when buffered bytes exceed the connection high-water mark.";
70795
- inputSchema = InputSchema34;
70822
+ inputSchema = InputSchema33;
70796
70823
  category = "communication";
70797
70824
  sendFn;
70798
70825
  constructor(sendFn) {
@@ -70844,7 +70871,7 @@ function umbilicalFilterIsWildcard(filter2) {
70844
70871
  let types = filter2?.event_types;
70845
70872
  return !types || types.length === 0 ? !0 : types.some((t) => t === "*" || t.endsWith(".*"));
70846
70873
  }
70847
- var InputSchema35 = external_exports.object({
70874
+ var InputSchema34 = external_exports.object({
70848
70875
  a: EndpointSchema,
70849
70876
  b: EndpointSchema,
70850
70877
  bidirectional: external_exports.boolean().optional(),
@@ -70872,7 +70899,7 @@ var InputSchema35 = external_exports.object({
70872
70899
  manager;
70873
70900
  name = "stream_bind";
70874
70901
  description = "Bind two runtime-managed byte endpoints so bytes are pumped outside the agent loop. Supports WebSocket, TCP, host process, and umbilical source endpoints.";
70875
- inputSchema = InputSchema35;
70902
+ inputSchema = InputSchema34;
70876
70903
  category = "communication";
70877
70904
  async execute(input, _workspace) {
70878
70905
  let parsed = input;
@@ -70893,7 +70920,7 @@ var InputSchema35 = external_exports.object({
70893
70920
  };
70894
70921
 
70895
70922
  // src/main/tools/built-in/stream-unbind.tool.ts
70896
- var InputSchema36 = external_exports.object({
70923
+ var InputSchema35 = external_exports.object({
70897
70924
  binding_id: external_exports.string().min(1)
70898
70925
  }), StreamUnbindTool = class {
70899
70926
  constructor(manager) {
@@ -70902,7 +70929,7 @@ var InputSchema36 = external_exports.object({
70902
70929
  manager;
70903
70930
  name = "stream_unbind";
70904
70931
  description = "Terminate an active stream binding by ID.";
70905
- inputSchema = InputSchema36;
70932
+ inputSchema = InputSchema35;
70906
70933
  category = "communication";
70907
70934
  async execute(input, _workspace) {
70908
70935
  let parsed = input;
@@ -70923,14 +70950,14 @@ var InputSchema36 = external_exports.object({
70923
70950
  };
70924
70951
 
70925
70952
  // src/main/tools/built-in/stream-bindings.tool.ts
70926
- var InputSchema37 = external_exports.object({}), StreamBindingsTool = class {
70953
+ var InputSchema36 = external_exports.object({}), StreamBindingsTool = class {
70927
70954
  constructor(manager) {
70928
70955
  this.manager = manager;
70929
70956
  }
70930
70957
  manager;
70931
70958
  name = "stream_bindings";
70932
70959
  description = "List active stream bindings for this agent, including sanitized endpoint summaries and byte counters.";
70933
- inputSchema = InputSchema37;
70960
+ inputSchema = InputSchema36;
70934
70961
  category = "communication";
70935
70962
  async execute(_input, _workspace) {
70936
70963
  return { content: JSON.stringify(this.manager.bindingsSummary()), isError: !1 };
@@ -71694,7 +71721,7 @@ function ensureHostWorkspace(agentId) {
71694
71721
  }
71695
71722
 
71696
71723
  // src/main/tools/built-in/fs-transfer.tool.ts
71697
- var Endpoint = external_exports.enum(["vfs", "isolated", "shared", "host"]), InputSchema38 = external_exports.object({
71724
+ var Endpoint = external_exports.enum(["vfs", "isolated", "shared", "host"]), InputSchema37 = external_exports.object({
71698
71725
  from: Endpoint.describe("Source environment: 'vfs', 'isolated', 'shared', or 'host'."),
71699
71726
  to: Endpoint.describe("Destination environment: 'vfs', 'isolated', 'shared', or 'host'."),
71700
71727
  path: external_exports.string().describe("Path of the file or directory to transfer (relative to the environment root)."),
@@ -71708,7 +71735,7 @@ var Endpoint = external_exports.enum(["vfs", "isolated", "shared", "host"]), Inp
71708
71735
  capabilities;
71709
71736
  name = "fs_transfer";
71710
71737
  description = "Transfer files or directories between environments: 'vfs' (agent virtual filesystem), 'isolated' (agent container), 'shared' (shared container), or 'host' (host workspace). 'from' and 'to' must differ.";
71711
- inputSchema = InputSchema38;
71738
+ inputSchema = InputSchema37;
71712
71739
  category = "filesystem";
71713
71740
  async execute(input, workspace) {
71714
71741
  let { from, to, path, save_as } = input, sourcePath, destPath;
@@ -74246,14 +74273,14 @@ function truncate(text, maxBytes) {
74246
74273
  }
74247
74274
 
74248
74275
  // src/main/tools/built-in/chat-info.tool.ts
74249
- var InputSchema39 = external_exports.object({
74276
+ var InputSchema38 = external_exports.object({
74250
74277
  adapter: external_exports.string().min(1).describe('Channel adapter type to query: "telegram", "discord", "slack", "whatsapp", ... Must be enabled and connected for this agent.'),
74251
74278
  chat_id: external_exports.string().min(1).describe('Platform chat/channel id \u2014 the source_context.chat_id (or channel_id) from an inbox message. E.g. Telegram "-100123...", Slack "C0123...", WhatsApp "xyz@g.us".'),
74252
74279
  limit: external_exports.number().int().min(1).max(100).optional().describe("Max participants to return (default 50).")
74253
74280
  }), ChatInfoTool = class {
74254
74281
  name = "chat_info";
74255
74282
  description = "Look up a chat/channel you are in via a connected channel adapter: title, description, member roster (truncated), participant count. Read-only. Use when the meta.group context on an inbound message is not enough. Note: Telegram can only list admins; email has no live roster (recipients are in source_context.to/cc via msg_read).";
74256
- inputSchema = InputSchema39;
74283
+ inputSchema = InputSchema38;
74257
74284
  category = "communication";
74258
74285
  chatInfoFn;
74259
74286
  constructor(chatInfoFn) {
@@ -74527,7 +74554,7 @@ async function writeBackCredentialFiles(store2, serverCfg, target, capturedAt, l
74527
74554
  }
74528
74555
 
74529
74556
  // src/main/tools/built-in/mcp-install.tool.ts
74530
- var InputSchema40 = external_exports.object({
74557
+ var InputSchema39 = external_exports.object({
74531
74558
  package: external_exports.string().optional().describe('Package name (npm/pypi) or command path (custom). E.g. "@modelcontextprotocol/server-github", "garmin-mcp", "node"'),
74532
74559
  type: external_exports.enum(["npm", "pypi", "custom", "http"]).default("npm").describe("Package type: npm, pypi, custom, or http"),
74533
74560
  url: external_exports.string().url().optional().describe("Streamable HTTP MCP URL. Required when type=http."),
@@ -74568,7 +74595,7 @@ var McpInstallTool = class {
74568
74595
  getRegistrations;
74569
74596
  name = "mcp_install";
74570
74597
  description = "Install an MCP server package, attach a custom server, or connect a Streamable HTTP MCP server. If the requested name or package is already configured in ADF Studio Settings and available to agents, this tool ATTACHES that registration instead of installing a fresh copy \u2014 the user's configuration, credentials, and authorization come along. Provide package (name or command) for npm/pypi/custom, or url for type=http. Optionally pass env with credential values to store in agent identity, and credential_files for file-shaped credentials (OAuth keys/token stores) that are kept sealed in the keystore and materialized where the server runs. Set host=true to run on host (requires host_access). For an OAuth remote (type=http) that has no stored token yet, attaching it opens a browser for the user to sign in before it connects \u2014 only in the interactive (Studio) runtime; a headless/background runtime instead reports that the user must sign in once from Settings. For the agent's visible persistent browser, prefer the maintained @playwright/mcp package; it attaches to ADF-owned Chromium. New tools are discovered immediately, enabled and visible, and protected by human approval. Use mcp_restart to reconnect if discovery is delayed.";
74571
- inputSchema = InputSchema40;
74598
+ inputSchema = InputSchema39;
74572
74599
  category = "system";
74573
74600
  /** Find the Settings registration this install request matches, if any. */
74574
74601
  findMatchingRegistration(parsed, derivedName) {
@@ -74837,7 +74864,7 @@ var McpInstallTool = class {
74837
74864
  };
74838
74865
 
74839
74866
  // src/main/tools/built-in/mcp-uninstall.tool.ts
74840
- var InputSchema41 = external_exports.object({
74867
+ var InputSchema40 = external_exports.object({
74841
74868
  name: external_exports.string().describe("Name of the MCP server to uninstall")
74842
74869
  }), McpUninstallTool = class {
74843
74870
  constructor(onServerUninstalled) {
@@ -74846,7 +74873,7 @@ var InputSchema41 = external_exports.object({
74846
74873
  onServerUninstalled;
74847
74874
  name = "mcp_uninstall";
74848
74875
  description = "Remove an MCP server from this agent. Removes the server configuration and all associated tool declarations.";
74849
- inputSchema = InputSchema41;
74876
+ inputSchema = InputSchema40;
74850
74877
  category = "system";
74851
74878
  async execute(input, workspace) {
74852
74879
  let { name: serverName } = input, config = workspace.getAgentConfig(), servers = config.mcp?.servers ?? [], idx = servers.findIndex((s) => s.name === serverName);
@@ -74873,7 +74900,7 @@ var InputSchema41 = external_exports.object({
74873
74900
  };
74874
74901
 
74875
74902
  // src/main/tools/built-in/mcp-restart.tool.ts
74876
- var InputSchema42 = external_exports.object({
74903
+ var InputSchema41 = external_exports.object({
74877
74904
  name: external_exports.string().describe("Name of the MCP server to reconnect")
74878
74905
  }), McpRestartTool = class {
74879
74906
  constructor(onServerRestarted) {
@@ -74882,7 +74909,7 @@ var InputSchema42 = external_exports.object({
74882
74909
  onServerRestarted;
74883
74910
  name = "mcp_restart";
74884
74911
  description = "Reconnect an MCP server already configured on this agent and refresh its discovered tools. Use this after installing a server, changing credentials, or when tool discovery returned no tools.";
74885
- inputSchema = InputSchema42;
74912
+ inputSchema = InputSchema41;
74886
74913
  category = "system";
74887
74914
  async execute(input, workspace) {
74888
74915
  let { name: serverName } = input;
@@ -74960,7 +74987,7 @@ function protectionGatedRegistry(registry2, gate) {
74960
74987
  }
74961
74988
 
74962
74989
  // src/main/tools/shell/shell.tool.ts
74963
- var InputSchema43 = external_exports.object({
74990
+ var InputSchema42 = external_exports.object({
74964
74991
  command: external_exports.string().describe("Bash command or pipeline")
74965
74992
  }), ShellTool = class {
74966
74993
  name = "adf_shell";
@@ -74996,7 +75023,7 @@ Execution surfaces \u2014 pick by where the work must run:
74996
75023
  Event context arrives as env vars (\`$EVENT_TYPE\`, \`$MSG_ID\`, \`$TIMER_ID\`, ...) \u2014 \`env\` lists them.
74997
75024
 
74998
75025
  Full guide: ${DOCS_GUIDES_URL}/tools.md`;
74999
- inputSchema = InputSchema43;
75026
+ inputSchema = InputSchema42;
75000
75027
  category = "system";
75001
75028
  toolRegistry;
75002
75029
  workspace;
@@ -86865,11 +86892,19 @@ var LOOP_PATCH_FIELDS = ["goal", "enabled", "autostart", "autonomous", "model",
86865
86892
  let managed = target.managed, asks = this.askExecutors(managed).flatMap(({ loop, executor }) => executor.getPendingAsks().map((ask) => ({ ...ask, loop })));
86866
86893
  return { agentId: managed.id, asks };
86867
86894
  }
86868
- /** Request ids are per executor, so `loop` disambiguates; absent = the first loop holding that id. */
86869
- answerAgentAsk(agentId, requestId, answer, loop) {
86895
+ /**
86896
+ * `answers`: one per question (`null` = skipped); a payload that does not fit the form is a 400 and the ask stays pending.
86897
+ * Request ids are per executor, so `loop` disambiguates; absent = the first loop holding that id.
86898
+ */
86899
+ answerAgentAsk(agentId, requestId, answers, loop) {
86870
86900
  let managed = this.requireAgent(agentId), holder = this.askExecutors(managed).find((entry) => (loop === void 0 || entry.loop === loop) && entry.executor.getPendingAsks().some((ask) => ask.requestId === requestId));
86871
86901
  if (!holder) throw new RuntimeLoopError(`Ask request "${requestId}" not found${loop ? ` in loop "${loop}"` : ""} (already answered, or never asked).`, 404, "ask_not_found");
86872
- return holder.executor.resolveAsk(requestId, answer), { agentId: managed.id, requestId, loop: holder.loop, answered: !0 };
86902
+ try {
86903
+ holder.executor.resolveAsk(requestId, answers);
86904
+ } catch (err) {
86905
+ throw err instanceof AskAnswerError ? new RuntimeLoopError(`Invalid answers: ${err.message}.`, 400, "invalid_answers") : err;
86906
+ }
86907
+ return { agentId: managed.id, requestId, loop: holder.loop, answered: !0 };
86873
86908
  }
86874
86909
  /**
86875
86910
  * One loop's per-request context breakdown (Studio's context modal; daemon
@@ -99034,7 +99069,7 @@ data: {"cursor":42,"event":{"seq":7,"event_type":"agent.state.changed","turn_id"
99034
99069
  "Tasks & approvals"
99035
99070
  ],
99036
99071
  summary: "Answer an ask request",
99037
- description: "Request ids are numbered per loop: pass the `loop` from GET \u2026/asks when two loops ask at once; without it the first loop holding the id is answered. An id no loop holds (already answered, or never asked) answers 404 `ask_not_found`.",
99072
+ description: "Answer with one entry per question, in order: a string (free text, or one option label), an array of strings (several picks, for a question with `multiple`), or `null` to skip. A value that is not one of the question's option labels is the human's own (\"Other\") text. Answers that do not fit the form (wrong count, a value that is not a string) answer 400 `invalid_answers` and the ask stays pending. The agent receives `Q: <question>` / `A: <answer>` pairs (`(skipped)` for a skipped question, `Other: <text>` for free text beside options). Request ids are numbered per loop: pass the `loop` from GET \u2026/asks when two loops ask at once; without it the first loop holding the id is answered. An id no loop holds (already answered, or never asked) answers 404 `ask_not_found`.",
99038
99073
  operationId: "answerAgentAsk",
99039
99074
  parameters: [
99040
99075
  {
@@ -99066,7 +99101,22 @@ data: {"cursor":42,"event":{"seq":7,"event_type":"agent.state.changed","turn_id"
99066
99101
  }
99067
99102
  },
99068
99103
  "400": {
99069
- $ref: "#/components/responses/BadRequest"
99104
+ description: "`answers` missing, not an array, the wrong length, or holding a non-string entry (`invalid_answers`); a bad `loop` (`bad_request`)",
99105
+ content: {
99106
+ "application/json": {
99107
+ schema: {
99108
+ $ref: "#/components/schemas/ErrorResponse"
99109
+ },
99110
+ examples: {
99111
+ invalid_answers: {
99112
+ value: {
99113
+ error: "Invalid answers: answers has 1 entries but the ask has 2 questions.",
99114
+ code: "invalid_answers"
99115
+ }
99116
+ }
99117
+ }
99118
+ }
99119
+ }
99070
99120
  },
99071
99121
  "401": {
99072
99122
  $ref: "#/components/responses/Unauthorized"
@@ -111681,22 +111731,92 @@ data: {"cursor":13,"kind":"executor","agentId":"\u2026","filePath":"/agents/agen
111681
111731
  skippedProtection: 1
111682
111732
  }
111683
111733
  },
111684
- AskRespondBody: {
111734
+ AskQuestion: {
111685
111735
  type: "object",
111686
111736
  required: [
111687
- "answer"
111737
+ "question"
111688
111738
  ],
111739
+ description: 'One question of an ask form. No `options` = free text; with `options` = one pick (several with `multiple`). Free ("Other") text and skipping are always allowed.',
111689
111740
  properties: {
111690
- answer: {
111741
+ question: {
111691
111742
  type: "string"
111692
111743
  },
111744
+ options: {
111745
+ type: "array",
111746
+ items: {
111747
+ type: "object",
111748
+ required: [
111749
+ "label"
111750
+ ],
111751
+ properties: {
111752
+ label: {
111753
+ type: "string"
111754
+ },
111755
+ description: {
111756
+ type: "string"
111757
+ }
111758
+ }
111759
+ }
111760
+ },
111761
+ multiple: {
111762
+ type: "boolean",
111763
+ description: "Several options may be picked"
111764
+ }
111765
+ },
111766
+ example: {
111767
+ question: "Which regions?",
111768
+ options: [
111769
+ {
111770
+ label: "eu-west"
111771
+ },
111772
+ {
111773
+ label: "us-east",
111774
+ description: "Closest to most users"
111775
+ }
111776
+ ],
111777
+ multiple: !0
111778
+ }
111779
+ },
111780
+ AskRespondBody: {
111781
+ type: "object",
111782
+ required: [
111783
+ "answers"
111784
+ ],
111785
+ properties: {
111786
+ answers: {
111787
+ type: "array",
111788
+ description: "One per question, in order: a string, an array of strings (picks), or null (skipped)",
111789
+ items: {
111790
+ oneOf: [
111791
+ {
111792
+ type: "string"
111793
+ },
111794
+ {
111795
+ type: "array",
111796
+ items: {
111797
+ type: "string"
111798
+ }
111799
+ },
111800
+ {
111801
+ type: "null"
111802
+ }
111803
+ ]
111804
+ }
111805
+ },
111693
111806
  loop: {
111694
111807
  type: "string",
111695
111808
  description: "The loop that asked (GET \u2026/asks lists it); absent = the first loop holding the id"
111696
111809
  }
111697
111810
  },
111698
111811
  example: {
111699
- answer: "Yes, go ahead."
111812
+ answers: [
111813
+ "Yes, go ahead.",
111814
+ [
111815
+ "eu-west",
111816
+ "us-east"
111817
+ ],
111818
+ null
111819
+ ]
111700
111820
  }
111701
111821
  },
111702
111822
  AskRespondResponse: {
@@ -111743,6 +111863,7 @@ data: {"cursor":13,"kind":"executor","agentId":"\u2026","filePath":"/agents/agen
111743
111863
  required: [
111744
111864
  "requestId",
111745
111865
  "question",
111866
+ "questions",
111746
111867
  "loop"
111747
111868
  ],
111748
111869
  properties: {
@@ -111750,7 +111871,15 @@ data: {"cursor":13,"kind":"executor","agentId":"\u2026","filePath":"/agents/agen
111750
111871
  type: "string"
111751
111872
  },
111752
111873
  question: {
111753
- type: "string"
111874
+ type: "string",
111875
+ description: "One-line summary: the first question, plus how many more"
111876
+ },
111877
+ questions: {
111878
+ type: "array",
111879
+ description: "The form; answer with one entry per question",
111880
+ items: {
111881
+ $ref: "#/components/schemas/AskQuestion"
111882
+ }
111754
111883
  },
111755
111884
  loop: {
111756
111885
  type: "string",
@@ -133574,7 +133703,7 @@ function registerApprovalsRoutes(server, ctx) {
133574
133703
  for (let filePath of order) {
133575
133704
  let handle = handles.get(filePath) ?? deriveHandle(filePath), mine = pending.filter((entry) => entry.filePath === filePath);
133576
133705
  for (let ask of mine.filter((entry) => entry.kind === "ask"))
133577
- out.push({ filePath, handle, type: "ask", requestId: ask.requestId, question: ask.question });
133706
+ out.push({ filePath, handle, type: "ask", requestId: ask.requestId, question: ask.question, questions: ask.questions });
133578
133707
  for (let approval of mine.filter((entry) => entry.kind === "approval"))
133579
133708
  out.push({
133580
133709
  filePath,
@@ -139149,12 +139278,10 @@ function createDaemonHttpApi(runtime2, opts = {}) {
139149
139278
  }
139150
139279
  }), server.get("/agents/:id/asks", async (request, reply) => runtime2.getAgentOrDocument(request.params.id) ? runtime2.getAgentAsks(request.params.id) : notFound3(reply, `Unknown agent "${request.params.id}"`)), server.post("/agents/:id/asks/:requestId/respond", async (request, reply) => {
139151
139280
  if (!runtime2.getAgentOrDocument(request.params.id)) return notFound3(reply, `Unknown agent "${request.params.id}"`);
139152
- let answer = request.body?.answer;
139153
- if (typeof answer != "string") return badRequest3(reply, "answer is required");
139154
- let loop = request.body?.loop;
139281
+ let answers = request.body?.answers, loop = request.body?.loop;
139155
139282
  if (loop !== void 0 && (typeof loop != "string" || !loop)) return badRequest3(reply, "loop must be a non-empty string");
139156
139283
  try {
139157
- return runtime2.answerAgentAsk(request.params.id, request.params.requestId, answer, loop);
139284
+ return runtime2.answerAgentAsk(request.params.id, request.params.requestId, answers, loop);
139158
139285
  } catch (err) {
139159
139286
  return handleRuntimeError(reply, err);
139160
139287
  }
@@ -141651,7 +141778,7 @@ process.on("uncaughtException", (err) => {
141651
141778
  process.on("unhandledRejection", (reason) => {
141652
141779
  console.error("[ADF Daemon] Unhandled rejection:", reason instanceof Error ? reason.stack : reason);
141653
141780
  });
141654
- var port = Number(process.env.ADF_DAEMON_PORT ?? 7385), host = process.env.ADF_DAEMON_HOST ?? "127.0.0.1", pidFile = process.env.ADF_DAEMON_PIDFILE, settingsPath = process.env.ADF_DAEMON_SETTINGS ?? defaultSettingsPath(), daemonVersion = "0.8.2", startedBy = takeLaunchEnv();
141781
+ var port = Number(process.env.ADF_DAEMON_PORT ?? 7385), host = process.env.ADF_DAEMON_HOST ?? "127.0.0.1", pidFile = process.env.ADF_DAEMON_PIDFILE, settingsPath = process.env.ADF_DAEMON_SETTINGS ?? defaultSettingsPath(), daemonVersion = "0.8.3", startedBy = takeLaunchEnv();
141655
141782
  console.log(`[ADF Daemon] Version ${daemonVersion} (pid ${process.pid}, started by ${startedBy})`);
141656
141783
  var settings = new FileSettingsStore(settingsPath);
141657
141784
  processAgentLeases().configure({ kind: "daemon", settingsPath, version: daemonVersion });