funolio-agent 1.0.75 → 1.1.65

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 (236) hide show
  1. package/dist/auth/credential-reader.d.ts.map +1 -1
  2. package/dist/auth/credential-reader.js +4 -3
  3. package/dist/auth/credential-reader.js.map +1 -1
  4. package/dist/auth/token-refresh.d.ts +8 -0
  5. package/dist/auth/token-refresh.d.ts.map +1 -1
  6. package/dist/auth/token-refresh.js +82 -52
  7. package/dist/auth/token-refresh.js.map +1 -1
  8. package/dist/auto-organizer.d.ts.map +1 -1
  9. package/dist/auto-organizer.js +6 -7
  10. package/dist/auto-organizer.js.map +1 -1
  11. package/dist/bench-prefix.d.ts +16 -0
  12. package/dist/bench-prefix.d.ts.map +1 -0
  13. package/dist/bench-prefix.js +25 -0
  14. package/dist/bench-prefix.js.map +1 -0
  15. package/dist/bot-manager.d.ts.map +1 -1
  16. package/dist/bot-manager.js +23 -14
  17. package/dist/bot-manager.js.map +1 -1
  18. package/dist/chat-sync.d.ts +42 -0
  19. package/dist/chat-sync.d.ts.map +1 -0
  20. package/dist/chat-sync.js +95 -0
  21. package/dist/chat-sync.js.map +1 -0
  22. package/dist/clerk-model.d.ts +7 -0
  23. package/dist/clerk-model.d.ts.map +1 -1
  24. package/dist/clerk-model.js +42 -8
  25. package/dist/clerk-model.js.map +1 -1
  26. package/dist/cli-bootstrap-history.d.ts +10 -0
  27. package/dist/cli-bootstrap-history.d.ts.map +1 -0
  28. package/dist/cli-bootstrap-history.js +112 -0
  29. package/dist/cli-bootstrap-history.js.map +1 -0
  30. package/dist/cli-models.d.ts +8 -0
  31. package/dist/cli-models.d.ts.map +1 -0
  32. package/dist/cli-models.js +91 -0
  33. package/dist/cli-models.js.map +1 -0
  34. package/dist/cli-session-epoch.d.ts +13 -3
  35. package/dist/cli-session-epoch.d.ts.map +1 -1
  36. package/dist/cli-session-epoch.js +53 -4
  37. package/dist/cli-session-epoch.js.map +1 -1
  38. package/dist/codex-app-server-manager.d.ts +64 -4
  39. package/dist/codex-app-server-manager.d.ts.map +1 -1
  40. package/dist/codex-app-server-manager.js +755 -55
  41. package/dist/codex-app-server-manager.js.map +1 -1
  42. package/dist/commands/pool.d.ts +32 -0
  43. package/dist/commands/pool.d.ts.map +1 -1
  44. package/dist/commands/pool.js +145 -66
  45. package/dist/commands/pool.js.map +1 -1
  46. package/dist/commands/start.d.ts +21 -0
  47. package/dist/commands/start.d.ts.map +1 -1
  48. package/dist/commands/start.js +484 -63
  49. package/dist/commands/start.js.map +1 -1
  50. package/dist/commands/status.d.ts.map +1 -1
  51. package/dist/commands/status.js +5 -2
  52. package/dist/commands/status.js.map +1 -1
  53. package/dist/config.d.ts +1 -0
  54. package/dist/config.d.ts.map +1 -1
  55. package/dist/config.js +170 -58
  56. package/dist/config.js.map +1 -1
  57. package/dist/context-window.d.ts +37 -1
  58. package/dist/context-window.d.ts.map +1 -1
  59. package/dist/context-window.js +202 -16
  60. package/dist/context-window.js.map +1 -1
  61. package/dist/live-activity.d.ts +3 -1
  62. package/dist/live-activity.d.ts.map +1 -1
  63. package/dist/live-activity.js.map +1 -1
  64. package/dist/local-chat-execution.d.ts +114 -0
  65. package/dist/local-chat-execution.d.ts.map +1 -0
  66. package/dist/local-chat-execution.js +349 -0
  67. package/dist/local-chat-execution.js.map +1 -0
  68. package/dist/local-cli-pty-manager.d.ts +138 -3
  69. package/dist/local-cli-pty-manager.d.ts.map +1 -1
  70. package/dist/local-cli-pty-manager.js +1415 -111
  71. package/dist/local-cli-pty-manager.js.map +1 -1
  72. package/dist/local-conversation-gateway.d.ts +110 -0
  73. package/dist/local-conversation-gateway.d.ts.map +1 -0
  74. package/dist/local-conversation-gateway.js +175 -0
  75. package/dist/local-conversation-gateway.js.map +1 -0
  76. package/dist/local-data.d.ts +235 -5
  77. package/dist/local-data.d.ts.map +1 -1
  78. package/dist/local-data.js +1066 -87
  79. package/dist/local-data.js.map +1 -1
  80. package/dist/local-db.d.ts +6 -0
  81. package/dist/local-db.d.ts.map +1 -1
  82. package/dist/local-db.js +376 -4
  83. package/dist/local-db.js.map +1 -1
  84. package/dist/local-funnel.d.ts.map +1 -1
  85. package/dist/local-funnel.js +6 -5
  86. package/dist/local-funnel.js.map +1 -1
  87. package/dist/local-server.d.ts +30 -0
  88. package/dist/local-server.d.ts.map +1 -1
  89. package/dist/local-server.js +2898 -319
  90. package/dist/local-server.js.map +1 -1
  91. package/dist/managed-process-registry.d.ts +59 -0
  92. package/dist/managed-process-registry.d.ts.map +1 -0
  93. package/dist/managed-process-registry.js +390 -0
  94. package/dist/managed-process-registry.js.map +1 -0
  95. package/dist/mcp/claude-config-writer.d.ts +5 -5
  96. package/dist/mcp/claude-config-writer.d.ts.map +1 -1
  97. package/dist/mcp/claude-config-writer.js +19 -11
  98. package/dist/mcp/claude-config-writer.js.map +1 -1
  99. package/dist/mcp/index.d.ts +4 -2
  100. package/dist/mcp/index.d.ts.map +1 -1
  101. package/dist/mcp/index.js.map +1 -1
  102. package/dist/mcp/sync-cli-config.d.ts +42 -4
  103. package/dist/mcp/sync-cli-config.d.ts.map +1 -1
  104. package/dist/mcp/sync-cli-config.js +497 -17
  105. package/dist/mcp/sync-cli-config.js.map +1 -1
  106. package/dist/message-loop.d.ts.map +1 -1
  107. package/dist/message-loop.js +43 -1
  108. package/dist/message-loop.js.map +1 -1
  109. package/dist/mqtt-client.d.ts +34 -0
  110. package/dist/mqtt-client.d.ts.map +1 -1
  111. package/dist/mqtt-client.js +270 -45
  112. package/dist/mqtt-client.js.map +1 -1
  113. package/dist/mqtt-data-relay.d.ts +44 -0
  114. package/dist/mqtt-data-relay.d.ts.map +1 -0
  115. package/dist/mqtt-data-relay.js +106 -0
  116. package/dist/mqtt-data-relay.js.map +1 -0
  117. package/dist/orchestration/capabilities.d.ts +13 -0
  118. package/dist/orchestration/capabilities.d.ts.map +1 -0
  119. package/dist/orchestration/capabilities.js +152 -0
  120. package/dist/orchestration/capabilities.js.map +1 -0
  121. package/dist/orchestration/dispatch-executor.d.ts +83 -0
  122. package/dist/orchestration/dispatch-executor.d.ts.map +1 -0
  123. package/dist/orchestration/dispatch-executor.js +266 -0
  124. package/dist/orchestration/dispatch-executor.js.map +1 -0
  125. package/dist/orchestration/dispatch-hint.d.ts +134 -0
  126. package/dist/orchestration/dispatch-hint.d.ts.map +1 -0
  127. package/dist/orchestration/dispatch-hint.js +247 -0
  128. package/dist/orchestration/dispatch-hint.js.map +1 -0
  129. package/dist/orchestration/dispatch-runner.d.ts +106 -0
  130. package/dist/orchestration/dispatch-runner.d.ts.map +1 -0
  131. package/dist/orchestration/dispatch-runner.js +604 -0
  132. package/dist/orchestration/dispatch-runner.js.map +1 -0
  133. package/dist/orchestration/dispatch-tools.d.ts +167 -0
  134. package/dist/orchestration/dispatch-tools.d.ts.map +1 -0
  135. package/dist/orchestration/dispatch-tools.js +328 -0
  136. package/dist/orchestration/dispatch-tools.js.map +1 -0
  137. package/dist/orchestration/front-door-policy.d.ts +35 -10
  138. package/dist/orchestration/front-door-policy.d.ts.map +1 -1
  139. package/dist/orchestration/front-door-policy.js +30 -267
  140. package/dist/orchestration/front-door-policy.js.map +1 -1
  141. package/dist/orchestration/orchestrator-dispatch-prompt.d.ts +43 -0
  142. package/dist/orchestration/orchestrator-dispatch-prompt.d.ts.map +1 -0
  143. package/dist/orchestration/orchestrator-dispatch-prompt.js +267 -0
  144. package/dist/orchestration/orchestrator-dispatch-prompt.js.map +1 -0
  145. package/dist/orchestration/orchestrator-operating-prompt.d.ts +14 -0
  146. package/dist/orchestration/orchestrator-operating-prompt.d.ts.map +1 -1
  147. package/dist/orchestration/orchestrator-operating-prompt.js +157 -31
  148. package/dist/orchestration/orchestrator-operating-prompt.js.map +1 -1
  149. package/dist/orchestration/plan-import.d.ts +39 -0
  150. package/dist/orchestration/plan-import.d.ts.map +1 -0
  151. package/dist/orchestration/plan-import.js +547 -0
  152. package/dist/orchestration/plan-import.js.map +1 -0
  153. package/dist/orchestration/worker-operating-prompt.d.ts +2 -0
  154. package/dist/orchestration/worker-operating-prompt.d.ts.map +1 -1
  155. package/dist/orchestration/worker-operating-prompt.js +36 -46
  156. package/dist/orchestration/worker-operating-prompt.js.map +1 -1
  157. package/dist/orchestrator.d.ts +195 -3
  158. package/dist/orchestrator.d.ts.map +1 -1
  159. package/dist/orchestrator.js +1970 -432
  160. package/dist/orchestrator.js.map +1 -1
  161. package/dist/providers/anthropic.d.ts.map +1 -1
  162. package/dist/providers/anthropic.js +8 -4
  163. package/dist/providers/anthropic.js.map +1 -1
  164. package/dist/providers/claude-cli.d.ts.map +1 -1
  165. package/dist/providers/claude-cli.js +28 -3
  166. package/dist/providers/claude-cli.js.map +1 -1
  167. package/dist/providers/codex-cli.d.ts +10 -6
  168. package/dist/providers/codex-cli.d.ts.map +1 -1
  169. package/dist/providers/codex-cli.js +190 -17
  170. package/dist/providers/codex-cli.js.map +1 -1
  171. package/dist/providers/google.d.ts.map +1 -1
  172. package/dist/providers/google.js +15 -5
  173. package/dist/providers/google.js.map +1 -1
  174. package/dist/providers/index.d.ts +15 -1
  175. package/dist/providers/index.d.ts.map +1 -1
  176. package/dist/providers/index.js.map +1 -1
  177. package/dist/providers/openai.d.ts +1 -1
  178. package/dist/providers/openai.d.ts.map +1 -1
  179. package/dist/providers/openai.js +13 -5
  180. package/dist/providers/openai.js.map +1 -1
  181. package/dist/server-adapter.d.ts +8 -0
  182. package/dist/server-adapter.d.ts.map +1 -1
  183. package/dist/server-adapter.js +7 -0
  184. package/dist/server-adapter.js.map +1 -1
  185. package/dist/service-mode.d.ts +1 -1
  186. package/dist/service-mode.d.ts.map +1 -1
  187. package/dist/service-mode.js +64 -1
  188. package/dist/service-mode.js.map +1 -1
  189. package/dist/service-setup-only.d.ts +8 -0
  190. package/dist/service-setup-only.d.ts.map +1 -0
  191. package/dist/service-setup-only.js +37 -0
  192. package/dist/service-setup-only.js.map +1 -0
  193. package/dist/slash-commands.d.ts +21 -0
  194. package/dist/slash-commands.d.ts.map +1 -0
  195. package/dist/slash-commands.js +99 -0
  196. package/dist/slash-commands.js.map +1 -0
  197. package/dist/subagent/index.d.ts +4 -2
  198. package/dist/subagent/index.d.ts.map +1 -1
  199. package/dist/subagent/index.js.map +1 -1
  200. package/dist/summarization-pipeline.d.ts.map +1 -1
  201. package/dist/summarization-pipeline.js +1 -9
  202. package/dist/summarization-pipeline.js.map +1 -1
  203. package/dist/token-counter.d.ts.map +1 -1
  204. package/dist/token-counter.js +11 -4
  205. package/dist/token-counter.js.map +1 -1
  206. package/dist/tool-filter.d.ts.map +1 -1
  207. package/dist/tool-filter.js +10 -6
  208. package/dist/tool-filter.js.map +1 -1
  209. package/dist/tools/admin-tools.d.ts.map +1 -1
  210. package/dist/tools/admin-tools.js +13 -4
  211. package/dist/tools/admin-tools.js.map +1 -1
  212. package/dist/tools/run-command.d.ts.map +1 -1
  213. package/dist/tools/run-command.js +5 -1
  214. package/dist/tools/run-command.js.map +1 -1
  215. package/dist/tools/search-conversation-history.d.ts.map +1 -1
  216. package/dist/tools/search-conversation-history.js +12 -2
  217. package/dist/tools/search-conversation-history.js.map +1 -1
  218. package/dist/tools/todo-tasks.d.ts.map +1 -1
  219. package/dist/tools/todo-tasks.js +77 -5
  220. package/dist/tools/todo-tasks.js.map +1 -1
  221. package/dist/usage-log.d.ts +62 -0
  222. package/dist/usage-log.d.ts.map +1 -0
  223. package/dist/usage-log.js +98 -0
  224. package/dist/usage-log.js.map +1 -0
  225. package/dist/wizard-state.d.ts +13 -0
  226. package/dist/wizard-state.d.ts.map +1 -1
  227. package/dist/wizard-state.js +61 -3
  228. package/dist/wizard-state.js.map +1 -1
  229. package/dist/wizard-support.d.ts.map +1 -1
  230. package/dist/wizard-support.js +27 -1
  231. package/dist/wizard-support.js.map +1 -1
  232. package/dist/workflow-engine.d.ts +40 -1
  233. package/dist/workflow-engine.d.ts.map +1 -1
  234. package/dist/workflow-engine.js +753 -93
  235. package/dist/workflow-engine.js.map +1 -1
  236. package/package.json +2 -2
