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.
- package/dist/auth/credential-reader.d.ts.map +1 -1
- package/dist/auth/credential-reader.js +4 -3
- package/dist/auth/credential-reader.js.map +1 -1
- package/dist/auth/token-refresh.d.ts +8 -0
- package/dist/auth/token-refresh.d.ts.map +1 -1
- package/dist/auth/token-refresh.js +82 -52
- package/dist/auth/token-refresh.js.map +1 -1
- package/dist/auto-organizer.d.ts.map +1 -1
- package/dist/auto-organizer.js +6 -7
- package/dist/auto-organizer.js.map +1 -1
- package/dist/bench-prefix.d.ts +16 -0
- package/dist/bench-prefix.d.ts.map +1 -0
- package/dist/bench-prefix.js +25 -0
- package/dist/bench-prefix.js.map +1 -0
- package/dist/bot-manager.d.ts.map +1 -1
- package/dist/bot-manager.js +23 -14
- package/dist/bot-manager.js.map +1 -1
- package/dist/chat-sync.d.ts +42 -0
- package/dist/chat-sync.d.ts.map +1 -0
- package/dist/chat-sync.js +95 -0
- package/dist/chat-sync.js.map +1 -0
- package/dist/clerk-model.d.ts +7 -0
- package/dist/clerk-model.d.ts.map +1 -1
- package/dist/clerk-model.js +42 -8
- package/dist/clerk-model.js.map +1 -1
- package/dist/cli-bootstrap-history.d.ts +10 -0
- package/dist/cli-bootstrap-history.d.ts.map +1 -0
- package/dist/cli-bootstrap-history.js +112 -0
- package/dist/cli-bootstrap-history.js.map +1 -0
- package/dist/cli-models.d.ts +8 -0
- package/dist/cli-models.d.ts.map +1 -0
- package/dist/cli-models.js +91 -0
- package/dist/cli-models.js.map +1 -0
- package/dist/cli-session-epoch.d.ts +13 -3
- package/dist/cli-session-epoch.d.ts.map +1 -1
- package/dist/cli-session-epoch.js +53 -4
- package/dist/cli-session-epoch.js.map +1 -1
- package/dist/codex-app-server-manager.d.ts +64 -4
- package/dist/codex-app-server-manager.d.ts.map +1 -1
- package/dist/codex-app-server-manager.js +755 -55
- package/dist/codex-app-server-manager.js.map +1 -1
- package/dist/commands/pool.d.ts +32 -0
- package/dist/commands/pool.d.ts.map +1 -1
- package/dist/commands/pool.js +145 -66
- package/dist/commands/pool.js.map +1 -1
- package/dist/commands/start.d.ts +21 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +484 -63
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +5 -2
- package/dist/commands/status.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +170 -58
- package/dist/config.js.map +1 -1
- package/dist/context-window.d.ts +37 -1
- package/dist/context-window.d.ts.map +1 -1
- package/dist/context-window.js +202 -16
- package/dist/context-window.js.map +1 -1
- package/dist/live-activity.d.ts +3 -1
- package/dist/live-activity.d.ts.map +1 -1
- package/dist/live-activity.js.map +1 -1
- package/dist/local-chat-execution.d.ts +114 -0
- package/dist/local-chat-execution.d.ts.map +1 -0
- package/dist/local-chat-execution.js +349 -0
- package/dist/local-chat-execution.js.map +1 -0
- package/dist/local-cli-pty-manager.d.ts +138 -3
- package/dist/local-cli-pty-manager.d.ts.map +1 -1
- package/dist/local-cli-pty-manager.js +1415 -111
- package/dist/local-cli-pty-manager.js.map +1 -1
- package/dist/local-conversation-gateway.d.ts +110 -0
- package/dist/local-conversation-gateway.d.ts.map +1 -0
- package/dist/local-conversation-gateway.js +175 -0
- package/dist/local-conversation-gateway.js.map +1 -0
- package/dist/local-data.d.ts +235 -5
- package/dist/local-data.d.ts.map +1 -1
- package/dist/local-data.js +1066 -87
- package/dist/local-data.js.map +1 -1
- package/dist/local-db.d.ts +6 -0
- package/dist/local-db.d.ts.map +1 -1
- package/dist/local-db.js +376 -4
- package/dist/local-db.js.map +1 -1
- package/dist/local-funnel.d.ts.map +1 -1
- package/dist/local-funnel.js +6 -5
- package/dist/local-funnel.js.map +1 -1
- package/dist/local-server.d.ts +30 -0
- package/dist/local-server.d.ts.map +1 -1
- package/dist/local-server.js +2898 -319
- package/dist/local-server.js.map +1 -1
- package/dist/managed-process-registry.d.ts +59 -0
- package/dist/managed-process-registry.d.ts.map +1 -0
- package/dist/managed-process-registry.js +390 -0
- package/dist/managed-process-registry.js.map +1 -0
- package/dist/mcp/claude-config-writer.d.ts +5 -5
- package/dist/mcp/claude-config-writer.d.ts.map +1 -1
- package/dist/mcp/claude-config-writer.js +19 -11
- package/dist/mcp/claude-config-writer.js.map +1 -1
- package/dist/mcp/index.d.ts +4 -2
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/sync-cli-config.d.ts +42 -4
- package/dist/mcp/sync-cli-config.d.ts.map +1 -1
- package/dist/mcp/sync-cli-config.js +497 -17
- package/dist/mcp/sync-cli-config.js.map +1 -1
- package/dist/message-loop.d.ts.map +1 -1
- package/dist/message-loop.js +43 -1
- package/dist/message-loop.js.map +1 -1
- package/dist/mqtt-client.d.ts +34 -0
- package/dist/mqtt-client.d.ts.map +1 -1
- package/dist/mqtt-client.js +270 -45
- package/dist/mqtt-client.js.map +1 -1
- package/dist/mqtt-data-relay.d.ts +44 -0
- package/dist/mqtt-data-relay.d.ts.map +1 -0
- package/dist/mqtt-data-relay.js +106 -0
- package/dist/mqtt-data-relay.js.map +1 -0
- package/dist/orchestration/capabilities.d.ts +13 -0
- package/dist/orchestration/capabilities.d.ts.map +1 -0
- package/dist/orchestration/capabilities.js +152 -0
- package/dist/orchestration/capabilities.js.map +1 -0
- package/dist/orchestration/dispatch-executor.d.ts +83 -0
- package/dist/orchestration/dispatch-executor.d.ts.map +1 -0
- package/dist/orchestration/dispatch-executor.js +266 -0
- package/dist/orchestration/dispatch-executor.js.map +1 -0
- package/dist/orchestration/dispatch-hint.d.ts +134 -0
- package/dist/orchestration/dispatch-hint.d.ts.map +1 -0
- package/dist/orchestration/dispatch-hint.js +247 -0
- package/dist/orchestration/dispatch-hint.js.map +1 -0
- package/dist/orchestration/dispatch-runner.d.ts +106 -0
- package/dist/orchestration/dispatch-runner.d.ts.map +1 -0
- package/dist/orchestration/dispatch-runner.js +604 -0
- package/dist/orchestration/dispatch-runner.js.map +1 -0
- package/dist/orchestration/dispatch-tools.d.ts +167 -0
- package/dist/orchestration/dispatch-tools.d.ts.map +1 -0
- package/dist/orchestration/dispatch-tools.js +328 -0
- package/dist/orchestration/dispatch-tools.js.map +1 -0
- package/dist/orchestration/front-door-policy.d.ts +35 -10
- package/dist/orchestration/front-door-policy.d.ts.map +1 -1
- package/dist/orchestration/front-door-policy.js +30 -267
- package/dist/orchestration/front-door-policy.js.map +1 -1
- package/dist/orchestration/orchestrator-dispatch-prompt.d.ts +43 -0
- package/dist/orchestration/orchestrator-dispatch-prompt.d.ts.map +1 -0
- package/dist/orchestration/orchestrator-dispatch-prompt.js +267 -0
- package/dist/orchestration/orchestrator-dispatch-prompt.js.map +1 -0
- package/dist/orchestration/orchestrator-operating-prompt.d.ts +14 -0
- package/dist/orchestration/orchestrator-operating-prompt.d.ts.map +1 -1
- package/dist/orchestration/orchestrator-operating-prompt.js +157 -31
- package/dist/orchestration/orchestrator-operating-prompt.js.map +1 -1
- package/dist/orchestration/plan-import.d.ts +39 -0
- package/dist/orchestration/plan-import.d.ts.map +1 -0
- package/dist/orchestration/plan-import.js +547 -0
- package/dist/orchestration/plan-import.js.map +1 -0
- package/dist/orchestration/worker-operating-prompt.d.ts +2 -0
- package/dist/orchestration/worker-operating-prompt.d.ts.map +1 -1
- package/dist/orchestration/worker-operating-prompt.js +36 -46
- package/dist/orchestration/worker-operating-prompt.js.map +1 -1
- package/dist/orchestrator.d.ts +195 -3
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +1970 -432
- package/dist/orchestrator.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +8 -4
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/claude-cli.d.ts.map +1 -1
- package/dist/providers/claude-cli.js +28 -3
- package/dist/providers/claude-cli.js.map +1 -1
- package/dist/providers/codex-cli.d.ts +10 -6
- package/dist/providers/codex-cli.d.ts.map +1 -1
- package/dist/providers/codex-cli.js +190 -17
- package/dist/providers/codex-cli.js.map +1 -1
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +15 -5
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/index.d.ts +15 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +13 -5
- package/dist/providers/openai.js.map +1 -1
- package/dist/server-adapter.d.ts +8 -0
- package/dist/server-adapter.d.ts.map +1 -1
- package/dist/server-adapter.js +7 -0
- package/dist/server-adapter.js.map +1 -1
- package/dist/service-mode.d.ts +1 -1
- package/dist/service-mode.d.ts.map +1 -1
- package/dist/service-mode.js +64 -1
- package/dist/service-mode.js.map +1 -1
- package/dist/service-setup-only.d.ts +8 -0
- package/dist/service-setup-only.d.ts.map +1 -0
- package/dist/service-setup-only.js +37 -0
- package/dist/service-setup-only.js.map +1 -0
- package/dist/slash-commands.d.ts +21 -0
- package/dist/slash-commands.d.ts.map +1 -0
- package/dist/slash-commands.js +99 -0
- package/dist/slash-commands.js.map +1 -0
- package/dist/subagent/index.d.ts +4 -2
- package/dist/subagent/index.d.ts.map +1 -1
- package/dist/subagent/index.js.map +1 -1
- package/dist/summarization-pipeline.d.ts.map +1 -1
- package/dist/summarization-pipeline.js +1 -9
- package/dist/summarization-pipeline.js.map +1 -1
- package/dist/token-counter.d.ts.map +1 -1
- package/dist/token-counter.js +11 -4
- package/dist/token-counter.js.map +1 -1
- package/dist/tool-filter.d.ts.map +1 -1
- package/dist/tool-filter.js +10 -6
- package/dist/tool-filter.js.map +1 -1
- package/dist/tools/admin-tools.d.ts.map +1 -1
- package/dist/tools/admin-tools.js +13 -4
- package/dist/tools/admin-tools.js.map +1 -1
- package/dist/tools/run-command.d.ts.map +1 -1
- package/dist/tools/run-command.js +5 -1
- package/dist/tools/run-command.js.map +1 -1
- package/dist/tools/search-conversation-history.d.ts.map +1 -1
- package/dist/tools/search-conversation-history.js +12 -2
- package/dist/tools/search-conversation-history.js.map +1 -1
- package/dist/tools/todo-tasks.d.ts.map +1 -1
- package/dist/tools/todo-tasks.js +77 -5
- package/dist/tools/todo-tasks.js.map +1 -1
- package/dist/usage-log.d.ts +62 -0
- package/dist/usage-log.d.ts.map +1 -0
- package/dist/usage-log.js +98 -0
- package/dist/usage-log.js.map +1 -0
- package/dist/wizard-state.d.ts +13 -0
- package/dist/wizard-state.d.ts.map +1 -1
- package/dist/wizard-state.js +61 -3
- package/dist/wizard-state.js.map +1 -1
- package/dist/wizard-support.d.ts.map +1 -1
- package/dist/wizard-support.js +27 -1
- package/dist/wizard-support.js.map +1 -1
- package/dist/workflow-engine.d.ts +40 -1
- package/dist/workflow-engine.d.ts.map +1 -1
- package/dist/workflow-engine.js +753 -93
- package/dist/workflow-engine.js.map +1 -1
- 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;
|
|
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
|
|
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
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
-
|
|
109
|
-
- If you
|
|
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
|
-
|
|
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
|
|
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
|
-
-
|
|
182
|
-
-
|
|
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
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
-
|
|
218
|
-
- If you
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
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 {
|