@@ -0,0 +1,267 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ORCHESTRATOR_DISPATCH_PROMPT_BODY = void 0;
4
+ exports.buildOrchestratorDispatchPrompt = buildOrchestratorDispatchPrompt;
5
+ const PROMPT_BODY_STATIC = `You are the orchestrator for a Funolio multi-bot conversation.
6
+
7
+ Your job: understand the user's request, decide whether to handle it yourself or
8
+ delegate to a worker bot, and return a structured tool call. The user's prompt
9
+ is authoritative — treat it as such.
10
+
11
+ OPERATING RULE
12
+
13
+ You handle every request yourself UNLESS it falls under one of the capabilities
14
+ listed below in CAPABILITIES WITH A DEDICATED BOT. For those capabilities,
15
+ delegate to the bot that owns that priority.
16
+
17
+ Anything outside the listed capabilities — reading a file, summarizing, answering a
18
+ question, giving status, writing a short reply, clarifying something — you do
19
+ directly. You have read-side tools for this:
20
+
21
+ - read_file, list_directory, search_codebase — inspect the project.
22
+ - search_local_memory — look up stored project memory.
23
+ - list_tasks — see the current TODO queue.
24
+ - web_search, web_fetch — external info.
25
+
26
+ Use these tools freely when you need context to answer. When you're done
27
+ gathering context, end the turn with reply_directly.
28
+
29
+ WRITE-SIDE WORK (creating or changing files, running commands) IS NOT
30
+ available to you directly — those are role-specific jobs. Delegate them to
31
+ the appropriate bot from the list below via delegate_single or
32
+ create_workflow.
33
+
34
+ MULTI-TURN FLOW
35
+
36
+ If you need multiple pieces of context, call the read-side tools across
37
+ multiple turns. Funolio feeds each tool's result back to you automatically.
38
+ Only when you have what you need, end the conversation with exactly one
39
+ of the three dispatch tools.
40
+
41
+ Do NOT mix a read-side tool call with a dispatch tool call in the same
42
+ turn — that's ambiguous and will be rejected. Gather first, then
43
+ dispatch on a subsequent turn.
44
+
45
+ THREE DISPATCH TOOLS
46
+
47
+ Every turn ends by calling exactly ONE of these three tools:
48
+
49
+ reply_directly(text)
50
+ Your answer to the user. Use for questions, clarifications, status,
51
+ summaries, greetings, and anything that does not require a role-specific
52
+ bot. The text you provide becomes the user's reply.
53
+
54
+ delegate_single(task_instructions, bot_name?, role?, success_criteria?)
55
+ Delegate a single task to one worker bot. Creates one TODO.
56
+ Provide at least one of bot_name or role.
57
+ - bot_name routes to that specific bot.
58
+ - role picks the highest-priority bot for that role.
59
+ - When both are provided, bot_name wins.
60
+ Optional title may be supplied for the TODO label.
61
+ task_instructions must include every concrete reference the worker
62
+ needs — file paths, URLs, artifact names, the relevant user spec —
63
+ so the worker can act without prospecting for context.
64
+
65
+ create_workflow(steps[])
66
+ Create an ordered multi-step workflow. Use when the user needs multiple
67
+ roles in sequence (e.g. research → coding → QA → verify).
68
+ Each step requires task_instructions plus bot_name or role.
69
+ Each step may include a short title for the TODO label.
70
+ Optional handoff_to_next passes context from one step's worker to the
71
+ next worker's task prompt. Each step's task_instructions must carry
72
+ concrete references for that worker.
73
+
74
+ If the hint includes selected_workflow_template or candidate_workflow_plan,
75
+ Funolio detected an obvious user-requested workflow candidate. Treat it as a
76
+ suggestion, not a command. Approve it by calling create_workflow with the
77
+ listed steps, modify it by calling create_workflow with corrected steps, or
78
+ reject it with reply_directly if the candidate is wrong or unclear.
79
+
80
+ If the hint also shows existing_todos that match the candidate, Funolio has
81
+ already created visible proposed TODOs but has NOT started any workers. In
82
+ that case you do not need to call a dispatch tool just to approve the proposal.
83
+ If it is correct, reply with exactly: APPROVE_PROPOSED_WORKFLOW. If it is
84
+ wrong or unclear, reply with exactly: REJECT_PROPOSED_WORKFLOW followed by one
85
+ short reason. If you need edits, call create_workflow with the corrected plan.
86
+
87
+ For selected_workflow_template, the user explicitly selected or named that
88
+ saved workflow. If you agree, keep exactly the listed step order and bot_name
89
+ values. You author each step's title and task_instructions from the user's
90
+ request and the intended role of that bot. Do not emit generic labels like
91
+ "Complete Ben's workflow step", "Coding", "QA", or "Verify". The saved
92
+ template provides bot order; it is not a substitute for your per-run task
93
+ writing.
94
+
95
+ TODO COMPLETION RULE
96
+
97
+ Do NOT call complete_worker_task or block_worker_task. Those are the worker's
98
+ tools for reporting status on their own TODO. The orchestrator calling them
99
+ would mark a worker's task done without the worker actually doing it.
100
+
101
+ Rare exception — deliberate override: if a worker is permanently stuck and
102
+ the user has explicitly asked you to clean up the stuck TODO, call
103
+ complete_worker_task or block_worker_task with a clear reason. The system
104
+ logs these to the orchestration audit trail.
105
+
106
+ QA PASS/FAIL
107
+
108
+ Workers declare QA pass/fail via the qa_result argument on
109
+ complete_worker_task — not via prose. As the orchestrator you do not
110
+ classify worker output; you trust the structured signal. If QA passes,
111
+ the workflow continues. If QA fails, the runtime auto-creates a fix
112
+ task + re-QA cycle based on the worker's findings.
113
+
114
+ HINT BLOCK
115
+
116
+ Every turn includes a structured context block containing the user prompt,
117
+ conversation metadata, available bots with their role priority lists,
118
+ existing TODOs, and effective policy. The \`advisory\` sub-block contains
119
+ heuristic keyword suggestions — treat it as advisory only; trust the user
120
+ prompt and the available bots list.
121
+
122
+ When the hint includes \`conversation.recent_turns\`, read those turns before
123
+ deciding. They are especially important for stateless/API orchestrators when the
124
+ user refers to "the page", "that file", "the last fix", or similar shorthand.
125
+
126
+ When the hint includes \`conversation.bootstrap_history_file\`, read that file
127
+ for context. This is used for fresh CLI orchestrator sessions. Use it for
128
+ context only and do not mention the file path unless the user asks.
129
+
130
+ PLAN FILE EXECUTION
131
+
132
+ When the hint includes \`plan_execution_intent.mode\`:
133
+
134
+ - \`per_step_todos\`
135
+ The user explicitly wants a file/plan expanded into sequential worker TODOs.
136
+ First read the referenced file. Only do this if the file actually contains
137
+ structured steps (numbered items, lettered items, bullet items, or clearly
138
+ separated actionable sections). Then create ONE ordered workflow where each
139
+ parsed file step is expanded through the user-requested worker sequence.
140
+ Example: if the user asked for Ben coding then John QA, file step 1 becomes
141
+ Ben step 1 -> John QA step 1, file step 2 becomes Ben step 2 -> John QA step 2.
142
+ Do not collapse the entire file into one coarse TODO.
143
+
144
+ - \`per_step_workflow\`
145
+ The user explicitly wants each file step to run through the selected or
146
+ named workflow template. First read the referenced file. Only proceed if
147
+ the file actually contains structured steps. Then expand EACH parsed file
148
+ step through the saved workflow order. Example: if the selected workflow is
149
+ Brain -> Ben -> John, file step 1 becomes Brain step 1 -> Ben step 1 ->
150
+ John step 1; then file step 2 repeats the same workflow order.
151
+ If no selected/named workflow is actually available, ask the user to pick
152
+ one instead of guessing.
153
+
154
+ If the file is not structured enough to identify separate steps, reply_directly
155
+ and ask the user to clarify or reformat the plan instead of guessing.
156
+
157
+ When this orchestrator runs through an API provider (OpenAI, Anthropic API,
158
+ Google Gemini, etc.), the hint block that reaches the provider includes
159
+ local project path metadata (project_folder). That's deliberate — the path
160
+ lets you write accurate task_instructions for workers.
161
+
162
+ ROLE-BASED DISPATCH DETAILS
163
+
164
+ When you use \`role\` without naming a bot, the dispatcher picks the
165
+ highest-priority bot for that role from the available_bots list in the
166
+ hint. Ties break toward bots that don't already have active TODOs in this
167
+ conversation.
168
+
169
+ Role strings are matched case-insensitively after whitespace normalization.
170
+ "QA" == "qa" == " QA ". There is no alias table — use the exact role labels
171
+ from the \`role_priorities\` of the bots in the hint.
172
+
173
+ NATIVE TOOL CALLS VS TEXT FALLBACK
174
+
175
+ If your provider supports native tool calls (Anthropic API, OpenAI API,
176
+ Google Gemini API, etc.), invoke one of the three dispatch tools directly.
177
+
178
+ If your provider does NOT support native tool calls (Claude CLI, Codex CLI,
179
+ or any other text-only interface), emit exactly ONE fenced JSON block as
180
+ your ENTIRE response, with no prose before or after:
181
+
182
+ \`\`\`json
183
+ {"tool": "delegate_single", "arguments": {"bot_name": "Ben", "task_instructions": "Fix the login bug in C:\\\\Projects\\\\app\\\\login.ts"}}
184
+ \`\`\`
185
+
186
+ The shape must be:
187
+ - \`tool\`: one of "reply_directly", "delegate_single", "create_workflow"
188
+ - \`arguments\`: the same fields documented above for that tool
189
+
190
+ Funolio parses this block identically to a native tool call — same
191
+ validators, same executor, same audit trail. Emit exactly one block per
192
+ turn.`;
193
+ /**
194
+ * Build the "CAPABILITIES WITH A DEDICATED BOT" section dynamically from the
195
+ * hint's active bots. For each distinct role priority across bots, lists
196
+ * the bot(s) that own that role. Steven's rule: exceptions to "do it
197
+ * yourself" come from settings — i.e. from the bots the user actually
198
+ * configured.
199
+ */
200
+ function buildRolesSection(bots) {
201
+ const rolesToBots = new Map();
202
+ for (const bot of bots) {
203
+ if (!bot.is_active)
204
+ continue;
205
+ for (const role of bot.role_priorities || []) {
206
+ const key = String(role || '').trim();
207
+ if (!key)
208
+ continue;
209
+ const list = rolesToBots.get(key) || [];
210
+ if (!list.includes(bot.name))
211
+ list.push(bot.name);
212
+ rolesToBots.set(key, list);
213
+ }
214
+ }
215
+ if (rolesToBots.size === 0) {
216
+ return [
217
+ 'CAPABILITIES WITH A DEDICATED BOT',
218
+ '',
219
+ '(none configured for this conversation — handle every request yourself via reply_directly, unless the user explicitly names a bot.)',
220
+ ].join('\n');
221
+ }
222
+ const lines = ['CAPABILITIES WITH A DEDICATED BOT', ''];
223
+ const sorted = Array.from(rolesToBots.entries()).sort(([a], [b]) => a.localeCompare(b));
224
+ for (const [role, owners] of sorted) {
225
+ lines.push(` - ${role} → ${owners.join(', ')}`);
226
+ }
227
+ lines.push('');
228
+ lines.push('These are the ONLY roles for which delegation is preferred. Any');
229
+ lines.push('request that does not cleanly map to one of the roles above, you');
230
+ lines.push('handle yourself via reply_directly.');
231
+ return lines.join('\n');
232
+ }
233
+ /**
234
+ * Build the full system prompt for an orchestrator turn.
235
+ *
236
+ * Output shape:
237
+ * [Orchestrator Operating Prompt]
238
+ * <static body>
239
+ *
240
+ * <dynamic roles-with-a-dedicated-bot section>
241
+ *
242
+ * [Additional Guidance] — if provided
243
+ * <soul_md or bot-specific text>
244
+ *
245
+ * [Hint Block]
246
+ * <JSON-stringified hint>
247
+ *
248
+ * [End of Hint]
249
+ */
250
+ function buildOrchestratorDispatchPrompt(input) {
251
+ const rolesSection = buildRolesSection(input.hint.available_bots || []);
252
+ const parts = [
253
+ '[Orchestrator Operating Prompt]',
254
+ PROMPT_BODY_STATIC.trim(),
255
+ '',
256
+ rolesSection,
257
+ ];
258
+ const guidance = input.additionalGuidance?.trim();
259
+ if (guidance) {
260
+ parts.push('', '[Additional Guidance]', guidance);
261
+ }
262
+ parts.push('', '[Hint Block]', JSON.stringify(input.hint, null, 2), '[End of Hint]');
263
+ return parts.join('\n');
264
+ }
265
+ /** Export the static body for tests. */
266
+ exports.ORCHESTRATOR_DISPATCH_PROMPT_BODY = PROMPT_BODY_STATIC;
267
+ //# sourceMappingURL=orchestrator-dispatch-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator-dispatch-prompt.js","sourceRoot":"","sources":["../../src/orchestration/orchestrator-dispatch-prompt.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,9 @@ export interface OrchestratorFrontDoorDecision {
8
8
  delegate_request?: string;
9
9
  workflow_request?: string;
10
10
  clarification_questions?: string[];
11
+ narration?: string;
11
12
  }
13
+ export declare const ORCHESTRATOR_DECISION_SENTINEL = "===DECISION===";
12
14
  export interface SpecialistInfo {
13
15
  name: string;
14
16
  roleLabel: string;
@@ -44,7 +46,19 @@ export declare function buildOrchestratorOperatingPrompt(input: {
44
46
  effectivePolicy?: string | null;
45
47
  recentSummary?: string | null;
46
48
  lastFiveTurns?: string | null;
49
+ bootstrapHistoryFilePath?: string | null;
47
50
  decisionOnly?: boolean;
51
+ defaultBotName?: string | null;
48
52
  }): string;
53
+ /**
54
+ * Splits the LLM raw output at the ===DECISION=== sentinel.
55
+ * Returns { narration, decisionText } where narration may be empty if the
56
+ * LLM did not follow the format. The decisionText is the portion after
57
+ * the sentinel (or the entire raw if no sentinel was found, for backward compat).
58
+ */
59
+ export declare function splitOrchestratorNarrationAndDecision(raw: string): {
60
+ narration: string;
61
+ decisionText: string;
62
+ };
49
63
  export declare function parseOrchestratorFrontDoorDecision(raw: string): OrchestratorFrontDoorDecision | null;
50
64
  //# sourceMappingURL=orchestrator-operating-prompt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator-operating-prompt.d.ts","sourceRoot":"","sources":["../../src/orchestration/orchestrator-operating-prompt.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,yBAAyB,GACjC,SAAS,GACT,cAAc,GACd,UAAU,GACV,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,yBAAyB,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,GAAG,MAAM,CAAC;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,GAAG,MAAM,GAAG,IAAI,CAAC;CAC7D;AAED,wBAAgB,gCAAgC,CAAC,KAAK,EAAE;IACtD,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,mBAAmB,CAAC,EAAE,QAAQ,GAAG,kBAAkB,GAAG,eAAe,CAAC;IACtE,SAAS,CAAC,EAAE,QAAQ,GAAG,oBAAoB,CAAC;IAC5C,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,gBAAgB,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;IACpD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,GAAG,MAAM,CAoPT;AAED,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,MAAM,GAAG,6BAA6B,GAAG,IAAI,CAgDpG"}
1
+ {"version":3,"file":"orchestrator-operating-prompt.d.ts","sourceRoot":"","sources":["../../src/orchestration/orchestrator-operating-prompt.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,yBAAyB,GACjC,SAAS,GACT,cAAc,GACd,UAAU,GACV,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,yBAAyB,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,GAAG,MAAM,CAAC;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,8BAA8B,mBAAmB,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,GAAG,MAAM,GAAG,IAAI,CAAC;CAC7D;AAED,wBAAgB,gCAAgC,CAAC,KAAK,EAAE;IACtD,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,mBAAmB,CAAC,EAAE,QAAQ,GAAG,kBAAkB,GAAG,eAAe,CAAC;IACtE,SAAS,CAAC,EAAE,QAAQ,GAAG,oBAAoB,CAAC;IAC5C,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,gBAAgB,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;IACpD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,GAAG,MAAM,CAgWT;AAED;;;;;GAKG;AACH,wBAAgB,qCAAqC,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAS9G;AAED,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,MAAM,GAAG,6BAA6B,GAAG,IAAI,CA+CpG"}
@@ -1,7 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ORCHESTRATOR_DECISION_SENTINEL = void 0;
3
4
  exports.buildOrchestratorOperatingPrompt = buildOrchestratorOperatingPrompt;
5
+ exports.splitOrchestratorNarrationAndDecision = splitOrchestratorNarrationAndDecision;
4
6
  exports.parseOrchestratorFrontDoorDecision = parseOrchestratorFrontDoorDecision;
7
+ exports.ORCHESTRATOR_DECISION_SENTINEL = '===DECISION===';
5
8
  function buildOrchestratorOperatingPrompt(input) {
6
9
  const primaryRole = input.primaryRole?.trim() || 'generalist';
7
10
  const specialists = input.specialists || [];
@@ -30,6 +33,8 @@ function buildOrchestratorOperatingPrompt(input) {
30
33
  const effectivePolicy = input.effectivePolicy?.trim() || 'No confirmed special policy is set.';
31
34
  const recentSummary = input.recentSummary?.trim() || '(none)';
32
35
  const lastFiveTurns = input.lastFiveTurns?.trim() || '(no recent turns)';
36
+ const bootstrapHistoryFilePath = input.bootstrapHistoryFilePath?.trim() || null;
37
+ const defaultBotName = input.defaultBotName?.trim() || '(none)';
33
38
  const signalLines = input.signalSummary
34
39
  ? [
35
40
  input.signalSummary.matchedBots?.length ? `- Matched bot names: ${input.signalSummary.matchedBots.join(', ')}` : null,
@@ -68,29 +73,53 @@ By default, you do the work yourself.
68
73
 
69
74
  Only split the work when:
70
75
  - part of the request clearly belongs to another listed bot or role
71
- - the user explicitly asks for a named workflow
76
+ - the user explicitly asks for a named workflow that is listed here
72
77
  - the request clearly requires multiple bots doing different tasks
73
78
 
74
79
  Workflow and TODOs are not the same.
75
- Use a workflow only when the user explicitly asks for a named workflow.
80
+ Use a saved workflow template when the user names one that is listed here.
76
81
  Use TODOs when the work needs to be split across multiple bots or roles.
77
82
 
78
83
  If you keep the work, do the work now in this same response.
79
84
  If you split the work, create the needed TODOs and stop after clearly setting up the next step.
80
85
 
81
86
  If the user mentions another bot only as context, history, or authorship, keep the work and handle it yourself.
87
+ Handle these kinds of direct orchestration work yourself by default:
88
+ - answer user questions
89
+ - inspect the project or codebase and explain findings
90
+ - read files
91
+ - write or update plain-text notes, plans, fix lists, and summaries
92
+ - create, edit, reorder, or explain TODOs
93
+ - break work into sequential steps
94
+ - summarize progress and status
95
+ - ask clarifying questions
96
+ - do lightweight project research and comparison
97
+ - keep work that does not clearly belong to a listed worker role
98
+
99
+ If you cannot complete kept work directly, use the default bot instead of forcing a worker workflow.
82
100
 
83
101
  Available Bots and Roles
84
102
  ${specialistLines}
85
103
 
104
+ Default Bot
105
+ - ${defaultBotName}
106
+
86
107
  Named Workflows
87
108
  ${workflowLines}
109
+ If the user names a saved workflow listed here, execute that template sequentially.
110
+ If no matching saved workflow is listed, do not treat the word "workflow" as a template error. Use normal language context.
88
111
 
89
112
  Project
90
113
  - Name: ${projectName}
91
114
  - Folder: ${projectFolder}
92
115
  ${localPromptContract === 'api_or_fresh_cli'
93
- ? `
116
+ ? bootstrapHistoryFilePath
117
+ ? `
118
+
119
+ Bootstrap History File
120
+ Please read the history file at: ${bootstrapHistoryFilePath}
121
+ Use it for context only. Do not mention the file or path unless the user asks.`
122
+ : `
94
123
 
95
124
  Recent Summary
96
125
  ${recentSummary}
@@ -100,15 +129,54 @@ ${lastFiveTurns}`
100
129
  : ''}
101
130
 
102
131
  ${decisionOnly
103
- ? `OUTPUT JSON ONLY
104
- Return exactly one JSON object.
105
- Do not wrap it in markdown fences.
106
- Do not add commentary before or after the JSON.`
107
- : `OUTPUT RULES
108
- - If you keep the work, return the user-facing answer directly and do NOT return JSON.
109
- - If you split the work, return exactly one JSON object.
132
+ ? `OUTPUT FORMAT (TWO PARTS — narration THEN decision JSON)
133
+
134
+ PART 1: NARRATION
135
+ Write exactly ONE short, friendly, natural sentence telling the user what you're about to do.
136
+ - Be conversational and warm, like a helpful colleague casually narrating their plan to a teammate.
137
+ - Vary the wording every time. Never sound scripted or robotic.
138
+ - If you're routing to specific bots, mention them by name in a natural way.
139
+ - Do NOT say "I am reviewing your request" or any similar boilerplate.
140
+ - Do NOT use exclamation points unless the moment really calls for it.
141
+ - Do NOT add any preamble, headers, or labels — just the sentence itself.
142
+
143
+ PART 2: DECISION
144
+ After the narration, on a new line, write exactly the marker ${exports.ORCHESTRATOR_DECISION_SENTINEL}
145
+ Then on the next line, write exactly one JSON object describing your decision.
146
+ Do not wrap JSON in markdown fences.
147
+ Do not add commentary before or after the JSON.
148
+
149
+ EXAMPLE:
150
+ ${(() => {
151
+ const researchBot = specialists.find((s) => /research|brainstorm|plan/i.test(s.roleLabel));
152
+ const codingBot = specialists.find((s) => /cod|build|develop|engineer/i.test(s.roleLabel));
153
+ const qaBot = specialists.find((s) => /qa|review/i.test(s.roleLabel));
154
+ const rName = researchBot?.name || 'the researcher';
155
+ const cName = codingBot?.name || 'the coder';
156
+ const qName = qaBot?.name || 'the reviewer';
157
+ return `Got it — I'll have ${rName} sketch a plan first, then ${cName} can build it and ${qName} will give it a once-over.
158
+ ${exports.ORCHESTRATOR_DECISION_SENTINEL}
159
+ ${JSON.stringify({
160
+ mode: 'workflow',
161
+ reason: 'Multi-step build',
162
+ workflow_request: `${rName} plan, ${cName} code, ${qName} QA`,
163
+ }, null, 2)}`;
164
+ })()}
165
+
166
+ THE JSON SCHEMA:`
167
+ : `OUTPUT FORMAT (TWO PARTS — narration THEN decision/answer)
168
+
169
+ PART 1: NARRATION
170
+ If you are splitting the work, write exactly ONE short, friendly sentence first telling the user what you're about to do.
171
+ Be natural and warm. Vary the wording. No robotic boilerplate.
172
+ If you are keeping the work and answering directly, skip narration and just return your answer.
173
+
174
+ PART 2: DECISION OR DIRECT ANSWER
175
+ - If you keep the work: return the user-facing answer directly with no JSON, no sentinel.
176
+ - If you split the work: after narration, on a new line write ${exports.ORCHESTRATOR_DECISION_SENTINEL}, then write exactly one JSON object.
110
177
  - Do not wrap JSON in markdown fences.
111
- - Do not add commentary before or after the JSON.`}
178
+
179
+ THE JSON SCHEMA:`}
112
180
  ${JSON.stringify({
113
181
  mode: decisionOnly ? 'respond | execute_self | delegate | workflow | clarify' : 'respond | delegate | workflow | clarify',
114
182
  reason: 'short explanation',
@@ -148,24 +216,31 @@ DELEGATION POSTURE
148
216
  - If the system suggests a TODO or workflow for work that cannot be clearly delegated to an available worker other than yourself, do not create a TODO or workflow. Handle the request yourself instead.
149
217
  - You may delegate without a system suggestion only when the user clearly directs work to an available worker, role, or specialist other than yourself.
150
218
  - If you disagree with the system suggestion, explain why in the "reason" field.
219
+ - If no listed worker role clearly matches the task, keep the work yourself.
220
+ - If you cannot complete kept work directly, use the default bot instead of forcing a worker workflow.
151
221
 
152
222
  ---
153
223
 
154
224
  Available Workers
155
225
  ${specialistLines}
156
226
 
227
+ Default Bot
228
+ - ${defaultBotName}
229
+
157
230
  AVAILABLE WORKER BOUNDARY
158
231
  - Delegable work is defined by the available bots, their roles, and their stated responsibilities in this project.
159
232
  - A bot name, model name, or prior worker reference is not by itself a delegation request.
160
233
  - If the user mentions a worker only as context, history, or authorship, keep the request and handle it yourself.
161
234
  - Delegate when the request clearly directs work to an available worker or clearly requires work owned by that worker's role.
235
+ - Handle these kinds of work yourself by default: answering user questions, inspecting the project or codebase and explaining findings, reading files, writing or updating plain-text notes/plans/fix lists/summaries, creating/editing/reordering TODOs, breaking work into sequential steps, summarizing progress/status, asking clarifying questions, and lightweight project research/comparison.
162
236
 
163
237
  ---
164
238
 
165
239
  Available Workflows
166
240
  ${workflowLines}
167
241
  - Use workflow when the system suggests workflow and that suggestion is correct, or when the user clearly requests multi-worker or staged work.
168
- - If no workflows are listed, named workflow mode is not available.
242
+ - If the user names a saved workflow listed here, execute that template sequentially.
243
+ - If no matching saved workflow is listed, do not treat the word "workflow" as a template error. Use normal language context.
169
244
  - Delegate ONE clear task only.
170
245
 
171
246
  - delegate_request MUST be fully self-contained:
@@ -178,8 +253,8 @@ ${workflowLines}
178
253
  - The receiving bot has NO prior context
179
254
  - Do NOT reference prior conversation ("as discussed", "above", etc.)
180
255
 
181
- - Only use workflow when it is explicitly requested and a system-defined workflow is available.
182
- - Do NOT create your own workflows.
256
+ - Treat the listed worker roles and responsibilities as the explicit delegation scope for worker bots.
257
+ - Work outside those listed worker scopes should stay with you unless you intentionally fall back to the default bot.
183
258
 
184
259
  ---
185
260
 
@@ -209,15 +284,45 @@ DECISION ORDER
209
284
  ---
210
285
 
211
286
  ${decisionOnly
212
- ? `OUTPUT JSON ONLY
213
- Return exactly one JSON object.
214
- Do not wrap it in markdown fences.
215
- Do not add commentary before or after the JSON.`
216
- : `OUTPUT RULES
217
- - If you keep the work, return the user-facing answer directly and do NOT return JSON.
218
- - If you delegate, use workflow, or need clarification, return exactly one JSON object.
287
+ ? `OUTPUT FORMAT (TWO PARTS — narration THEN decision JSON)
288
+
289
+ PART 1: NARRATION
290
+ Write exactly ONE short, friendly, natural sentence telling the user what you're about to do.
291
+ - Be conversational and warm, like a helpful colleague casually narrating their plan to a teammate.
292
+ - Vary the wording every time. Never sound scripted or robotic.
293
+ - If you're routing to specific bots, mention them by name in a natural way.
294
+ - Do NOT say "I am reviewing your request" or any similar boilerplate.
295
+ - Do NOT use exclamation points unless the moment really calls for it.
296
+ - Do NOT add any preamble, headers, or labels — just the sentence itself.
297
+
298
+ PART 2: DECISION
299
+ After the narration, on a new line, write exactly the marker ${exports.ORCHESTRATOR_DECISION_SENTINEL}
300
+ Then on the next line, write exactly one JSON object describing your decision.
301
+ Do not wrap JSON in markdown fences.
302
+
303
+ EXAMPLE:
304
+ Got it — I'll have Brain sketch a plan first, then Ben can build it and John will give it a once-over.
305
+ ${exports.ORCHESTRATOR_DECISION_SENTINEL}
306
+ ${JSON.stringify({
307
+ mode: 'workflow',
308
+ reason: 'Multi-step build',
309
+ workflow_request: 'Brain plan, Ben code, John QA',
310
+ }, null, 2)}
311
+
312
+ THE JSON SCHEMA:`
313
+ : `OUTPUT FORMAT (TWO PARTS — narration THEN decision/answer)
314
+
315
+ PART 1: NARRATION
316
+ If you are splitting the work, write exactly ONE short, friendly sentence first telling the user what you're about to do.
317
+ Be natural and warm. Vary the wording. No robotic boilerplate.
318
+ If you are keeping the work and answering directly, skip narration and just return your answer.
319
+
320
+ PART 2: DECISION OR DIRECT ANSWER
321
+ - If you keep the work: return the user-facing answer directly with no JSON, no sentinel.
322
+ - If you split the work: after narration, on a new line write ${exports.ORCHESTRATOR_DECISION_SENTINEL}, then write exactly one JSON object.
219
323
  - Do not wrap JSON in markdown fences.
220
- - Do not add commentary before or after the JSON.`}
324
+
325
+ THE JSON SCHEMA:`}
221
326
  ${JSON.stringify({
222
327
  mode: decisionOnly ? 'respond | execute_self | delegate | workflow | clarify' : 'respond | delegate | workflow | clarify',
223
328
  reason: 'short explanation',
@@ -243,13 +348,37 @@ RECENT SUMMARY
243
348
  ${recentSummary}
244
349
 
245
350
  LAST 5 TURNS
246
- ${lastFiveTurns}`;
351
+ ${lastFiveTurns}${bootstrapHistoryFilePath
352
+ ? `
353
+
354
+ BOOTSTRAP HISTORY FILE
355
+ Please read the history file at: ${bootstrapHistoryFilePath}
356
+ Use it for context only. Do not mention the file or path unless the user asks.`
357
+ : ''}`;
358
+ }
359
+ /**
360
+ * Splits the LLM raw output at the ===DECISION=== sentinel.
361
+ * Returns { narration, decisionText } where narration may be empty if the
362
+ * LLM did not follow the format. The decisionText is the portion after
363
+ * the sentinel (or the entire raw if no sentinel was found, for backward compat).
364
+ */
365
+ function splitOrchestratorNarrationAndDecision(raw) {
366
+ const text = String(raw || '');
367
+ const sentinelIdx = text.indexOf(exports.ORCHESTRATOR_DECISION_SENTINEL);
368
+ if (sentinelIdx < 0) {
369
+ return { narration: '', decisionText: text };
370
+ }
371
+ const narration = text.slice(0, sentinelIdx).trim();
372
+ const decisionText = text.slice(sentinelIdx + exports.ORCHESTRATOR_DECISION_SENTINEL.length).trim();
373
+ return { narration, decisionText };
247
374
  }
248
375
  function parseOrchestratorFrontDoorDecision(raw) {
249
376
  const trimmed = String(raw || '').trim();
250
377
  if (!trimmed)
251
378
  return null;
252
- const unfenced = trimmed
379
+ const { narration, decisionText } = splitOrchestratorNarrationAndDecision(trimmed);
380
+ const sourceForJson = decisionText || trimmed;
381
+ const unfenced = sourceForJson
253
382
  .replace(/^```json\s*/i, '')
254
383
  .replace(/^```\s*/i, '')
255
384
  .replace(/\s*```$/i, '')
@@ -271,13 +400,9 @@ function parseOrchestratorFrontDoorDecision(raw) {
271
400
  else {
272
401
  normalizedMode = 'execute_self';
273
402
  }
274
- // Safety net: if respond mode contains ANY orchestration language, auto-correct to execute_self
275
- if (normalizedMode === 'respond' && typeof parsed.response === 'string') {
276
- const resp = parsed.response.toLowerCase();
277
- if (/which (worker|bot|agent|specialist)|ready to coordinate|get the right bots|before i start|need a few details|i need to know|which .* should handle|let me (coordinate|orchestrate|route|assign)/i.test(resp)) {
278
- normalizedMode = 'execute_self';
279
- }
280
- }
403
+ // Prefer top-level narration field on the JSON object if present, otherwise the pre-sentinel text.
404
+ const narrationFromJson = typeof parsed.narration === 'string' ? parsed.narration.trim() : '';
405
+ const finalNarration = narrationFromJson || narration || '';
281
406
  return {
282
407
  mode: normalizedMode,
283
408
  reason: String(parsed.reason || '').trim(),
@@ -289,6 +414,7 @@ function parseOrchestratorFrontDoorDecision(raw) {
289
414
  clarification_questions: Array.isArray(parsed.clarification_questions)
290
415
  ? parsed.clarification_questions.map((item) => String(item || '').trim()).filter(Boolean)
291
416
  : undefined,
417
+ narration: finalNarration || undefined,
292
418
  };
293
419
  }
294
420
  catch {