reasoning.run 0.1.0
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/LICENSE +54 -0
- package/README.md +99 -0
- package/bin/run.js +13 -0
- package/dist/bundle.mjs +664 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
PROPRIETARY SOFTWARE LICENSE
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lloyal AI. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and all associated files (the "Software") are the
|
|
6
|
+
proprietary and confidential property of Lloyal AI.
|
|
7
|
+
|
|
8
|
+
PERMITTED USE
|
|
9
|
+
|
|
10
|
+
You are granted a non-exclusive, non-transferable, revocable license to
|
|
11
|
+
download and execute the Software via npm/npx for personal or internal
|
|
12
|
+
business research purposes, subject to all terms below.
|
|
13
|
+
|
|
14
|
+
PROHIBITED
|
|
15
|
+
|
|
16
|
+
The following are prohibited without prior written permission from
|
|
17
|
+
Lloyal AI:
|
|
18
|
+
|
|
19
|
+
1. Copying, redistributing, sublicensing, selling, or making the
|
|
20
|
+
Software available to third parties.
|
|
21
|
+
|
|
22
|
+
2. Modifying, adapting, translating, or creating derivative works
|
|
23
|
+
based on the Software.
|
|
24
|
+
|
|
25
|
+
3. Reverse engineering, decompiling, disassembling, or otherwise
|
|
26
|
+
attempting to derive source code, prompt content, or proprietary
|
|
27
|
+
algorithms from the Software, except to the extent such activity
|
|
28
|
+
is expressly permitted by applicable non-waivable law.
|
|
29
|
+
|
|
30
|
+
4. Removing, altering, or obscuring any copyright, trademark, or
|
|
31
|
+
other proprietary notices.
|
|
32
|
+
|
|
33
|
+
5. Using the Software to develop a competing product.
|
|
34
|
+
|
|
35
|
+
THIRD-PARTY COMPONENTS
|
|
36
|
+
|
|
37
|
+
The Software incorporates components from third parties, including
|
|
38
|
+
without limitation @lloyal-labs/sdk, @lloyal-labs/lloyal-agents,
|
|
39
|
+
@lloyal-labs/rig, @lloyal-labs/lloyal.node, llama.cpp, Ink, React,
|
|
40
|
+
Effection, Eta, and ignore. Each such component is licensed under its
|
|
41
|
+
own terms; this license applies only to the original portions of the
|
|
42
|
+
Software authored by Lloyal AI.
|
|
43
|
+
|
|
44
|
+
DISCLAIMER
|
|
45
|
+
|
|
46
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
47
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
48
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
|
|
49
|
+
IN NO EVENT SHALL LLOYAL AI BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER
|
|
50
|
+
LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR
|
|
51
|
+
THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
52
|
+
|
|
53
|
+
For licensing inquiries beyond the permitted use above, contact
|
|
54
|
+
Lloyal AI.
|
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# reasoning.run
|
|
2
|
+
|
|
3
|
+
Local deep-research agent composer — runs on your machine, zero-config after the first query.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
npx reasoning.run
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Then type a research question.
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
|
|
13
|
+
- Downloads a Qwen3.5-4B LLM and Qwen3 reranker on first run (~3 GB, cached in `~/.cache/lloyal/models/`).
|
|
14
|
+
- Runs a planner that decomposes your question into research tasks.
|
|
15
|
+
- Shows the plan in an Ink-based composer; press Enter to approve or `E` to edit.
|
|
16
|
+
- Spawns research agents (parallel for `Fast` mode, chained for `Deep` mode) that query your corpus and/or the web via Tavily.
|
|
17
|
+
- Synthesizes findings into a coherent answer, streamed live.
|
|
18
|
+
|
|
19
|
+
## Configuration
|
|
20
|
+
|
|
21
|
+
State lives in `./harness.json` (auto-created, auto-gitignored on first save):
|
|
22
|
+
|
|
23
|
+
```jsonc
|
|
24
|
+
{
|
|
25
|
+
"sources": {
|
|
26
|
+
"tavilyKey": "tvly-...", // optional — web search via Tavily
|
|
27
|
+
"corpusPath": "/path/to/docs", // optional — local markdown corpus
|
|
28
|
+
"outputDir": "./reasoning-runs" // optional — defaults to cwd
|
|
29
|
+
},
|
|
30
|
+
"defaults": {
|
|
31
|
+
"reasoningMode": "deep" // or "flat"
|
|
32
|
+
},
|
|
33
|
+
"model": {
|
|
34
|
+
"nCtx": 32768 // LLM context window
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Settings in the composer
|
|
40
|
+
|
|
41
|
+
Press `Esc` to open the menu mode:
|
|
42
|
+
|
|
43
|
+
- `W` → set Tavily key (or clear with empty)
|
|
44
|
+
- `C` → set corpus path (or clear with empty)
|
|
45
|
+
- `O` → set output dir (or clear to fall back to cwd)
|
|
46
|
+
- `T` → toggle Deep / Fast reasoning
|
|
47
|
+
- `Esc` → back to the query input
|
|
48
|
+
|
|
49
|
+
Everything persists to `harness.json` the moment you save.
|
|
50
|
+
|
|
51
|
+
## Run artifacts
|
|
52
|
+
|
|
53
|
+
Every query writes a self-contained bundle under `<output-dir>/<ISO-timestamp>/`:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
<output-dir>/
|
|
57
|
+
trace-2026-05-01T12-34-56.jsonl ← session trace (one per process invocation)
|
|
58
|
+
2026-05-01T12-34-56/ ← query 1
|
|
59
|
+
report.md ← synth answer + metadata + annexure index
|
|
60
|
+
annexure-1.md ← research agent 1's report
|
|
61
|
+
annexure-2.md
|
|
62
|
+
annexure-3.md
|
|
63
|
+
2026-05-01T13-02-11/ ← follow-up query 2
|
|
64
|
+
report.md
|
|
65
|
+
annexure-1.md
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`<output-dir>` defaults to the directory you launched from. Override with `--output-dir <path>` or the composer's `O` hotkey. The session trace captures every query (including warm follow-ups) in one file.
|
|
69
|
+
|
|
70
|
+
### Environment overrides
|
|
71
|
+
|
|
72
|
+
- `TAVILY_API_KEY` — wins over the stored key; never persists to disk while set.
|
|
73
|
+
- `LLAMA_CTX_SIZE` — context window fallback.
|
|
74
|
+
|
|
75
|
+
## Keyboard shortcuts
|
|
76
|
+
|
|
77
|
+
Standard readline chords (work in every terminal):
|
|
78
|
+
|
|
79
|
+
| Chord | Effect |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `Ctrl+A` | Jump to line start |
|
|
82
|
+
| `Ctrl+E` | Jump to line end |
|
|
83
|
+
| `Ctrl+U` | Clear to line start |
|
|
84
|
+
| `Ctrl+K` | Clear to line end |
|
|
85
|
+
| `Ctrl+W` | Delete word back |
|
|
86
|
+
| `Opt+Backspace` | Delete word back (macOS; requires "Use Option as Meta key" in Terminal.app) |
|
|
87
|
+
| `Ctrl+C` | Quit |
|
|
88
|
+
|
|
89
|
+
For Cmd+Backspace / Cmd+arrow to work, turn on "Natural Text Editing" in iTerm2, or use Ghostty.
|
|
90
|
+
|
|
91
|
+
## Source
|
|
92
|
+
|
|
93
|
+
- Built on [`@lloyal-labs/*`](https://github.com/lloyal-ai/lloyal-sdk) for the agent runtime, session/branch primitives, and RIG tools.
|
|
94
|
+
- Local inference via `@lloyal-labs/lloyal.node` (llama.cpp Node binding).
|
|
95
|
+
- UI via Ink (React for terminals).
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
Proprietary. © 2026 Lloyal AI. See `LICENSE` for terms.
|
package/bin/run.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* reasoning.run — entry point for `npx reasoning.run`.
|
|
4
|
+
*
|
|
5
|
+
* Loads the pre-built ESM bundle. Source is not shipped — see
|
|
6
|
+
* `package.json` `files` whitelist. Build with `npm run build`
|
|
7
|
+
* (also invoked automatically on `npm publish` via prepublishOnly).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import("../dist/bundle.mjs").catch((err) => {
|
|
11
|
+
process.stderr.write(`Error: ${err && err.stack ? err.stack : err}\n`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
});
|
package/dist/bundle.mjs
ADDED
|
@@ -0,0 +1,664 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var ao=Object.defineProperty;var E=(t,e)=>()=>(t&&(e=t(t=0)),e);var lo=(t,e)=>{for(var n in e)ao(t,n,{get:e[n],enumerable:!0})};var ut,Nt=E(()=>{"use strict";ut={query:"",warm:!1,uiPhase:"boot",phase:"idle",mode:null,plan:null,agents:new Map,researchAgentIds:[],sourceCount:0,synth:{open:!1,buffer:"",done:!1,stats:null},verify:{active:!1,count:0,done:!1,timeMs:null},evalState:null,answer:null,pressure:null,timings:[],startedAt:Date.now(),pipelineElapsedMs:0,pipelineResumedAt:null,nextTimelineId:0,nextLabelIdx:0,pendingTaskIndex:null,pendingTaskDescription:null,researchSpawnCount:0,config:null,configOrigin:null,toast:null,composerPrefill:"",clarifyContext:null,downloads:[],loadingLabel:null,nextToastId:0,scrollback:[],corpusStatus:null,bootError:null}});function Lt(t){let e=process.env.HOME;return e&&t.startsWith(e)?"~"+t.slice(e.length):t}function Ko(t){let e=t.replace(/^\s*\n/,"").replace(/\*\*/g,"").replace(/^#+\s*/,"").trim();if(!e)return"Thinking\u2026";let n=e.split(`
|
|
3
|
+
`)[0].trim();return n.length>72?n.slice(0,72).trimEnd()+"\u2026":n}function dt(t){try{return new URL(t).hostname.replace(/^www\./,"")}catch{return t}}function Go(t,e){let n;try{n=JSON.parse(e)}catch{n={}}let r=typeof n.query=="string"?n.query:typeof n.pattern=="string"?n.pattern:typeof n.url=="string"?n.url:typeof n.filename=="string"?n.filename:"";return r?`"${r.length>48?r.slice(0,48)+"\u2026":r}"`:""}function Qo(t,e){try{let r=JSON.parse(e);if(t==="web_search"&&Array.isArray(r)){let o=r,s=Array.from(new Set(o.map(i=>i.url?dt(i.url):"").filter(Boolean))).slice(0,3);return{summary:`${o.length} results`,hosts:s,resultCount:o.length,preview:o[0]?.title??null}}if(t==="search"&&Array.isArray(r)){let o=r;return{summary:`${o.length} results`,hosts:[],resultCount:o.length,preview:o[0]?.heading??null}}if(t==="grep"&&typeof r=="object"&&r!==null){let o=r;return{summary:`${o.totalMatches??0} matches`,hosts:[],resultCount:o.totalMatches??null,preview:null}}if(t==="fetch_page"&&typeof r=="object"&&r!==null){let o=r;if(o.error)return{summary:o.error,hosts:[],resultCount:null,preview:null};let s=o.url?[dt(o.url)]:[];return{summary:`${e.length}b`,hosts:s,resultCount:null,preview:o.title??null}}if(t==="web_fetch"&&typeof r=="object"&&r!==null){let o=r,s=o.url?[dt(o.url)]:[];return{summary:`${e.length}b`,hosts:s,resultCount:null,preview:o.title??null}}}catch{}let n=Array.from(e.matchAll(/https?:\/\/[^\s\])>"]+/g)).map(r=>r[0]);if(n.length>0){let r=Array.from(new Set(n.map(dt))).slice(0,3);return{summary:`${n.length} links`,hosts:r,resultCount:n.length,preview:null}}return{summary:`${e.length}b`,hosts:[],resultCount:null,preview:null}}function J(t,e,n){let r=t.agents.get(e);if(!r)return t;let o=new Map(t.agents);return o.set(e,n(r)),{...t,agents:o}}function Qn(t,e,n={}){if(t.agents.has(e))return t;let r={id:e,label:`A${t.nextLabelIdx}`,phase:"idle",tokenCount:0,toolCallCount:0,taskIndex:null,taskDescription:null,dependencyHint:null,currentThinkId:null,pendingToolCallId:null,contentBuffer:"",timeline:[],...n},o=new Map(t.agents);return o.set(e,r),{...t,agents:o,nextLabelIdx:t.nextLabelIdx+1}}function ht(t,e){return{...t,timeline:[...t.timeline,e]}}function Jn(t,e,n){return{...t,timeline:t.timeline.map(r=>r.id===e?n(r):r)}}function Vn(t,e){let n=t.nextTimelineId;return{...J(t,e,o=>ht({...o,currentThinkId:n,phase:"thinking"},{kind:"think",id:n,title:"Thinking\u2026",body:"",live:!0,openedAt:Date.now(),closedAt:null})),nextTimelineId:t.nextTimelineId+1}}function pt(t,e,n){let r=t.agents.get(e);if(!r||r.currentThinkId===null)return t;let o=r.currentThinkId,s=Ko(n);return J(t,e,i=>Jn({...i,currentThinkId:null,phase:"content"},o,a=>a.kind==="think"?{...a,body:n,title:s,live:!1,closedAt:Date.now()}:a))}function Ft(t,e){switch(e.type){case"query":return{...ut,config:t.config,configOrigin:t.configOrigin,uiPhase:t.uiPhase,mode:t.mode,nextToastId:t.nextToastId,toast:t.toast,scrollback:t.scrollback,query:e.query,warm:e.warm,phase:"plan",startedAt:Date.now()};case"plan":return{...t,uiPhase:e.intent==="clarify"?"clarifying":t.uiPhase,phase:e.intent==="research"?"plan":"done",plan:{intent:e.intent,tasks:e.tasks,clarifyQuestions:e.clarifyQuestions,tokenCount:e.tokenCount,timeMs:e.timeMs},clarifyContext:e.intent==="clarify"?{originalQuery:t.query,questions:e.clarifyQuestions}:null};case"research:start":return{...t,uiPhase:"research",phase:"research",mode:e.mode==="flat"?"flat":"deep",pipelineResumedAt:Date.now()};case"research:done":return{...t,phase:"synth"};case"fanout:tasks":return t;case"spine:task":return{...t,pendingTaskIndex:e.taskIndex,pendingTaskDescription:e.description};case"spine:source":case"spine:task:done":return t;case"synthesize:start":return{...t,phase:"synth",synth:{open:!0,buffer:"",done:!1,stats:null}};case"synthesize:done":{let n=t.synth.buffer.trim(),r=n?[...t.scrollback,{key:`synth-${t.scrollback.length}-${Date.now()}`,kind:"synth",body:n}]:t.scrollback;return{...t,scrollback:r,synth:{...t.synth,open:!1,done:!0,stats:{tokens:e.tokenCount,toolCalls:e.toolCallCount,ppl:e.ppl,timeMs:e.timeMs}}}}case"verify:start":return{...t,phase:"verify",verify:{active:!0,count:e.count,done:!1,timeMs:null}};case"verify:done":return{...t,verify:{active:!1,count:e.count,done:!0,timeMs:e.timeMs}};case"eval:done":return{...t,phase:"eval",evalState:{done:!0,converged:e.converged,sampleCount:e.sampleCount,tokenCount:e.tokenCount,timeMs:e.timeMs}};case"answer":return{...t,answer:e.text};case"stats":return{...t,timings:e.timings,pressure:{pct:e.ctxPct,cellsUsed:e.ctxPos,nCtx:e.ctxTotal}};case"complete":{let n=t.pipelineResumedAt?t.pipelineElapsedMs+(Date.now()-t.pipelineResumedAt):t.pipelineElapsedMs;return{...t,phase:"done",uiPhase:"done",pipelineElapsedMs:n,pipelineResumedAt:null}}case"config:loaded":return{...t,config:e.config,configOrigin:e.origin};case"config:updated":{let n=t.nextToastId+1,r=e.skipped.length>0?`saved \u2192 ${Lt(e.savedTo)} (skipped: ${e.skipped.join(", ")} \u2014 env active)`:e.gitignored?`saved \u2192 ${Lt(e.savedTo)} (added to .gitignore)`:`saved \u2192 ${Lt(e.savedTo)}`;return{...t,config:e.config,configOrigin:e.origin,toast:{id:n,message:r,tone:e.skipped.length>0?"warn":"success"},nextToastId:n}}case"plan:start":{let r=t.uiPhase==="composer"||t.uiPhase==="done"||t.uiPhase==="boot"?{pipelineElapsedMs:0,startedAt:Date.now()}:{};return{...t,...r,uiPhase:"planning",phase:"plan",plan:null,query:e.query,mode:e.mode==="flat"?"flat":"deep",pipelineResumedAt:Date.now()}}case"ui:composer":{let n=t.pipelineResumedAt?t.pipelineElapsedMs+(Date.now()-t.pipelineResumedAt):t.pipelineElapsedMs;return{...t,uiPhase:"composer",composerPrefill:e.prefill??"",clarifyContext:null,pipelineElapsedMs:n,pipelineResumedAt:null}}case"ui:plan_review":{let n=t.pipelineResumedAt?t.pipelineElapsedMs+(Date.now()-t.pipelineResumedAt):t.pipelineElapsedMs;return{...t,uiPhase:"plan_review",pipelineElapsedMs:n,pipelineResumedAt:null}}case"ui:error":{let n=t.nextToastId+1;return{...t,uiPhase:"composer",toast:{id:n,message:e.message,tone:"error"},nextToastId:n}}case"download:plan":return{...t,uiPhase:"downloading",downloads:e.entries.map(n=>({id:n.id,label:n.label,got:0,total:n.sizeBytes,done:!1,started:!1}))};case"download:start":return{...t,uiPhase:"downloading",downloads:t.downloads.map(n=>n.id===e.id?{...n,started:!0}:n)};case"download:progress":return{...t,downloads:t.downloads.map(n=>n.id===e.id?{...n,started:!0,got:e.got,total:e.total,url:e.url??n.url}:n)};case"download:complete":return{...t,downloads:t.downloads.map(n=>n.id===e.id?{...n,got:n.total||n.got,done:!0}:n)};case"weights:start":return{...t,uiPhase:"loading",loadingLabel:e.label};case"weights:label":return{...t,loadingLabel:e.label};case"weights:done":return{...t,loadingLabel:null};case"corpus:indexed":return{...t,corpusStatus:{fileCount:e.fileCount,chunkCount:e.chunkCount}};case"boot:error":return{...t,uiPhase:"boot_error",bootError:{kind:e.kind,message:e.message}};case"agent:spawn":{if(t.phase!=="research")return Qn(t,e.agentId,{phase:"idle",taskIndex:null});let n,r,o=t.pendingTaskIndex,s=t.pendingTaskDescription;t.mode==="deep"?(n=o??t.researchSpawnCount,r=s??t.plan?.tasks[n]?.description??null,o=null,s=null):(n=t.researchSpawnCount,r=t.plan?.tasks[n]?.description??null);let i=t.mode==="deep"&&n>0?`builds on Task ${n}`:null,a=Qn(t,e.agentId,{phase:"thinking",taskIndex:n,taskDescription:r,dependencyHint:i});return a={...a,researchAgentIds:[...a.researchAgentIds,e.agentId],researchSpawnCount:t.researchSpawnCount+1,pendingTaskIndex:o,pendingTaskDescription:s},Vn(a,e.agentId)}case"agent:produce":{if(t.phase==="synth"&&t.synth.open)return{...t,synth:{...t.synth,buffer:t.synth.buffer+e.text}};if(t.phase==="verify"||t.phase==="eval"||t.phase!=="research")return t;let n=t.agents.get(e.agentId);if(!n||n.taskIndex===null)return t;let r=t,o=n;if(o.phase==="content")return J(r,o.id,x=>({...x,tokenCount:e.tokenCount,contentBuffer:x.contentBuffer+e.text}));if(o.phase!=="thinking"||o.currentThinkId===null)if(o.phase==="tool"||o.phase==="idle")r=Vn(r,o.id),o=r.agents.get(o.id);else return J(r,o.id,x=>({...x,tokenCount:e.tokenCount}));let s=o.currentThinkId,i=o.timeline.find(x=>x.id===s);if(!i||i.kind!=="think")return r;let a=i.body+e.text,p=a.indexOf(Gn);if(p===-1)return J(r,o.id,x=>Jn({...x,tokenCount:e.tokenCount},s,k=>k.kind==="think"?{...k,body:a}:k));let l=a.slice(0,p),u=a.slice(p+Gn.length),h=pt(r,o.id,l);return J(h,o.id,x=>({...x,tokenCount:e.tokenCount,contentBuffer:u}))}case"agent:tool_call":{let n=t.agents.get(e.agentId);if(!n)return t;let r=t;if(n.currentThinkId!==null){let i=n.timeline.find(p=>p.id===n.currentThinkId),a=i&&i.kind==="think"?i.body:"";r=pt(r,e.agentId,a)}if(r.agents.get(e.agentId)?.taskIndex==null)return J(r,e.agentId,i=>({...i,phase:"tool",toolCallCount:i.toolCallCount+1}));let o=r.nextTimelineId;return{...J(r,e.agentId,i=>ht({...i,phase:"tool",toolCallCount:i.toolCallCount+1,pendingToolCallId:o,contentBuffer:""},{kind:"tool_call",id:o,tool:e.tool,argsSummary:Go(e.tool,e.args)})),nextTimelineId:r.nextTimelineId+1}}case"agent:tool_result":{let n=t.agents.get(e.agentId);if(!n)return t;if(n.taskIndex==null)return J(t,e.agentId,a=>({...a,phase:"idle"}));let r=Qo(e.tool,e.result),o=t.nextTimelineId,s=Array.from(new Set(r.hosts));return{...J(t,e.agentId,a=>ht({...a,phase:"idle",pendingToolCallId:null},{kind:"tool_result",id:o,tool:e.tool,callId:n.pendingToolCallId,byteLength:e.result.length,preview:r.preview,hosts:s,resultCount:r.resultCount})),nextTimelineId:t.nextTimelineId+1,sourceCount:t.sourceCount+s.length}}case"agent:tool_progress":return t;case"agent:report":{let n=t.agents.get(e.agentId);if(!n)return t;let r=t;if(n.currentThinkId!==null){let u=n.timeline.find(x=>x.id===n.currentThinkId),h=u&&u.kind==="think"?u.body:"";r=pt(r,e.agentId,h)}if(r.agents.get(e.agentId)?.taskIndex==null)return J(r,e.agentId,u=>({...u,phase:"done",contentBuffer:""}));let o=r.nextTimelineId,s=J(r,e.agentId,u=>ht({...u,phase:"done",contentBuffer:""},{kind:"report",id:o,body:e.result,tokenCount:u.tokenCount})),i=s.agents.get(e.agentId),a=s.researchAgentIds.includes(e.agentId),p=a&&i?[...s.scrollback,{key:`agent-${e.agentId}-${s.scrollback.length}`,kind:"agent",agent:i}]:s.scrollback,l=a?s.researchAgentIds.filter(u=>u!==e.agentId):s.researchAgentIds;return{...s,nextTimelineId:r.nextTimelineId+1,scrollback:p,researchAgentIds:l}}case"agent:done":{let n=t.agents.get(e.agentId);if(!n)return t;let r=t;if(n.currentThinkId!==null){let o=n.timeline.find(i=>i.id===n.currentThinkId),s=o&&o.kind==="think"?o.body:"";r=pt(r,e.agentId,s)}return J(r,e.agentId,o=>({...o,phase:"idle"}))}case"agent:tick":return{...t,pressure:{pct:e.nCtx>0?Math.round(100*e.cellsUsed/e.nCtx):0,cellsUsed:e.cellsUsed,nCtx:e.nCtx}};default:return t}}var Gn,Xn=E(()=>{"use strict";Nt();Gn="</think>"});import{useEffect as Vo,useReducer as Jo}from"react";function Zn(t,e=[]){let[n,r]=Jo(Ft,e,o=>o.reduce(Ft,ut));return Vo(()=>t.subscribe(r),[t]),n}var er=E(()=>{"use strict";Nt();Xn()});import{createContext as Xo,useContext as Zo}from"react";function mt(){return Zo(Ut)}var es,Ut,ft=E(()=>{"use strict";es=()=>{},Ut=Xo(es)});import{memo as ts}from"react";import{Box as ns,Text as tr}from"ink";import{jsx as nr,jsxs as rs}from"react/jsx-runtime";var rr,or=E(()=>{"use strict";rr=ts(function({query:e,warm:n}){return e?rs(ns,{flexDirection:"column",marginBottom:1,children:[nr(tr,{bold:!0,children:e}),n?nr(tr,{dimColor:!0,children:"follow-up \xB7 warm session"}):null]}):null})});function gt(t){let e=Number.parseInt(t.slice(1),10);return!Number.isFinite(e)||e<0?$t[0]:$t[e%$t.length]}var $t,Wt=E(()=>{"use strict";$t=["cyan","yellow","green","magenta","red","blue"]});import{memo as Oe}from"react";import{Box as _,Text as A}from"ink";import{jsx as T,jsxs as D}from"react/jsx-runtime";function ss(t){return os.includes(t.phase)}function is(t){let e=t.indexOf(`
|
|
4
|
+
`);if(e<=0)return"Thinking\u2026";let n=t.slice(0,e).trim();return n?n.length>72?n.slice(0,72).trimEnd()+"\u2026":n:"Thinking\u2026"}function sr(t){let e=t.indexOf(`
|
|
5
|
+
`);return e<=0?"":t.slice(e+1).trimStart()}var os,zt,Ht,Yt,jt,as,ls,yt,Kt=E(()=>{"use strict";Wt();os=["thinking","content","tool"];zt=Oe(function({item:e,color:n}){let r=e.live?e.body.includes(`
|
|
6
|
+
`)?is(e.body):"Thinking\u2026":e.title,o=e.live?sr(e.body):sr(e.body).trim();return D(_,{flexDirection:"column",marginBottom:1,flexShrink:0,children:[D(_,{children:[T(A,{color:n,children:"\u2726 "}),T(A,{bold:!0,children:r})]}),o?T(_,{paddingLeft:2,children:D(A,{children:[o,e.live?"\u258E":""]})}):e.live?T(_,{paddingLeft:2,children:T(A,{dimColor:!0,children:"\u258E"})}):null]})});Ht=Oe(function({item:e}){return D(_,{flexShrink:0,children:[T(A,{dimColor:!0,children:"\u203A "}),T(A,{color:"cyan",children:e.tool}),e.argsSummary?D(A,{dimColor:!0,children:[" ",e.argsSummary]}):null]})}),Yt=Oe(function({item:e}){let n=e.hosts.length>0?e.hosts.join(" \xB7 "):null;return D(_,{flexDirection:"column",flexShrink:0,children:[D(_,{paddingLeft:2,children:[T(A,{color:"green",children:"\u2713 "}),T(A,{children:e.resultCount??e.byteLength+"b"}),typeof e.resultCount=="number"?T(A,{children:" results"}):null]}),n?T(_,{paddingLeft:4,children:T(A,{dimColor:!0,children:n})}):e.preview?T(_,{paddingLeft:4,children:T(A,{dimColor:!0,children:e.preview.length>60?e.preview.slice(0,60)+"\u2026":e.preview})}):null]})}),jt=Oe(function({item:e,color:n}){let r=e.body.trim();return D(_,{flexDirection:"column",marginTop:1,flexShrink:0,children:[D(_,{children:[T(A,{color:n,children:"\u2713 "}),T(A,{bold:!0,children:"report"}),D(A,{dimColor:!0,children:[" \xB7 ",e.tokenCount," tok"]})]}),r?T(_,{paddingLeft:2,children:T(A,{children:r})}):null]})}),as=Oe(function({buffer:e,color:n}){return D(_,{flexDirection:"column",marginTop:1,flexShrink:0,children:[D(_,{children:[T(A,{color:n,children:"\u25B8 "}),T(A,{dimColor:!0,bold:!0,children:"streaming"})]}),T(_,{paddingLeft:2,children:D(A,{dimColor:!0,children:[e,"\u258E"]})})]})}),ls=3,yt=Oe(function({agent:e,headerPrefix:n,bodyHeight:r,width:o}){let s=gt(e.label),i=ss(e),a=e.taskDescription?e.taskDescription.length>80?e.taskDescription.slice(0,80)+"\u2026":e.taskDescription:null,p=r+ls+2;return D(_,{flexDirection:"column",width:o,height:p,borderStyle:"round",borderColor:i?s:"gray",paddingX:1,marginRight:1,flexShrink:0,overflow:"hidden",children:[D(_,{flexShrink:0,children:[n?D(A,{dimColor:!0,children:[n," \xB7 "]}):null,T(A,{color:s,bold:!0,children:e.label}),T(_,{flexGrow:1}),T(A,{color:i?s:"green",children:i?"\u25CF":"\u2713"})]}),a?T(A,{dimColor:!0,children:a}):null,e.dependencyHint?D(A,{dimColor:!0,children:["\u2191 ",e.dependencyHint]}):null,D(_,{flexDirection:"column",flexGrow:1,justifyContent:"flex-end",overflow:"hidden",children:[e.timeline.map(l=>l.kind==="think"?T(zt,{item:l,color:s},l.id):l.kind==="tool_call"?T(Ht,{item:l},l.id):l.kind==="tool_result"?T(Yt,{item:l},l.id):l.kind==="report"?T(jt,{item:l,color:s},l.id):null),e.contentBuffer?T(as,{buffer:e.contentBuffer,color:s}):null]})]})})});import{Box as bt,Text as xt}from"ink";import{jsx as pe,jsxs as Gt}from"react/jsx-runtime";function ir({agent:t}){let e=gt(t.label),n=t.taskDescription?t.taskDescription.length>80?t.taskDescription.slice(0,80)+"\u2026":t.taskDescription:null;return Gt(bt,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:1,marginBottom:1,children:[Gt(bt,{flexShrink:0,children:[pe(xt,{color:e,bold:!0,children:t.label}),pe(bt,{flexGrow:1}),pe(xt,{color:"green",children:"\u2713"})]}),n?pe(xt,{dimColor:!0,children:n}):null,t.dependencyHint?Gt(xt,{dimColor:!0,children:["\u2191 ",t.dependencyHint]}):null,pe(bt,{flexDirection:"column",children:t.timeline.map(r=>r.kind==="think"?pe(zt,{item:r,color:e},r.id):r.kind==="tool_call"?pe(Ht,{item:r},r.id):r.kind==="tool_result"?pe(Yt,{item:r},r.id):r.kind==="report"?pe(jt,{item:r,color:e},r.id):null)})]})}var ar=E(()=>{"use strict";Wt();Kt()});import{useEffect as cs,useState as us}from"react";import{useStdout as ds}from"ink";function lr(){let{stdout:t}=ds(),[e,n]=us(()=>[t?.columns??120,t?.rows??40]);return cs(()=>{if(!t)return;let r=()=>{n([t.columns??120,t.rows??40])};return t.on("resize",r),()=>{t.off("resize",r)}},[t]),e}function cr(t){let e=Math.floor(t/1e3),n=Math.floor(e/60),r=e%60;return`${String(n).padStart(2,"0")}:${String(r).padStart(2,"0")}`}var Qt=E(()=>{"use strict"});import{Box as Vt}from"ink";import{jsx as Be}from"react/jsx-runtime";function dr({state:t}){let[e,n]=lr(),r=t.researchAgentIds.map(i=>t.agents.get(i)).filter(i=>!!i);if(r.length===0)return null;let o=Math.max(Jt,n-ps);if(t.mode==="flat"){let i=r.length,a=Math.max(ur*i,e-4),p=Math.max(ur,Math.floor(a/i)-1);return p*i+i<=e?Be(Vt,{flexDirection:"row",marginBottom:1,children:r.map(u=>Be(yt,{agent:u,headerPrefix:null,bodyHeight:o,width:p},u.id))}):Be(Vt,{flexDirection:"column",marginBottom:1,children:r.map(u=>Be(yt,{agent:u,headerPrefix:null,bodyHeight:Math.max(Jt,Math.floor(o/i))},u.id))})}let s=Math.max(Jt,Math.floor(o/Math.max(1,r.length)));return Be(Vt,{flexDirection:"column",marginBottom:1,children:r.map(i=>Be(yt,{agent:i,headerPrefix:`Task ${(i.taskIndex??0)+1}`,bodyHeight:s},i.id))})}var ps,ur,Jt,pr=E(()=>{"use strict";Kt();Qt();ps=18,ur=26,Jt=10});import{Box as Ye,Text as ve}from"ink";import{jsx as Ce,jsxs as je}from"react/jsx-runtime";function hr({state:t}){let{synth:e}=t;if(!e.open&&!e.done)return null;let n=e.done?je(Ye,{children:[Ce(ve,{bold:!0,children:"Synthesis "}),Ce(ve,{color:"green",children:"\u2713"}),e.stats?je(ve,{dimColor:!0,children:[" ","\xB7 ",e.stats.tokens," tok \xB7 ",e.stats.toolCalls," tools \xB7"," ",Number.isFinite(e.stats.ppl)?`ppl ${e.stats.ppl.toFixed(2)} \xB7 `:"",hs(e.stats.timeMs)]}):null]}):je(Ye,{children:[Ce(ve,{bold:!0,children:"Synthesis"}),Ce(ve,{color:"cyan",children:" \u25CF"})]}),r=e.buffer.trim();return je(Ye,{flexDirection:"column",marginBottom:1,children:[n,e.open&&r?Ce(Ye,{paddingLeft:2,marginTop:0,children:je(ve,{children:[r,"\u258E"]})}):e.open?Ce(Ye,{paddingLeft:2,children:Ce(ve,{dimColor:!0,children:"\u258E"})}):null]})}var hs,mr=E(()=>{"use strict";hs=t=>`${(t/1e3).toFixed(1)}s`});var ae,kt=E(()=>{"use strict";ae=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"]});import{useEffect as ms,useState as fs}from"react";import{Box as fr,Text as De}from"ink";import{jsx as Xt,jsxs as Ke}from"react/jsx-runtime";function gr({state:t}){let{verify:e}=t,[n,r]=fs(0);return ms(()=>{if(!e.active)return;let o=setInterval(()=>r(s=>(s+1)%ae.length),80);return()=>clearInterval(o)},[e.active]),!e.active&&!e.done?null:e.active?Ke(fr,{marginBottom:1,children:[Ke(De,{color:"cyan",children:[ae[n]," "]}),Xt(De,{dimColor:!0,children:"Verifying "}),Ke(De,{children:[e.count," samples\u2026"]})]}):Ke(fr,{marginBottom:1,children:[Xt(De,{bold:!0,children:"Verify "}),Xt(De,{color:"green",children:"\u2713"}),Ke(De,{dimColor:!0,children:[" ","\xB7 ",e.count," samples",e.timeMs!=null?` \xB7 ${gs(e.timeMs)}`:""]})]})}var gs,yr=E(()=>{"use strict";kt();gs=t=>`${(t/1e3).toFixed(1)}s`});import{Box as ys,Text as qe}from"ink";import{jsx as Qe,jsxs as br}from"react/jsx-runtime";function xr({state:t}){let e=t.evalState;if(!e||!e.done)return null;let n=e.converged===!0?Qe(qe,{color:"green",children:"yes"}):e.converged===!1?Qe(qe,{color:"red",children:"no"}):Qe(qe,{color:"yellow",children:"unknown"});return br(ys,{marginBottom:1,children:[Qe(qe,{bold:!0,children:"Eval "}),Qe(qe,{children:"Converged: "}),n,br(qe,{dimColor:!0,children:[" ","\xB7 ",e.sampleCount," samples \xB7 ",e.tokenCount," tok \xB7 ",bs(e.timeMs)]})]})}var bs,kr=E(()=>{"use strict";bs=t=>`${(t/1e3).toFixed(1)}s`});import{Box as wr,Text as Tr}from"ink";import{jsx as Zt,jsxs as xs}from"react/jsx-runtime";function vr({state:t}){return!t.answer||t.synth.done&&t.synth.buffer.trim().length>0?null:xs(wr,{flexDirection:"column",marginBottom:1,children:[Zt(Tr,{dimColor:!0,children:"\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"}),Zt(wr,{marginTop:1,paddingLeft:2,children:Zt(Tr,{children:t.answer.trim()})})]})}var Cr=E(()=>{"use strict"});import{useEffect as ks,useState as ws}from"react";import{Box as Sr,Text as ee}from"ink";import{Fragment as Rs,jsx as le,jsxs as Ve}from"react/jsx-runtime";function Ts(t,e=12){let n=Math.min(e,Math.max(0,Math.round(t/100*e)));return"\u2588".repeat(n)+"\u2591".repeat(e-n)}function vs(t){return t>=90?"red":t>=70?"yellow":"green"}function Cs(t){let e=0;for(let n of t.agents.values())n.phase!=="done"&&n.phase!=="idle"&&e++;return e}function Ss(t){let e=t.pipelineResumedAt,[,n]=ws(0);return ks(()=>{if(e===null)return;let r=setInterval(()=>n(o=>o+1),250);return()=>clearInterval(r)},[e]),e===null?t.pipelineElapsedMs:t.pipelineElapsedMs+(Date.now()-e)}function Rr({state:t}){let e=Ss(t),n=t.pressure?.pct??0,r=Cs(t),o=vs(n);return le(Sr,{borderStyle:"single",borderColor:"gray",borderTop:!0,borderBottom:!1,borderLeft:!1,borderRight:!1,paddingTop:0,children:Ve(Sr,{flexDirection:"row",children:[le(ee,{dimColor:!0,children:"KV "}),le(ee,{color:o,children:Ts(n)}),Ve(ee,{children:[" ",String(n).padStart(2," "),"%"]}),le(ee,{dimColor:!0,children:" \xB7 "}),le(ee,{children:t.phase}),le(ee,{dimColor:!0,children:" \xB7 \u23F1 "}),le(ee,{children:cr(e)}),le(ee,{dimColor:!0,children:" \xB7 "}),Ve(ee,{children:[r," active"]}),t.sourceCount>0?Ve(Rs,{children:[le(ee,{dimColor:!0,children:" \xB7 "}),le(ee,{dimColor:!0,children:"\u2315 "}),Ve(ee,{children:[t.sourceCount," sources"]})]}):null]})})}var Er=E(()=>{"use strict";Qt()});import{useState as Es}from"react";import{Text as Ne,useInput as As}from"ink";import{jsx as wt,jsxs as Pr}from"react/jsx-runtime";function Se({value:t,onChange:e,onSubmit:n,onCancel:r,placeholder:o="",focused:s=!0,mask:i=!1,color:a}){let[p,l]=Es(t.length),u=Math.min(p,t.length);As((R,g)=>{if(g.return){n?.(t);return}if(g.escape){r?.();return}if(g.leftArrow){g.meta||g.ctrl?l(Ar(t,u)):l(Math.max(0,u-1));return}if(g.rightArrow){g.meta||g.ctrl?l(Ps(t,u)):l(Math.min(t.length,u+1));return}if(R==="\x1B[H"||R==="\x1BOH"){l(0);return}if(R==="\x1B[F"||R==="\x1BOF"){l(t.length);return}if(g.backspace||g.delete){if(u===0)return;if(g.meta||g.ctrl){let L=Ar(t,u);e(t.slice(0,L)+t.slice(u)),l(L);return}let Q=t.slice(0,u-1)+t.slice(u);l(u-1),e(Q);return}if(g.ctrl&&R==="a"){l(0);return}if(g.ctrl&&R==="e"){l(t.length);return}if(g.ctrl&&R==="u"){e(t.slice(u)),l(0);return}if(g.ctrl&&R==="k"){e(t.slice(0,u));return}if(g.ctrl&&R==="w"){let Q=t.slice(0,u),L=/\S+\s*$/.exec(Q),Y=L?L.index:0;e(t.slice(0,Y)+t.slice(u)),l(Y);return}if(!(g.ctrl||g.meta||g.tab||g.upArrow||g.downArrow)&&R.length>0){let Q=t.slice(0,u)+R+t.slice(u);l(u+R.length),e(Q)}},{isActive:s});let h=i?"*".repeat(t.length):t;if(t.length===0)return Pr(Ne,{children:[wt(Ne,{color:a,children:s?"\u258E":""}),wt(Ne,{dimColor:!0,children:o})]});if(!s)return wt(Ne,{color:a,children:h});let k=h.slice(0,u),M=h.slice(u,u+1),H=h.slice(u+1);return Pr(Ne,{color:a,children:[k,wt(Ne,{inverse:!0,children:M||" "}),H]})}function Ar(t,e){if(e<=0)return 0;let n=e;for(;n>0&&/\s/.test(t[n-1]);)n--;for(;n>0&&!/\s/.test(t[n-1]);)n--;return n}function Ps(t,e){let n=t.length;if(e>=n)return n;let r=e;for(;r<n&&/\s/.test(t[r]);)r++;for(;r<n&&!/\s/.test(t[r]);)r++;return r}var Ir=E(()=>{"use strict"});import{memo as Xe,useEffect as Mr,useState as Je}from"react";import{Box as X,Text as S,useInput as Is}from"ink";import{jsx as y,jsxs as F}from"react/jsx-runtime";function _r(t){if(!t.startsWith("/"))return null;let e=t.slice(1).trimStart();if(!e)return{name:"",value:""};let n=e.search(/\s/),r=n===-1?e:e.slice(0,n),o=n===-1?"":e.slice(n+1).trim();return{name:r,value:o}}function Ms(t){if(!t)return[];if(!t.name)return Tt;let e=t.name.toLowerCase();return Tt.filter(n=>n.name.startsWith(e))}var Tt,Br,Or,_s,en,Os,Dr=E(()=>{"use strict";ft();Ir();Tt=[{name:"scan",desc:"Set local file source (path or glob)",kind:"value"},{name:"web",desc:"Set web search key",kind:"value"},{name:"model",desc:"Set local LLM .gguf path",kind:"value"},{name:"reranker",desc:"Set local reranker .gguf path",kind:"value"},{name:"output",desc:"Set output directory",kind:"value"},{name:"deep",desc:"Use deep (chain) reasoning",kind:"instant"},{name:"fast",desc:"Use fast (parallel) reasoning",kind:"instant"},{name:"help",desc:"Show this list",kind:"instant"},{name:"quit",desc:"Quit",kind:"instant"}];Br=Xe(function({state:e}){let n=mt(),r=e.config?.defaults.reasoningMode??"deep",[o,s]=Je(r),[i,a]=Je("query"),[p,l]=Je(""),[u,h]=Je(""),[x,k]=Je(!1);Mr(()=>{e.composerPrefill&&e.composerPrefill!==p&&l(e.composerPrefill)},[e.composerPrefill]),Mr(()=>{s(r)},[r]);let M=e.configOrigin?.tavilyKey??"unset",H=e.configOrigin?.corpusPath??"unset",R=e.configOrigin?.outputDir??"default",g=M!=="unset",L=g||H!=="unset",Y=M==="env",V=e.clarifyContext!==null,Z=_r(p),te=Z!==null,ie=Ms(Z);Is((d,f)=>{if(f.ctrl&&d==="c"){n({type:"quit"});return}if(f.tab){if(te&&Z&&Z.name&&ie.length===1){let w=ie[0];l("/"+w.name+(w.kind==="value"?" ":""));return}te||s(w=>w==="deep"?"flat":"deep");return}if(f.escape){if(V){n({type:"cancel_plan"}),l("");return}l(""),k(!1);return}},{isActive:i==="query"});let W=d=>{let f=d.trim();if(f){if(!V){let w=_r(f);if(w){C(w);return}}if(V){n({type:"submit_clarification",answer:f}),l("");return}L&&(n({type:"submit_query",query:f,mode:o}),l(""))}},C=({name:d,value:f})=>{if(!d)return;let w=Tt.find(rt=>rt.name===d);if(w){if(l(""),k(!1),w.kind==="instant"){d==="deep"?s("deep"):d==="fast"?s("flat"):d==="quit"?n({type:"quit"}):d==="help"&&k(!0);return}if(f){d==="web"?n({type:"set_tavily_key",key:f}):d==="scan"?n({type:"set_corpus_path",path:f}):d==="output"?n({type:"set_output_dir",path:f}):d==="model"?n({type:"set_model_path",path:f}):d==="reranker"&&n({type:"set_reranker_path",path:f});return}if(d==="web"){if(Y)return;h(e.config?.sources.tavilyKey??""),a("web")}else d==="scan"?(h(e.config?.sources.corpusPath??""),a("scan")):d==="output"?(h(e.config?.sources.outputDir??""),a("output")):d==="model"?(h(e.config?.model.path??""),a("model")):d==="reranker"&&(h(e.config?.model.reranker??""),a("reranker"))}};return F(X,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:1,children:[i==="query"?F(X,{children:[y(S,{children:"\u203A "}),y(Se,{value:p,onChange:l,onSubmit:W,focused:!0,placeholder:V?"Answer the questions above, or Esc to cancel\u2026":L?"Ask a research question, or / for commands\u2026":"Type / for commands (e.g. /web, /scan) to add a source"})]}):i==="web"?F(X,{children:[y(S,{color:"yellow",children:"Web search key \u203A "}),y(Se,{value:u,onChange:h,onSubmit:()=>{n({type:"set_tavily_key",key:u.trim()}),a("query"),h("")},onCancel:()=>{a("query"),h("")},focused:!0,mask:!0,placeholder:"tvly-..."})]}):i==="scan"?F(X,{children:[y(S,{color:"yellow",children:"Scan path \u203A "}),y(Se,{value:u,onChange:h,onSubmit:()=>{n({type:"set_corpus_path",path:u.trim()}),a("query"),h("")},onCancel:()=>{a("query"),h("")},focused:!0,placeholder:"/path/to/docs or /path/**/*.md"})]}):i==="output"?F(X,{children:[y(S,{color:"yellow",children:"Output dir \u203A "}),y(Se,{value:u,onChange:h,onSubmit:()=>{n({type:"set_output_dir",path:u.trim()}),a("query"),h("")},onCancel:()=>{a("query"),h("")},focused:!0,placeholder:`${process.cwd()} (default)`})]}):i==="model"?F(X,{children:[y(S,{color:"yellow",children:"Model path \u203A "}),y(Se,{value:u,onChange:h,onSubmit:()=>{n({type:"set_model_path",path:u.trim()}),a("query"),h("")},onCancel:()=>{a("query"),h("")},focused:!0,placeholder:"/path/to/qwen3.5-4b.gguf"})]}):F(X,{children:[y(S,{color:"yellow",children:"Reranker path \u203A "}),y(Se,{value:u,onChange:h,onSubmit:()=>{n({type:"set_reranker_path",path:u.trim()}),a("query"),h("")},onCancel:()=>{a("query"),h("")},focused:!0,placeholder:"/path/to/qwen3-reranker.gguf"})]}),i==="query"&&!V&&te?y(X,{flexDirection:"column",marginTop:0,children:ie.length===0?y(S,{color:"red",children:"no matching command"}):ie.map(d=>y(Or,{cmd:d},d.name))}):null,i==="query"&&!te&&x?y(X,{flexDirection:"column",marginTop:0,children:Tt.map(d=>y(Or,{cmd:d},d.name))}):null,F(X,{marginTop:0,children:[y(_s,{mode:o}),y(S,{children:" "}),y(en,{label:"Web",origin:M,value:g?"set":null,disabled:Y}),y(S,{children:" "}),y(en,{label:"Scan",origin:H,value:e.config?.sources.corpusPath?e.corpusStatus?`${e.corpusStatus.fileCount} files`:e.config.sources.corpusPath:null}),y(S,{children:" "}),y(en,{label:"Output",origin:R,value:e.config?.sources.outputDir??null}),y(X,{flexGrow:1}),y(Os,{field:i,hasSource:L,inSlash:te,clarifying:V})]}),e.toast?y(X,{marginTop:0,children:y(S,{color:e.toast.tone==="error"?"red":e.toast.tone==="warn"?"yellow":"green",children:e.toast.message})}):null]})}),Or=Xe(function({cmd:e}){return F(X,{children:[F(S,{color:"cyan",children:["/",e.name]}),F(S,{dimColor:!0,children:[" \xB7 ",e.desc]}),e.kind==="value"?y(S,{dimColor:!0,children:" <value>"}):null]})}),_s=Xe(function({mode:e}){return F(S,{children:[F(S,{color:e==="deep"?"cyan":void 0,bold:e==="deep",children:[e==="deep"?"\u25C6":"\u25CB"," Deep"]}),y(S,{dimColor:!0,children:" "}),F(S,{color:e==="flat"?"cyan":void 0,bold:e==="flat",children:[e==="flat"?"\u25C6":"\u25CB"," Fast"]})]})}),en=Xe(function({label:e,origin:n,value:r,disabled:o=!1}){let s=n!=="unset";return F(S,{children:[F(S,{color:s?"green":"gray",dimColor:o,children:[e," ",s?e==="Scan"&&r?r:"\u2713":"\u2014"]}),y(S,{dimColor:!0,children:n==="env"?" (env)":n==="cli"?" (cli)":""})]})}),Os=Xe(function({field:e,hasSource:n,inSlash:r,clarifying:o}){return e==="web"||e==="scan"||e==="output"||e==="model"||e==="reranker"?y(S,{dimColor:!0,children:"\u23CE save (empty to clear) \xB7 Ctrl+U clear \xB7 Esc cancel"}):o?y(S,{color:"yellow",children:"\u23CE submit answer \xB7 Esc cancel"}):r?y(S,{dimColor:!0,children:"Tab complete \xB7 \u23CE run \xB7 Esc clear"}):n?y(S,{dimColor:!0,children:"Tab toggle mode \xB7 / commands \xB7 \u23CE submit"}):y(S,{color:"yellow",children:"\u26A0 Add a source via /web or /scan"})})});import{memo as Bs,useEffect as Ds,useState as qs}from"react";import{Box as se,Text as O,useInput as Ns}from"ink";import{jsx as U,jsxs as K}from"react/jsx-runtime";var qr,Nr=E(()=>{"use strict";ft();qr=Bs(function({state:e}){let n=mt(),r=e.plan,[o,s]=qs(e.mode??"deep");if(Ds(()=>{e.mode&&e.mode!==o&&s(e.mode)},[e.mode]),Ns((a,p)=>{if(r){if(p.return){if(r.intent==="clarify"){n({type:"edit_plan",query:e.query});return}n({type:"accept_plan"});return}if(p.escape){n({type:"cancel_plan"});return}if(a==="e"||a==="E"){n({type:"edit_plan",query:e.query});return}if(a==="t"||a==="T"){let l=o==="deep"?"flat":"deep";s(l),n({type:"change_mode",mode:l});return}p.ctrl&&a==="c"&&n({type:"quit"})}}),!r)return null;if(r.intent==="clarify")return K(se,{flexDirection:"column",marginBottom:1,children:[U(se,{marginBottom:1,children:U(O,{bold:!0,children:e.query})}),U(O,{dimColor:!0,children:"A few questions to narrow this down."}),U(se,{flexDirection:"column",borderStyle:"round",borderColor:"yellow",paddingX:1,marginTop:1,children:r.clarifyQuestions.map((a,p)=>K(O,{children:[K(O,{dimColor:!0,children:["(",p+1,")"]})," ",a]},p))}),U(se,{marginTop:1,children:U(O,{dimColor:!0,children:"\u23CE answer \xB7 Esc cancel"})})]});if(r.intent==="passthrough")return K(se,{flexDirection:"column",marginBottom:1,children:[U(O,{bold:!0,children:e.query}),U(O,{dimColor:!0,children:"Answering directly \u2014 no research needed."})]});let i=o==="flat"?`${r.tasks.length} parallel tasks`:`${r.tasks.length} chained tasks`;return K(se,{flexDirection:"column",marginBottom:1,children:[U(se,{marginBottom:1,children:U(O,{bold:!0,children:e.query})}),U(O,{dimColor:!0,children:"Here's my plan."}),K(se,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:1,marginTop:1,children:[K(se,{children:[U(O,{bold:!0,children:"Research"}),K(O,{dimColor:!0,children:[" \xB7 ",i]})]}),r.tasks.map((a,p)=>K(O,{children:[K(O,{dimColor:!0,children:[" (",p+1,")"]})," ",a.description]},p))]}),K(se,{marginTop:1,children:[K(O,{color:o==="deep"?"cyan":void 0,bold:o==="deep",children:[o==="deep"?"\u25C6":"\u25CB"," Deep"]}),U(O,{children:" "}),K(O,{color:o==="flat"?"cyan":void 0,bold:o==="flat",children:[o==="flat"?"\u25C6":"\u25CB"," Fast"]}),U(O,{dimColor:!0,children:" (T to toggle \u2014 re-plans)"})]}),K(se,{marginTop:1,children:[U(O,{dimColor:!0,children:"[E] Edit plan \xB7 [Esc] Cancel \xB7 "}),U(O,{color:"cyan",bold:!0,children:"[\u23CE] Start research"})]})]})})});import{memo as Ls,useEffect as Fs,useState as Us}from"react";import{Box as Lr,Text as tn}from"ink";import{jsx as Fr,jsxs as nn}from"react/jsx-runtime";var Ur,$r=E(()=>{"use strict";kt();Ur=Ls(function({state:e}){let[n,r]=Us(0);return Fs(()=>{let o=setInterval(()=>r(s=>(s+1)%ae.length),80);return()=>clearInterval(o)},[]),nn(Lr,{flexDirection:"column",marginBottom:1,children:[Fr(tn,{bold:!0,children:e.query}),nn(Lr,{marginTop:1,children:[nn(tn,{color:"cyan",children:[ae[n]," "]}),Fr(tn,{dimColor:!0,children:"Planning\u2026"})]})]})})});import{memo as $s}from"react";import{Box as Wr,Text as vt}from"ink";import{jsx as rn,jsxs as on}from"react/jsx-runtime";var zr,Hr=E(()=>{"use strict";zr=$s(function({state:e}){if(!e.clarifyContext)return null;let{originalQuery:n,questions:r}=e.clarifyContext;return on(Wr,{flexDirection:"column",marginBottom:1,children:[rn(vt,{bold:!0,children:n}),rn(vt,{dimColor:!0,children:"A few questions to narrow this down."}),rn(Wr,{flexDirection:"column",borderStyle:"round",borderColor:"yellow",paddingX:1,marginTop:1,children:r.map((o,s)=>on(vt,{children:[on(vt,{dimColor:!0,children:["(",s+1,")"]})," ",o]},s))})]})})});import{memo as Yr,useEffect as Ws,useState as zs}from"react";import{Box as Re,Text as I}from"ink";import{Fragment as js,jsx as G,jsxs as $}from"react/jsx-runtime";function Ys(t){try{return new URL(t).host}catch{return null}}function Ct(t){return t>=1e9?(t/1e9).toFixed(1)+" GB":t>=1e6?(t/1e6).toFixed(0)+" MB":t>=1e3?(t/1e3).toFixed(0)+" KB":`${t} B`}var jr,Hs,Kr=E(()=>{"use strict";kt();jr=Yr(function({state:e}){let[n,r]=zs(0);if(Ws(()=>{let o=setInterval(()=>r(s=>(s+1)%ae.length),80);return()=>clearInterval(o)},[]),e.uiPhase==="boot_error"){let o=e.bootError,s=o?.kind??"llm",i=s==="llm"?"LLM":"reranker",a=s==="llm"?"/model":"/reranker",p=s==="llm"?"/reranker":"/model";return $(Re,{flexDirection:"column",marginBottom:1,children:[$(I,{color:"red",bold:!0,children:["\u2717 Boot failed (",i,")"]}),G(Re,{paddingLeft:2,children:G(I,{children:o?.message??"Unknown error"})}),G(Re,{paddingLeft:2,marginTop:1,children:$(I,{dimColor:!0,children:["Type ",$(I,{color:"cyan",children:[a," "]}),G(I,{dimColor:!0,children:"<path-to-gguf>"}),$(I,{dimColor:!0,children:[" to use a local ",i,", or "]}),G(I,{color:"cyan",children:p}),G(I,{dimColor:!0,children:" for the other, or "}),G(I,{color:"cyan",children:"/quit"}),G(I,{dimColor:!0,children:" to exit."})]})})]})}return e.uiPhase==="downloading"?$(Re,{flexDirection:"column",marginBottom:1,children:[$(Re,{children:[$(I,{color:"cyan",children:[ae[n]," "]}),G(I,{bold:!0,children:"Downloading models"})]}),e.downloads.map(o=>G(Hs,{item:o},o.id))]}):$(Re,{marginBottom:1,children:[$(I,{color:"cyan",children:[ae[n]," "]}),G(I,{bold:!0,children:e.loadingLabel??"Loading\u2026"})]})}),Hs=Yr(function({item:e}){let n=e.total>0?Math.min(100,Math.floor(e.got/e.total*100)):0,r=16,o=Math.floor(n/100*r),s="\u2588".repeat(o)+"\u2591".repeat(r-o),i=e.url?Ys(e.url):null,a=e.started&&i!==null,p=e.done?"\u2713 ":a?"\u25CF ":"\u25CB ",l=e.done?"green":a?"cyan":void 0,u=!a&&!e.done;return $(Re,{paddingLeft:2,children:[G(I,{color:l,dimColor:u,children:p}),$(I,{dimColor:u,children:[e.label.padEnd(28)," "]}),e.done?G(I,{dimColor:!0,children:Ct(e.got)}):a?$(js,{children:[G(I,{color:"cyan",children:s}),$(I,{children:[" ",String(n).padStart(2),"% \xB7 ",Ct(e.got)," / ",Ct(e.total)]}),$(I,{dimColor:!0,children:[" \xB7 ",i]})]}):$(I,{dimColor:!0,children:["queued \xB7 ",Ct(e.total)]})]})})});import{Box as St,Static as Ks,Text as Gr}from"ink";import{jsx as q,jsxs as sn}from"react/jsx-runtime";function Qr({bus:t,dispatch:e,bootstrap:n}){let r=Zn(t,n),o=r.uiPhase!=="composer"&&r.uiPhase!=="boot"&&r.uiPhase!=="downloading"&&r.uiPhase!=="loading"&&r.uiPhase!=="planning"&&r.uiPhase!=="plan_review"&&r.uiPhase!=="clarifying",s=r.uiPhase==="research"||r.uiPhase==="done",i=r.uiPhase==="composer"||r.uiPhase==="done"||r.uiPhase==="clarifying"||r.uiPhase==="boot_error";return sn(Ut.Provider,{value:e,children:[q(Ks,{items:r.scrollback,children:a=>a.kind==="agent"?q(St,{paddingX:2,children:q(ir,{agent:a.agent})},a.key):sn(St,{flexDirection:"column",paddingX:2,marginBottom:1,children:[q(Gr,{dimColor:!0,children:"\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"}),q(St,{paddingLeft:2,marginTop:1,children:q(Gr,{children:a.body})})]},a.key)}),sn(St,{flexDirection:"column",paddingX:2,paddingY:1,children:[o&&q(rr,{query:r.query,warm:r.warm}),(r.uiPhase==="downloading"||r.uiPhase==="loading"||r.uiPhase==="boot_error")&&q(jr,{state:r}),r.uiPhase==="planning"&&q(Ur,{state:r}),r.uiPhase==="plan_review"&&q(qr,{state:r}),r.uiPhase==="clarifying"&&q(zr,{state:r}),s&&q(dr,{state:r}),s&&q(hr,{state:r}),r.uiPhase==="done"&&q(gr,{state:r}),r.uiPhase==="done"&&q(xr,{state:r}),r.uiPhase==="done"&&q(vr,{state:r}),i&&q(Br,{state:r}),q(Rr,{state:r})]})]})}var Vr=E(()=>{"use strict";er();ft();or();ar();pr();mr();yr();kr();Cr();Er();Dr();Nr();$r();Hr();Kr()});var Jr={};lo(Jr,{render:()=>Vs});import Gs from"react";import{render as Qs}from"ink";function Vs(t,e,n=[]){return Qs(Gs.createElement(Qr,{bus:t,dispatch:e,bootstrap:n}),{incrementalRendering:!0})}var Xr=E(()=>{"use strict";Vr()});import*as N from"node:fs";import*as ue from"node:path";import{parseArgs as Js}from"node:util";import{main as Xs,ensure as an,createSignal as Zs,spawn as ei,each as Ee,call as Le}from"effection";import{createContext as ti}from"@lloyal-labs/lloyal.node";import{initAgents as ni,JsonlTraceWriter as ri}from"@lloyal-labs/lloyal-agents";var Rt=!1,co=!1;function bn(t){Rt=t}function xn(t){co=t}var Et=!!process.stdout.isTTY,At=Et?{bold:"\x1B[1m",dim:"\x1B[2m",reset:"\x1B[0m",green:"\x1B[32m",cyan:"\x1B[36m",yellow:"\x1B[33m",red:"\x1B[31m"}:{bold:"",dim:"",reset:"",green:"",cyan:"",yellow:"",red:""},yn="";function uo(){yn&&(yn="",process.stdout.write("\r\x1B[K"))}var st=(...t)=>{Rt||(uo(),console.log(...t))};function kn(t,e){Rt&&console.log(JSON.stringify({event:t,...e}))}import*as j from"node:fs";import*as z from"node:path";import*as Pt from"node:os";import*as it from"node:path";function fe(t){if(!t)return"";let e=t==="~"?Pt.homedir():t.startsWith("~/")?it.join(Pt.homedir(),t.slice(2)):t;return it.resolve(e)}function It(){return{version:1,sources:{},defaults:{reasoningMode:"deep",verifyCount:3,maxTurns:10},model:{}}}function Tn(t){try{let e=j.readFileSync(t,"utf8"),n=JSON.parse(e);if(n.version!==1)return null;let r=It();return{version:1,sources:{...r.sources,...n.sources??{}},defaults:{...r.defaults,...n.defaults??{}},model:{...r.model,...n.model??{}}}}catch{return null}}function Pe(t,e,n=process.env){let r=z.resolve(t),o=Tn(r),s=o??It(),i=n.TAVILY_API_KEY?.trim()||void 0,a=n.LLAMA_CTX_SIZE?.trim(),p=a&&/^\d+$/.test(a)?parseInt(a,10):void 0,l=e.tavilyKey??i??s.sources.tavilyKey,u=e.corpusPath??s.sources.corpusPath,h=u?fe(u):void 0,x=e.outputDir??s.sources.outputDir,k=x?fe(x):void 0,M=e.reasoningMode??s.defaults.reasoningMode??"deep",H=e.modelPath??s.model.path,R=H?fe(H):void 0,g=e.reranker??s.model.reranker,Q=e.nCtx??p??s.model.nCtx,L={version:1,sources:{tavilyKey:l,corpusPath:h,outputDir:k},defaults:{reasoningMode:M,verifyCount:s.defaults.verifyCount,maxTurns:s.defaults.maxTurns},model:{path:R,reranker:g,nCtx:Q}},Y={tavilyKey:e.tavilyKey?"cli":i?"env":s.sources.tavilyKey?"file":"unset",corpusPath:e.corpusPath?"cli":s.sources.corpusPath?"file":"unset",reasoningMode:e.reasoningMode?"cli":o?.defaults.reasoningMode?"file":"default",modelPath:e.modelPath?"cli":o?.model.path?"file":"default",reranker:e.reranker?"cli":o?.model.reranker?"file":"default",nCtx:e.nCtx!==void 0?"cli":p!==void 0?"env":o?.model.nCtx!==void 0?"file":"default",outputDir:e.outputDir?"cli":o?.sources.outputDir?"file":"default"};return{config:L,origin:Y,path:r,loadedFromFile:!!o}}function Ie(t,e,n=process.env){let r=z.resolve(e),o=Tn(r)??It(),s=[],i={...o.sources,...t.sources??{}};t.sources?.tavilyKey===""&&delete i.tavilyKey,t.sources?.corpusPath===""&&delete i.corpusPath,t.sources?.outputDir===""&&delete i.outputDir,n.TAVILY_API_KEY&&t.sources&&"tavilyKey"in t.sources&&(delete i.tavilyKey,s.push("sources.tavilyKey"));let a={version:1,sources:i,defaults:{...o.defaults,...t.defaults??{}},model:{...o.model,...t.model??{}}},p=z.dirname(r);j.mkdirSync(p,{recursive:!0});let l=r+".tmp-"+process.pid;j.writeFileSync(l,JSON.stringify(a,null,2)+`
|
|
7
|
+
`,"utf8"),j.renameSync(l,r);let u=po(r);return{path:r,gitignored:u,skipped:s}}function po(t){try{let e=ho(z.dirname(t));if(!e)return!1;let n=z.join(e,".gitignore"),r=z.relative(e,t).replace(/\\/g,"/"),o=j.existsSync(n)?j.readFileSync(n,"utf8"):"",s=z.basename(t);if(new RegExp(`(^|\\n)\\s*(${wn(r)}|${wn(s)})\\s*(\\n|$)`).test(o))return!1;let a=o.length===0||o.endsWith(`
|
|
8
|
+
`)?"":`
|
|
9
|
+
`;return j.appendFileSync(n,a+r+`
|
|
10
|
+
`),!0}catch{return!1}}function wn(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function ho(t){let e=z.resolve(t);for(;;){if(j.existsSync(z.join(e,".git")))return e;let n=z.dirname(e);if(n===e)return null;e=n}}function vn(){let t=[],e=new Set;return{send(n){if(t!==null){t.push(n);return}for(let r of e)r(n)},subscribe(n){if(e.add(n),t!==null){let r=t;t=null;for(let o of r)n(o)}return()=>{e.delete(n)}}}}import{TavilyProvider as oi}from"@lloyal-labs/rig";import{createReranker as si,WebSource as ii,CorpusSource as ai,chunkResources as li,resolveCorpusInput as ci}from"@lloyal-labs/rig/node";import ui from"ignore";import{call as Mt}from"effection";import{Ctx as Ot,Events as Bt,agent as So,agentPool as Dn,createToolkit as Ro,useAgent as Eo,chain as Ao,parallel as qn,renderTemplate as Te,withSharedRoot as Po,DefaultAgentPolicy as Wn}from"@lloyal-labs/lloyal-agents";import{reportTool as Nn,PlanTool as Io,taskToContent as Ln}from"@lloyal-labs/rig";var Cn=`You're a research planner. You analyze a user query and pick ONE of three dispositions, producing a JSON plan. Output JSON only.
|
|
11
|
+
---
|
|
12
|
+
The query: "<%= it.query %>"
|
|
13
|
+
|
|
14
|
+
Your output must commit to a single \`intent\`:
|
|
15
|
+
|
|
16
|
+
**intent: "clarify"** \u2014 the query is genuinely ambiguous and you cannot proceed without user input. Return 1-3 specific \`clarifyQuestions\` that would unblock you. Do not use this for "more detail would be nice" \u2014 only for genuine ambiguity that makes research infeasible.
|
|
17
|
+
|
|
18
|
+
**intent: "passthrough"** \u2014 the query is a follow-up answerable from the conversation history already visible in your context (prior assistant turns with their findings). No new research is needed; the harness will stream a direct answer from the existing context. Use this for questions like "what did you mean by X?", "summarize the second section", "compare A and B from your earlier findings". DO NOT use passthrough when the user has introduced new entities or shifted topic in a way that requires fresh research.
|
|
19
|
+
|
|
20
|
+
**intent: "research"** \u2014 the query needs a full research pipeline. Emit 1-\`<%= it.count %>\` research \`tasks\` as a chain-shaped plan.
|
|
21
|
+
|
|
22
|
+
For research intent, the rules for the \`tasks\` array:
|
|
23
|
+
|
|
24
|
+
1. **Task 1 is always landscape discovery.** It surveys the broad category the query belongs to and establishes vocabulary \u2014 the named projects, models, papers, or frameworks that later tasks will investigate. Task 1 should NOT try to answer any specific part of the query directly. Its only job is to identify entities and authoritative sources.
|
|
25
|
+
|
|
26
|
+
2. **Tasks 2+ each build on what prior tasks will have surfaced.** Every task after task 1 must be written so it can't be fully answered without prior findings. Use phrases like "for the entities surfaced by task 1", "among the projects identified in task 2", or "deepen the benchmarks from task 2" in the description \u2014 these force a real dependency chain rather than independent slices.
|
|
27
|
+
|
|
28
|
+
3. **Descriptions are self-contained at planning time.** Each description must be understandable on its own, written before any research has happened. For tasks 2+, pronoun-like references to prior tasks are resolved at runtime via the spine and count as self-contained. What's NOT allowed is inventing specific names: "investigate Moshi's architecture" presupposes you already found Moshi, which you haven't at planning time. Instead write: "investigate the architecture of the top end-to-end speech-to-speech models surfaced by task 1".
|
|
29
|
+
|
|
30
|
+
4. **Right-sized.** Each task answerable in 3-5 search/fetch cycles. Not "Research X" (too broad) and not "Find the exact phrase Y" (too narrow).
|
|
31
|
+
|
|
32
|
+
5. **Vocabulary-loaded.** Use the technical terms practitioners in that field would search for.
|
|
33
|
+
|
|
34
|
+
GOOD research chain for "How do modern cancer immunotherapies achieve durable remission?":
|
|
35
|
+
|
|
36
|
+
\`\`\`json
|
|
37
|
+
{
|
|
38
|
+
"intent": "research",
|
|
39
|
+
"tasks": [
|
|
40
|
+
{ "description": "Survey the landscape of cancer immunotherapies \u2014 the named modalities (checkpoint inhibitors, CAR-T cell therapies, bispecific antibodies, oncolytic viruses, cancer vaccines) \u2014 that appear in recent clinical reviews, oncology guidelines, and peer-reviewed surveys." },
|
|
41
|
+
{ "description": "For the modalities surfaced by task 1, find specific remission-durability metrics: objective response rate, progression-free survival, and overall survival at 2-5 years, reported in peer-reviewed clinical trials. Prefer sources with concrete numbers over qualitative claims." },
|
|
42
|
+
{ "description": "For the modalities with the best long-term remission rates from task 2, investigate the specific mechanisms and regimens that drive durability: target antigen selection, conditioning protocols, combination strategies, T-cell engineering." },
|
|
43
|
+
{ "description": "Survey the toxicity and access trade-offs for the modalities identified in task 1 \u2014 how each balances cytokine release syndrome, manufacturing complexity, and treatment cost against the durability benefits." }
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
\`\`\`
|
|
47
|
+
|
|
48
|
+
Notice that tasks 2-4 each reference what earlier tasks will have surfaced. None of them can be answered in isolation. This is a real dependency chain \u2014 the KV spine carries useful signal between every task.
|
|
49
|
+
|
|
50
|
+
GOOD passthrough for a follow-up after the above research completed: "What did you mean by cytokine release syndrome in the trade-offs section?":
|
|
51
|
+
|
|
52
|
+
\`\`\`json
|
|
53
|
+
{ "intent": "passthrough" }
|
|
54
|
+
\`\`\`
|
|
55
|
+
|
|
56
|
+
(No tasks, no clarifyQuestions \u2014 the harness will stream an answer from the prior assistant turn that's already in context.)
|
|
57
|
+
|
|
58
|
+
GOOD clarify for an ambiguous query "What's the best model?":
|
|
59
|
+
|
|
60
|
+
\`\`\`json
|
|
61
|
+
{
|
|
62
|
+
"intent": "clarify",
|
|
63
|
+
"clarifyQuestions": [
|
|
64
|
+
"Best at what task \u2014 language modeling, speech synthesis, image generation, or something else?",
|
|
65
|
+
"What constraints matter \u2014 local inference, cost, accuracy, latency?",
|
|
66
|
+
"Over what time horizon \u2014 currently available models or upcoming research?"
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
\`\`\`
|
|
70
|
+
|
|
71
|
+
BAD \u2014 passthrough when new research is warranted. If the follow-up introduces a new entity or topic not covered by the prior research, use research intent, not passthrough.
|
|
72
|
+
|
|
73
|
+
BAD \u2014 orthogonal slices, NOT a chain (for research intent):
|
|
74
|
+
|
|
75
|
+
\`\`\`json
|
|
76
|
+
{
|
|
77
|
+
"intent": "research",
|
|
78
|
+
"tasks": [
|
|
79
|
+
{ "description": "Research checkpoint inhibitors" },
|
|
80
|
+
{ "description": "Research CAR-T cell therapies" },
|
|
81
|
+
{ "description": "Research bispecific antibodies" },
|
|
82
|
+
{ "description": "Research oncolytic viruses" }
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
\`\`\`
|
|
86
|
+
|
|
87
|
+
These are independent \u2014 each could run in isolation, none builds on any other, and the spine carries no useful signal between them. Do NOT produce plans in this shape even when the query naturally decomposes into parallel sub-aspects.
|
|
88
|
+
|
|
89
|
+
BAD \u2014 individual task issues (for research intent):
|
|
90
|
+
- "Research cancer immunotherapy." (too broad, no vocabulary)
|
|
91
|
+
- "Find the exact 5-year overall survival number for pembrolizumab in NSCLC." (too narrow, single fact)
|
|
92
|
+
- "Investigate the durability of pembrolizumab, tisagenlecleucel, and talimogene laherparepvec." (invents specific names before task 1 has surfaced them \u2014 use "surfaced by task 1" pronoun reference instead)
|
|
93
|
+
<% if (it.context) { -%>
|
|
94
|
+
|
|
95
|
+
<%= it.context %>
|
|
96
|
+
<% } -%>
|
|
97
|
+
`;var Sn=`You're a research planner. You analyze a user query and pick ONE of three dispositions, producing a JSON plan. Output JSON only.
|
|
98
|
+
---
|
|
99
|
+
The query: "<%= it.query %>"
|
|
100
|
+
|
|
101
|
+
Your output must commit to a single \`intent\`:
|
|
102
|
+
|
|
103
|
+
**intent: "clarify"** \u2014 the query is genuinely ambiguous and you cannot proceed without user input. Return 1-3 specific \`clarifyQuestions\` that would unblock you. Do not use this for "more detail would be nice" \u2014 only for genuine ambiguity that makes research infeasible.
|
|
104
|
+
|
|
105
|
+
**intent: "passthrough"** \u2014 the query is a follow-up answerable from the conversation history already visible in your context (prior assistant turns with their findings). No new research is needed; the harness will stream a direct answer from the existing context. Use this for questions like "what did you mean by X?", "summarize the second section", "compare A and B from your earlier findings". DO NOT use passthrough when the user has introduced new entities or shifted topic in a way that requires fresh research.
|
|
106
|
+
|
|
107
|
+
**intent: "research"** \u2014 the query needs a full research pipeline. Emit 1-<%= it.count %> research \`tasks\` as a flat, parallel plan.
|
|
108
|
+
|
|
109
|
+
For research intent, the rules for the \`tasks\` array:
|
|
110
|
+
|
|
111
|
+
1. **Tasks are orthogonal.** Each task covers a distinct facet of the query and can be researched independently. Agents run concurrently and do NOT see each other's findings \u2014 no task can depend on another task's output.
|
|
112
|
+
|
|
113
|
+
2. **Descriptions are self-contained and independently researchable.** No cross-task references \u2014 phrases like "for the entities surfaced by task 1", "building on task 2's findings", or "among the projects identified in task 2" are FORBIDDEN. Every task must stand alone and be executable on its own without waiting for siblings.
|
|
114
|
+
|
|
115
|
+
3. **Collectively exhaustive.** The union of tasks should cover the meaningful facets of the query. Think "what are the distinct lenses through which this query decomposes?" \u2014 not "what's the first step, then the second step?"
|
|
116
|
+
|
|
117
|
+
4. **Vocabulary-loaded per-task.** Since there's no prior-task to lean on, each task must load its own technical vocabulary directly in its description. Name the modalities, frameworks, or entities the task should investigate \u2014 don't punt vocabulary discovery to a sibling.
|
|
118
|
+
|
|
119
|
+
5. **Right-sized.** Each task answerable in 3-5 search/fetch cycles. Not "Research X" (too broad) and not "Find the exact phrase Y" (too narrow).
|
|
120
|
+
|
|
121
|
+
GOOD research plan for "How do modern cancer immunotherapies achieve durable remission?":
|
|
122
|
+
|
|
123
|
+
\`\`\`json
|
|
124
|
+
{
|
|
125
|
+
"intent": "research",
|
|
126
|
+
"tasks": [
|
|
127
|
+
{ "description": "Survey checkpoint inhibitors (anti-PD-1, anti-PD-L1, anti-CTLA-4) \u2014 mechanisms, response rates, and long-term remission data in peer-reviewed oncology trials. Include durability metrics: objective response rate, progression-free survival, overall survival at 2-5 years." },
|
|
128
|
+
{ "description": "Survey CAR-T cell therapies \u2014 mechanisms (CD19, BCMA targeting), manufacturing approaches, response rates in hematologic malignancies (ALL, DLBCL, multiple myeloma), and solid-tumor trial outcomes. Include durability metrics and conditioning-regimen impact." },
|
|
129
|
+
{ "description": "Survey bispecific antibodies and T-cell engagers in oncology \u2014 named examples (blinatumomab, mosunetuzumab, teclistamab), mechanisms, clinical response durability, and trade-offs vs CAR-T." },
|
|
130
|
+
{ "description": "Survey oncolytic viruses and cancer vaccines as immunotherapy modalities \u2014 named examples (talimogene laherparepvec, neoantigen vaccines), mechanisms, response rates, and durability in clinical trials." }
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
\`\`\`
|
|
134
|
+
|
|
135
|
+
Notice that each task names its own scope and vocabulary directly. None reference another task. Each could run on its own agent and produce a standalone report. The harness fans in the four reports for synthesis.
|
|
136
|
+
|
|
137
|
+
GOOD passthrough for a follow-up after the above research completed: "What did you mean by cytokine release syndrome in the trade-offs section?":
|
|
138
|
+
|
|
139
|
+
\`\`\`json
|
|
140
|
+
{ "intent": "passthrough" }
|
|
141
|
+
\`\`\`
|
|
142
|
+
|
|
143
|
+
(No tasks, no clarifyQuestions \u2014 the harness will stream an answer from the prior assistant turn that's already in context.)
|
|
144
|
+
|
|
145
|
+
GOOD clarify for an ambiguous query "What's the best model?":
|
|
146
|
+
|
|
147
|
+
\`\`\`json
|
|
148
|
+
{
|
|
149
|
+
"intent": "clarify",
|
|
150
|
+
"clarifyQuestions": [
|
|
151
|
+
"Best at what task \u2014 language modeling, speech synthesis, image generation, or something else?",
|
|
152
|
+
"What constraints matter \u2014 local inference, cost, accuracy, latency?",
|
|
153
|
+
"Over what time horizon \u2014 currently available models or upcoming research?"
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
\`\`\`
|
|
157
|
+
|
|
158
|
+
BAD \u2014 passthrough when new research is warranted. If the follow-up introduces a new entity or topic not covered by the prior research, use research intent, not passthrough.
|
|
159
|
+
|
|
160
|
+
BAD \u2014 dependency chain, NOT orthogonal (for research intent):
|
|
161
|
+
|
|
162
|
+
\`\`\`json
|
|
163
|
+
{
|
|
164
|
+
"intent": "research",
|
|
165
|
+
"tasks": [
|
|
166
|
+
{ "description": "Survey the landscape of cancer immunotherapies and identify the named modalities that appear in recent reviews." },
|
|
167
|
+
{ "description": "For the modalities surfaced by task 1, find specific remission-durability metrics." },
|
|
168
|
+
{ "description": "For the modalities with the best long-term remission rates from task 2, investigate the specific mechanisms that drive durability." }
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
\`\`\`
|
|
172
|
+
|
|
173
|
+
These depend on each other \u2014 task 2 can't start until task 1 has surfaced modalities, and task 3 needs task 2's metrics. In parallel execution, task 2 and 3 run concurrently with task 1 and CANNOT see its findings. Do NOT produce plans in this shape. If the query genuinely needs a dependency chain, the user should run in chain mode.
|
|
174
|
+
|
|
175
|
+
BAD \u2014 individual task issues (for research intent):
|
|
176
|
+
- "Research cancer immunotherapy." (too broad, no vocabulary)
|
|
177
|
+
- "Find the exact 5-year overall survival number for pembrolizumab in NSCLC." (too narrow, single fact)
|
|
178
|
+
- "Investigate the best modalities found by other tasks." (cross-task reference \u2014 forbidden in parallel)
|
|
179
|
+
<% if (it.context) { -%>
|
|
180
|
+
|
|
181
|
+
<%= it.context %>
|
|
182
|
+
<% } -%>
|
|
183
|
+
`;var Rn="You are a research assistant.";var En=`Based on the research notes and source passages below, answer the question in 3-5 sentences. Use your own judgment to identify the key conclusions \u2014 do not paraphrase the research notes.
|
|
184
|
+
---
|
|
185
|
+
Research notes:
|
|
186
|
+
|
|
187
|
+
<%= it.agentFindings %>
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
Source passages:
|
|
192
|
+
|
|
193
|
+
<%= it.sourcePassages %>
|
|
194
|
+
|
|
195
|
+
Answer: "<%= it.query %>"
|
|
196
|
+
`;var An=`You are a consistency checker. Compare the responses below. Output JSON only.
|
|
197
|
+
|
|
198
|
+
Converged means: the responses agree on the key conclusions, even if they differ in detail, emphasis, or wording. Disagreement on minor points doesn't break convergence \u2014 disagreement on the core answer does.
|
|
199
|
+
---
|
|
200
|
+
Do these responses agree on the key conclusions?
|
|
201
|
+
|
|
202
|
+
<%= it.responses %>
|
|
203
|
+
`;var Pn=`You are a research reporter. The agent has been terminated due to budget constraints and must deliver findings now.
|
|
204
|
+
|
|
205
|
+
Call the report tool with the most important findings from the research above. Prioritize in this order:
|
|
206
|
+
1. Direct quotes and specific evidence that answer the task
|
|
207
|
+
2. Key conclusions with source URLs / line references
|
|
208
|
+
3. Supporting context (only if budget allows)
|
|
209
|
+
|
|
210
|
+
IMPORTANT: You have approximately <%= it.budget %> words for your report. Be concise \u2014 if you exceed the budget your report will be cut off.
|
|
211
|
+
---
|
|
212
|
+
Report your findings.
|
|
213
|
+
`;var In=`You are writing an analytical research report that answers the user's question below.
|
|
214
|
+
|
|
215
|
+
Above this message is the research that has been done: a series of conversation turns where each user turn asks a sub-question and the assistant turn that follows contains the findings for that sub-question.
|
|
216
|
+
|
|
217
|
+
Your report is an ARGUMENT, not a catalog. The difference matters:
|
|
218
|
+
- A catalog organizes findings by topic (hardware, quantization, TTS, LLMs) and lists what the research found on each. Readers can rearrange the sections without changing the report.
|
|
219
|
+
- An argument organizes findings by argumentative function (thesis, supporting evidence, complicating evidence, resolution, prescription). Each section exists to move the argument forward. Rearranging the sections breaks the logic.
|
|
220
|
+
|
|
221
|
+
Produce an argument.
|
|
222
|
+
|
|
223
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
224
|
+
RULE 0 \u2014 GROUNDING (overrides all other considerations)
|
|
225
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
226
|
+
|
|
227
|
+
Every factual claim must be traceable to the research turns above. "Factual claim" means: an entity (model, framework, library, paper, company, repository), a quantitative claim (benchmark number, VRAM, latency, size, percentage), a direct quote, a URL, or a concrete technical assertion (a technique, algorithm, or tradeoff that was evaluated).
|
|
228
|
+
|
|
229
|
+
Do NOT introduce:
|
|
230
|
+
- Models, frameworks, libraries, or papers the research did not name
|
|
231
|
+
- Benchmark numbers the research did not measure or cite
|
|
232
|
+
- Code examples or implementation snippets not shown in the research
|
|
233
|
+
- Techniques, algorithms, or tuning strategies the research did not discuss
|
|
234
|
+
- Architectural patterns, comparisons, or tradeoffs the research did not raise
|
|
235
|
+
|
|
236
|
+
If the research is silent on something important to the user's question, name that gap explicitly in your Limitations section rather than filling it from prior knowledge.
|
|
237
|
+
|
|
238
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
239
|
+
RULE 1 \u2014 THESIS
|
|
240
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
241
|
+
|
|
242
|
+
Commit to ONE thesis. State it in the opening paragraph. Every section that follows must advance that thesis.
|
|
243
|
+
|
|
244
|
+
The thesis is a POSITION on the user's question, derived from the findings. Examples of the shape:
|
|
245
|
+
- "Sub-100ms with native emotional nuance is not achievable with today's open-source stack \u2014 you must choose two of three."
|
|
246
|
+
- "Local voice agents have solved latency; the frontier has shifted to empathy modeling."
|
|
247
|
+
- "The market fragmentation reflects a deeper architectural split between cascading pipelines and end-to-end S2S models, and the right choice depends on N specific constraints."
|
|
248
|
+
|
|
249
|
+
The thesis is NOT:
|
|
250
|
+
- A restatement of the question
|
|
251
|
+
- A list of findings ("we found that A, B, and C")
|
|
252
|
+
- A hedge ("it depends on your needs")
|
|
253
|
+
- Three competing framings left unresolved
|
|
254
|
+
|
|
255
|
+
If the research points to multiple competing theses, PICK ONE based on which is most strongly supported by the findings, state it explicitly, and treat the others as complicating evidence to resolve within the report.
|
|
256
|
+
|
|
257
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
258
|
+
RULE 2 \u2014 STRUCTURE BY ARGUMENTATIVE FUNCTION
|
|
259
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
260
|
+
|
|
261
|
+
Organize the report by what each section DOES in service of the thesis, not by what topic it covers. Use this arc:
|
|
262
|
+
|
|
263
|
+
1. **Thesis (opening)** \u2014 state the position, name its load-bearing assumption
|
|
264
|
+
2. **Supporting evidence** \u2014 the findings that establish the thesis is real
|
|
265
|
+
3. **Complicating evidence** \u2014 the findings that pressure the thesis (counterexamples, exceptions, tradeoffs)
|
|
266
|
+
4. **Resolution** \u2014 how the complications are reconciled; what specifically must be true for the thesis to hold
|
|
267
|
+
5. **Prescription** \u2014 a concrete architectural/implementation recommendation that flows from the thesis
|
|
268
|
+
6. **Conclusion** \u2014 restate the thesis with the prescription tied in, + ### Limitations subheading
|
|
269
|
+
7. **Sources** \u2014 deduplicated URL list with descriptions
|
|
270
|
+
|
|
271
|
+
Section HEADINGS should reflect argumentative function, not topic. "The Empathy-Latency Tradeoff Emerges From Hardware Constraints" advances an argument. "Hardware Constraints" just labels a topic.
|
|
272
|
+
|
|
273
|
+
Do NOT produce a report with sections named after the agents' research topics (e.g., "Task 1 findings", "Hardware", "Emotional Prosody", "Speaker Diarization") in sequence. That is the catalog shape. Reject it.
|
|
274
|
+
|
|
275
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
276
|
+
RULE 3 \u2014 PROSE AND NARRATIVE
|
|
277
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
278
|
+
|
|
279
|
+
Write fluent, paragraph-based prose. A practitioner should be able to read the report end-to-end and understand the landscape.
|
|
280
|
+
|
|
281
|
+
Use narrative connective tissue to link findings into argument:
|
|
282
|
+
- "Building on X's approach to Y, Z demonstrates..."
|
|
283
|
+
- "The tradeoff between X and Y becomes concrete in the case of Z..."
|
|
284
|
+
- "Unlike X (which prioritizes A), Y takes the opposite approach by..."
|
|
285
|
+
- "Taken together, the findings on X, Y, and Z point to a pattern where..."
|
|
286
|
+
|
|
287
|
+
This connective tissue is interpretation, not invention \u2014 it draws out what findings mean when read as a whole, without adding entities or numbers that weren't found.
|
|
288
|
+
|
|
289
|
+
Prefer fluent paragraphs over bulleted extracts. Use bulleted lists only for genuinely parallel items (side-by-side model comparisons, spec tables) \u2014 never as a substitute for argument.
|
|
290
|
+
|
|
291
|
+
Tables serve the argument. A table comparing four models on three dimensions should support a claim being made in the prose, not stand alone as reference material.
|
|
292
|
+
|
|
293
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
294
|
+
RULE 4 \u2014 CUTTING FINDINGS THAT DON'T SERVE THE THESIS
|
|
295
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
296
|
+
|
|
297
|
+
The agents did thorough research. Not every finding belongs in the final report.
|
|
298
|
+
|
|
299
|
+
If a finding does not advance, support, complicate, or resolve the thesis, either:
|
|
300
|
+
- Mention it briefly and move on (one sentence), or
|
|
301
|
+
- Cut it entirely.
|
|
302
|
+
|
|
303
|
+
Do NOT include a finding because the agents found it. Include it because it serves the argument.
|
|
304
|
+
|
|
305
|
+
A comprehensive but flat report is weaker than a focused argument that leaves some findings out. Comprehensiveness is a catalog virtue. Coherence is an argument virtue.
|
|
306
|
+
|
|
307
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
308
|
+
HOW TO WRITE THE REPORT
|
|
309
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
310
|
+
|
|
311
|
+
1. Read every research turn above.
|
|
312
|
+
2. Take stock of the entities, sources, and quantitative claims the research surfaced \u2014 these are your factual vocabulary, the only factual vocabulary you may use.
|
|
313
|
+
3. Decide the thesis \u2014 one sentence that takes a position on the user's question, derived from what the findings collectively mean.
|
|
314
|
+
4. Identify which findings SUPPORT the thesis, which COMPLICATE it, and which are NOT RELEVANT to it.
|
|
315
|
+
5. Draft the report with the structure above \u2014 thesis in the opening paragraph, sections that build the argument, prescription that flows from the resolution.
|
|
316
|
+
6. For each section, write fluent paragraphs that cite findings inline (direct quotes, specific numbers, named sources). Bulleted extracts only when items are genuinely parallel.
|
|
317
|
+
7. End with ## Conclusion (restating thesis + prescription, + ### Limitations naming specific gaps) and ## Sources (deduplicated URL list with short descriptions).
|
|
318
|
+
|
|
319
|
+
OUTPUT FORMAT: emit the markdown report directly as your reply. Do NOT wrap it in any tool call, JSON envelope, or \`<tool_call>...</tool_call>\` tags. End naturally when the report is complete.
|
|
320
|
+
---
|
|
321
|
+
Research question: "<%= it.query %>"
|
|
322
|
+
|
|
323
|
+
Write the markdown report now.
|
|
324
|
+
`;var Mn=`You are writing an analytical research report that answers the user's question below.
|
|
325
|
+
|
|
326
|
+
The findings below come from N research agents that ran in parallel. Each agent covered a distinct facet of the question independently \u2014 they did not see each other's work. Your job is to synthesize their fan-in into a single coherent argument.
|
|
327
|
+
|
|
328
|
+
Your report is an ARGUMENT, not a catalog. The difference matters:
|
|
329
|
+
- A catalog organizes findings by topic (hardware, quantization, TTS, LLMs) and lists what each agent found. Readers can rearrange the sections without changing the report.
|
|
330
|
+
- An argument organizes findings by argumentative function (thesis, supporting evidence, complicating evidence, resolution, prescription). Each section exists to move the argument forward. Rearranging the sections breaks the logic.
|
|
331
|
+
|
|
332
|
+
Produce an argument.
|
|
333
|
+
|
|
334
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
335
|
+
RULE 0 \u2014 GROUNDING (overrides all other considerations)
|
|
336
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
337
|
+
|
|
338
|
+
Every factual claim must be traceable to the findings below. "Factual claim" means: an entity (model, framework, library, paper, company, repository), a quantitative claim (benchmark number, VRAM, latency, size, percentage), a direct quote, a URL, or a concrete technical assertion (a technique, algorithm, or tradeoff that was evaluated).
|
|
339
|
+
|
|
340
|
+
Do NOT introduce:
|
|
341
|
+
- Models, frameworks, libraries, or papers the research did not name
|
|
342
|
+
- Benchmark numbers the research did not measure or cite
|
|
343
|
+
- Code examples or implementation snippets not shown in the research
|
|
344
|
+
- Techniques, algorithms, or tuning strategies the research did not discuss
|
|
345
|
+
- Architectural patterns, comparisons, or tradeoffs the research did not raise
|
|
346
|
+
|
|
347
|
+
If the findings are silent on something important to the user's question, name that gap explicitly in your Limitations section rather than filling it from prior knowledge.
|
|
348
|
+
|
|
349
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
350
|
+
RULE 1 \u2014 THESIS
|
|
351
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
352
|
+
|
|
353
|
+
Commit to ONE thesis. State it in the opening paragraph. Every section that follows must advance that thesis.
|
|
354
|
+
|
|
355
|
+
The thesis is a POSITION on the user's question, derived from the findings. Examples of the shape:
|
|
356
|
+
- "Sub-100ms with native emotional nuance is not achievable with today's open-source stack \u2014 you must choose two of three."
|
|
357
|
+
- "Local voice agents have solved latency; the frontier has shifted to empathy modeling."
|
|
358
|
+
- "The market fragmentation reflects a deeper architectural split between cascading pipelines and end-to-end S2S models, and the right choice depends on N specific constraints."
|
|
359
|
+
|
|
360
|
+
The thesis is NOT:
|
|
361
|
+
- A restatement of the question
|
|
362
|
+
- A list of findings ("we found that A, B, and C")
|
|
363
|
+
- A hedge ("it depends on your needs")
|
|
364
|
+
- Three competing framings left unresolved
|
|
365
|
+
|
|
366
|
+
If the findings point to multiple competing theses, PICK ONE based on which is most strongly supported by the evidence across agents, state it explicitly, and treat the others as complicating evidence to resolve within the report.
|
|
367
|
+
|
|
368
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
369
|
+
RULE 2 \u2014 STRUCTURE BY ARGUMENTATIVE FUNCTION
|
|
370
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
371
|
+
|
|
372
|
+
Organize the report by what each section DOES in service of the thesis, not by which agent produced it. Use this arc:
|
|
373
|
+
|
|
374
|
+
1. **Thesis (opening)** \u2014 state the position, name its load-bearing assumption
|
|
375
|
+
2. **Supporting evidence** \u2014 the findings that establish the thesis is real
|
|
376
|
+
3. **Complicating evidence** \u2014 the findings that pressure the thesis (counterexamples, exceptions, tradeoffs)
|
|
377
|
+
4. **Resolution** \u2014 how the complications are reconciled; what specifically must be true for the thesis to hold
|
|
378
|
+
5. **Prescription** \u2014 a concrete architectural/implementation recommendation that flows from the thesis
|
|
379
|
+
6. **Conclusion** \u2014 restate the thesis with the prescription tied in, + ### Limitations subheading
|
|
380
|
+
7. **Sources** \u2014 deduplicated URL list with descriptions
|
|
381
|
+
|
|
382
|
+
Section HEADINGS should reflect argumentative function, not topic or agent. "The Empathy-Latency Tradeoff Emerges From Hardware Constraints" advances an argument. "Agent 1 Findings" or "Hardware" just labels a bucket.
|
|
383
|
+
|
|
384
|
+
CRITICAL: Do NOT produce a report with sections named after the agent facets (e.g., "Task 1: checkpoint inhibitors", "Task 2: CAR-T", "Task 3: bispecifics") in sequence. That is the catalog shape reproducing the fan-in structure. Reject it. Cross-cut the facets \u2014 when a finding from task 2 supports a claim from task 1, put them in the same section.
|
|
385
|
+
|
|
386
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
387
|
+
RULE 3 \u2014 PROSE AND NARRATIVE
|
|
388
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
389
|
+
|
|
390
|
+
Write fluent, paragraph-based prose. A practitioner should be able to read the report end-to-end and understand the landscape.
|
|
391
|
+
|
|
392
|
+
Use narrative connective tissue to link findings across agents:
|
|
393
|
+
- "Building on what agent 1 surfaced about X, the evidence from agent 3 demonstrates..."
|
|
394
|
+
- "The tradeoff between X and Y (agent 1) becomes concrete in the case of Z (agent 2)..."
|
|
395
|
+
- "Unlike the approach in facet 1 (which prioritizes A), facet 3 takes the opposite approach by..."
|
|
396
|
+
- "Taken together, the findings from agents 1, 2, and 3 point to a pattern where..."
|
|
397
|
+
|
|
398
|
+
This connective tissue is interpretation, not invention \u2014 it draws out what the fan-in means when read as a whole, without adding entities or numbers that weren't found.
|
|
399
|
+
|
|
400
|
+
Prefer fluent paragraphs over bulleted extracts. Use bulleted lists only for genuinely parallel items (side-by-side model comparisons, spec tables) \u2014 never as a substitute for argument.
|
|
401
|
+
|
|
402
|
+
Tables serve the argument. A table comparing four models on three dimensions should support a claim being made in the prose, not stand alone as reference material.
|
|
403
|
+
|
|
404
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
405
|
+
RULE 4 \u2014 CUTTING FINDINGS THAT DON'T SERVE THE THESIS
|
|
406
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
407
|
+
|
|
408
|
+
The agents did thorough research. Not every finding belongs in the final report.
|
|
409
|
+
|
|
410
|
+
If a finding does not advance, support, complicate, or resolve the thesis, either:
|
|
411
|
+
- Mention it briefly and move on (one sentence), or
|
|
412
|
+
- Cut it entirely.
|
|
413
|
+
|
|
414
|
+
Do NOT include a finding because an agent found it. Include it because it serves the argument.
|
|
415
|
+
|
|
416
|
+
A comprehensive but flat report is weaker than a focused argument that leaves some findings out. Comprehensiveness is a catalog virtue. Coherence is an argument virtue.
|
|
417
|
+
|
|
418
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
419
|
+
HOW TO WRITE THE REPORT
|
|
420
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
421
|
+
|
|
422
|
+
1. Read every agent's findings below.
|
|
423
|
+
2. Take stock of the entities, sources, and quantitative claims the fan-in surfaced \u2014 these are your factual vocabulary, the only factual vocabulary you may use.
|
|
424
|
+
3. Decide the thesis \u2014 one sentence that takes a position on the user's question, derived from what the findings collectively mean across agents.
|
|
425
|
+
4. Identify which findings SUPPORT the thesis, which COMPLICATE it, and which are NOT RELEVANT to it. Don't bucket by which agent produced them \u2014 cross-cut.
|
|
426
|
+
5. Draft the report with the structure above \u2014 thesis in the opening paragraph, sections that build the argument, prescription that flows from the resolution.
|
|
427
|
+
6. For each section, write fluent paragraphs that cite findings inline (direct quotes, specific numbers, named sources). Bulleted extracts only when items are genuinely parallel.
|
|
428
|
+
7. End with ## Conclusion (restating thesis + prescription, + ### Limitations naming specific gaps) and ## Sources (deduplicated URL list with short descriptions).
|
|
429
|
+
|
|
430
|
+
OUTPUT FORMAT: emit the markdown report directly as your reply. Do NOT wrap it in any tool call, JSON envelope, or \`<tool_call>...</tool_call>\` tags. End naturally when the report is complete.
|
|
431
|
+
---
|
|
432
|
+
Research question: "<%= it.query %>"
|
|
433
|
+
|
|
434
|
+
Findings from <%= it.agentCount %> parallel research agents:
|
|
435
|
+
|
|
436
|
+
<%= it.findings %>
|
|
437
|
+
|
|
438
|
+
Write the markdown report now.
|
|
439
|
+
`;var _n=`Apply the **corpus_research** skill.
|
|
440
|
+
|
|
441
|
+
You are a thorough research assistant analyzing a knowledge base to complete your task.
|
|
442
|
+
<% if (it.agentCount > 1) { -%>
|
|
443
|
+
|
|
444
|
+
You are one of <%= it.agentCount %> parallel agents. The other agents are covering:
|
|
445
|
+
<%= it.siblingTasks.map(function(q) { return '- ' + q }).join('\\n') %>
|
|
446
|
+
|
|
447
|
+
Stay focused on your own task. The other agents handle the rest.
|
|
448
|
+
<% } -%>
|
|
449
|
+
|
|
450
|
+
Available files:
|
|
451
|
+
<%= it.toc %>
|
|
452
|
+
|
|
453
|
+
You have <%= it.maxTurns %> tool calls. Plan your investigation within this budget.
|
|
454
|
+
|
|
455
|
+
RULES FOR TOOL OPTIMAL USE:
|
|
456
|
+
- If grep returns zero matches, the exact pattern is absent \u2014 but the topic may still be present. Try broader keywords or search instead.
|
|
457
|
+
- If a query returns \`Resource unavailable\`, another agent already issued that exact call. Try different terms.
|
|
458
|
+
- Don't repeat the same query or read the same lines twice.
|
|
459
|
+
- When a tool returns an error about time limit, KV limit or word limit, stop and call report() tool with all your findings so far.
|
|
460
|
+
|
|
461
|
+
PROCESS:
|
|
462
|
+
1. Grep or search to find relevant content for your task.
|
|
463
|
+
2. Read every matching line with read_file to verify in context. Do not rely on grep/search summaries alone \u2014 they are truncated.
|
|
464
|
+
3. Based on what you read, identify specific claims to verify or details that are missing, then grep/search for those.
|
|
465
|
+
4. Call report() with comprehensive findings: direct quotes, data points, source URLs. State what you found AND what you checked but could not find. Do not summarize \u2014 preserve the detail.
|
|
466
|
+
|
|
467
|
+
`;var On=`Apply the **web_research** skill.
|
|
468
|
+
|
|
469
|
+
You are a thorough research assistant investigating with your tools to complete your task.
|
|
470
|
+
<% if (it.agentCount > 1) { -%>
|
|
471
|
+
|
|
472
|
+
You are one of <%= it.agentCount %> parallel agents. The other agents are covering:
|
|
473
|
+
<%= it.siblingTasks.map(function(q) { return '- ' + q }).join('\\n') %>
|
|
474
|
+
|
|
475
|
+
Stay focused on your own task. The other agents handle the rest.
|
|
476
|
+
<% } -%>
|
|
477
|
+
|
|
478
|
+
You have <%= it.maxTurns %> tool calls. Plan your investigation within this budget.
|
|
479
|
+
|
|
480
|
+
Today's date is <%= it.date %>. When crafting search queries, anchor on the current year \u2014 do not default to earlier years unless the query explicitly asks about historical content.
|
|
481
|
+
|
|
482
|
+
RULES FOR TOOL OPTIMAL USE:
|
|
483
|
+
- The purpose of snippets from web_search results is only to identify pages to fetch.
|
|
484
|
+
- Your analysis should be based on pages returned by fetch_page.
|
|
485
|
+
- Following up a web_search call with fetch_page on selected links will maximize the information you can analyze.
|
|
486
|
+
- When a tool returns an error about time limit, KV limit or word limit, stop and call report() tool with all your findings so far.
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
<% if (it.taskIndex > 0) { %>
|
|
490
|
+
BUILD ON PRIOR RESEARCH:
|
|
491
|
+
Prior research tasks in this plan have already been completed. Their findings are in your conversation history above, as assistant turns following each task's user turn. Your task was written to build on what they found.
|
|
492
|
+
|
|
493
|
+
Before your first tool call, read the prior findings in your context. Look for named entities (projects, models, papers, frameworks, companies), authoritative sources, and open questions that your task is meant to follow up on. Your first web_search should target a specific named entity or open question from the prior findings, not the general topic of your task. Do not re-investigate ground already covered \u2014 deepen or fill gaps instead.
|
|
494
|
+
<% } %>
|
|
495
|
+
PROCESS:
|
|
496
|
+
1. Search for the broad category your task belongs to \u2014 surveys, comparisons, community discussions \u2014 not the specific task itself.
|
|
497
|
+
2. Immediately fetch the most information-dense links from the search results: research papers, community discussions (Reddit, HN, forums), survey articles that name many specific works.
|
|
498
|
+
3. From what you read, identify the specific projects, techniques, or entities relevant to your task. If a follow-up search would target a different angle, run it \u2014 but only after reading what you already have.
|
|
499
|
+
4. Call report() with comprehensive findings: direct quotes, data points, source URLs. State what you found AND what you checked but could not find. Do not summarize \u2014 preserve the detail.
|
|
500
|
+
`;var Bn=`You are an assistant working as part of a multi-agent workflow. You have access to the tools below, grouped by skill. You should only use the tools for a given skill when that particular skill is requested explicitly in your task instructions.
|
|
501
|
+
|
|
502
|
+
# Skills
|
|
503
|
+
|
|
504
|
+
<% if (it.hasWeb) { -%>
|
|
505
|
+
## web_research
|
|
506
|
+
Tools: web_search, fetch_page
|
|
507
|
+
Use when: gathering evidence from the open web \u2014 verifying current claims, retrieving primary sources from URLs, surveying official documentation and authoritative discussion.
|
|
508
|
+
|
|
509
|
+
<% } -%>
|
|
510
|
+
<% if (it.hasCorpus) { -%>
|
|
511
|
+
## corpus_research
|
|
512
|
+
Tools: grep, read_file, search
|
|
513
|
+
Use when: investigating a local document corpus \u2014 finding occurrences of terms, reading specific files at line offsets, semantic retrieval over indexed corpus content.
|
|
514
|
+
|
|
515
|
+
<% } -%>
|
|
516
|
+
# Tool selection rule
|
|
517
|
+
|
|
518
|
+
The agent system message will tell you which skill to apply. Use only that skill's tools. The agent system message also carries an engineered PROCESS that dictates intra-skill ordering. Follow that PROCESS, but constrained to the assigned skill's palette.
|
|
519
|
+
|
|
520
|
+
# Examples
|
|
521
|
+
|
|
522
|
+
<% if (it.hasWeb) { -%>
|
|
523
|
+
## GOOD: web_research applied correctly
|
|
524
|
+
|
|
525
|
+
SYSTEM:
|
|
526
|
+
Apply the **web_research** skill.
|
|
527
|
+
You are a thorough research assistant. PROCESS: 1) broad web_search; 2) fetch_page on top 2\u20133 results; 3) report.
|
|
528
|
+
|
|
529
|
+
USER:
|
|
530
|
+
Research task: Project Alpha
|
|
531
|
+
|
|
532
|
+
ASSISTANT calls: web_search({"query": "Project Alpha architecture overview"})
|
|
533
|
+
TOOL_RESULT: [search hits\u2026]
|
|
534
|
+
|
|
535
|
+
ASSISTANT calls: fetch_page({"url": "https://alpha.example.com/docs/architecture"})
|
|
536
|
+
TOOL_RESULT: [page content\u2026]
|
|
537
|
+
|
|
538
|
+
ASSISTANT calls: report({"summary": "Project Alpha findings: \u2026"})
|
|
539
|
+
|
|
540
|
+
\u2713 web_search and fetch_page both belong to web_research; PROCESS followed; report is the universal terminal.
|
|
541
|
+
|
|
542
|
+
<% } -%>
|
|
543
|
+
<% if (it.hasCorpus) { -%>
|
|
544
|
+
## GOOD: corpus_research applied correctly
|
|
545
|
+
|
|
546
|
+
SYSTEM:
|
|
547
|
+
Apply the **corpus_research** skill.
|
|
548
|
+
You are analyzing a local knowledge base. PROCESS: 1) grep or search; 2) read_file on matches; 3) report.
|
|
549
|
+
|
|
550
|
+
USER:
|
|
551
|
+
Research task: Project Beta
|
|
552
|
+
|
|
553
|
+
ASSISTANT calls: grep({"pattern": "Project Beta"})
|
|
554
|
+
TOOL_RESULT: [matching lines with file paths and line numbers\u2026]
|
|
555
|
+
|
|
556
|
+
ASSISTANT calls: read_file({"path": "docs/beta-overview.md", "offset": 40, "limit": 80})
|
|
557
|
+
TOOL_RESULT: [file content\u2026]
|
|
558
|
+
|
|
559
|
+
ASSISTANT calls: report({"summary": "Project Beta findings: \u2026"})
|
|
560
|
+
|
|
561
|
+
\u2713 grep, read_file, search are corpus_research's palette; report is the universal terminal.
|
|
562
|
+
|
|
563
|
+
<% } -%>
|
|
564
|
+
<% if (it.hasWeb && it.hasCorpus) { -%>
|
|
565
|
+
## BAD: corpus_research requested, web_research tool used
|
|
566
|
+
|
|
567
|
+
SYSTEM:
|
|
568
|
+
Apply the **corpus_research** skill.
|
|
569
|
+
You are analyzing a local knowledge base. PROCESS: grep/search \u2192 read_file \u2192 report.
|
|
570
|
+
|
|
571
|
+
USER:
|
|
572
|
+
Research task: Project Beta
|
|
573
|
+
|
|
574
|
+
ASSISTANT calls: web_search({"query": "Project Beta"})
|
|
575
|
+
|
|
576
|
+
\u2717 WRONG. web_search is in web_research's palette, not corpus_research's. Should have called grep, search, or read_file against the local corpus.
|
|
577
|
+
|
|
578
|
+
## BAD: web_research requested, corpus_research tool used
|
|
579
|
+
|
|
580
|
+
SYSTEM:
|
|
581
|
+
Apply the **web_research** skill.
|
|
582
|
+
PROCESS: search \u2192 fetch \u2192 report.
|
|
583
|
+
|
|
584
|
+
USER:
|
|
585
|
+
Research task: Project Alpha
|
|
586
|
+
|
|
587
|
+
ASSISTANT calls: grep({"pattern": "Project Alpha"})
|
|
588
|
+
|
|
589
|
+
\u2717 WRONG. grep is in corpus_research's palette, not web_research's. Should have called web_search to find authoritative sources on the open web.
|
|
590
|
+
|
|
591
|
+
<% } -%>
|
|
592
|
+
<% if (it.hasWeb) { -%>
|
|
593
|
+
## BAD: web_research requested, report called without prior retrieval
|
|
594
|
+
|
|
595
|
+
SYSTEM:
|
|
596
|
+
Apply the **web_research** skill.
|
|
597
|
+
PROCESS: search \u2192 fetch \u2192 report.
|
|
598
|
+
|
|
599
|
+
USER:
|
|
600
|
+
Research task: Project Alpha
|
|
601
|
+
|
|
602
|
+
ASSISTANT calls: report({"summary": "(no findings \u2014 no research performed)"})
|
|
603
|
+
|
|
604
|
+
\u2717 WRONG. Research skills require gathering evidence before reporting. report is the terminal \u2014 calling it without prior web_search/fetch_page produces an empty finding.
|
|
605
|
+
|
|
606
|
+
<% } -%>
|
|
607
|
+
<% if (it.hasCorpus) { -%>
|
|
608
|
+
## BAD: corpus_research requested, report called without prior retrieval
|
|
609
|
+
|
|
610
|
+
SYSTEM:
|
|
611
|
+
Apply the **corpus_research** skill.
|
|
612
|
+
PROCESS: grep/search \u2192 read_file \u2192 report.
|
|
613
|
+
|
|
614
|
+
USER:
|
|
615
|
+
Research task: Project Beta
|
|
616
|
+
|
|
617
|
+
ASSISTANT calls: report({"summary": "(no findings \u2014 no corpus inspection performed)"})
|
|
618
|
+
|
|
619
|
+
\u2717 WRONG. Research skills require gathering evidence before reporting. report is the terminal \u2014 calling it without prior grep/search/read_file produces an empty finding.
|
|
620
|
+
|
|
621
|
+
<% } -%>
|
|
622
|
+
`;function ge(t){let e=t.trim(),n=e.indexOf(`
|
|
623
|
+
---
|
|
624
|
+
`);return n===-1?{system:e,user:""}:{system:e.slice(0,n).trim(),user:e.slice(n+5).trim()}}var Mo=ge(Cn),_o=ge(Sn),Oo=ge(Rn),Fn=ge(En),Un=ge(An),Bo=ge(Pn),Do=ge(In),qo=ge(Mn),No=_n,Lo=On,Fo=Bn;function Uo(){return new Wn({budget:{context:{softLimit:2048,hardLimit:1024},time:{softLimit:24e4,hardLimit:36e4}},recovery:{prompt:Bo},terminalTool:"report"})}var _t=class extends Wn{onProduced(...e){let[,n]=e;return!n.toolCalls[0]&&n.content?{type:"free_text_report",content:n.content}:super.onProduced(...e)}};function $n(t,e){return t.promptData?Te(No,{...t.promptData(),...e}):t.name==="web"?Te(Lo,e):Oo.system}function zn(){return new Date().toISOString().slice(0,10)}function at(){let t=performance.now();return()=>performance.now()-t}function*$o(t,e){let n=e.trunk;if(!n)throw new Error("runPassthrough: session has no trunk \u2014 passthrough requires a warm session");let r=yield*Ot.expect(),o=r.getTurnSeparator(),{prompt:s}=r.formatChatSync(JSON.stringify([{role:"user",content:t}]),{addGenerationPrompt:!0,enableThinking:!1}),i=[...o,...r.tokenizeSync(s,!1)];yield*Mt(()=>n.prefill(i));let a=performance.now(),p=0,l=[];for(;;){let{token:u,text:h,isStop:x}=n.produceSync();if(x)break;yield*Mt(()=>n.commit(u)),p++,l.push(h)}return{answer:l.join(""),tokenCount:p,timeMs:performance.now()-a}}function*Me(t,e,n){let r=yield*Bt.expect(),o=u=>r.send(u);yield*o({type:"query",query:t,warm:!!e.trunk});let s=zn(),i=n.reasoningMode==="flat"?_o:Mo,a=new Io({prompt:i,session:e,maxQuestions:10}),p=n.context?`Today's date: ${s}
|
|
625
|
+
|
|
626
|
+
${n.context}`:`Today's date: ${s}`,l=yield*a.execute({query:t,context:p});return yield*o({type:"plan",intent:l.intent,tasks:l.tasks,clarifyQuestions:l.clarifyQuestions,tokenCount:l.tokenCount,timeMs:l.timeMs}),l}function*_e(t,e,n,r){let o=yield*Bt.expect(),s=u=>o.send(u),i=yield*$o(t,e);yield*s({type:"answer",text:i.answer});let p=(yield*Ot.expect())._storeKvPressure(),l=p.nCtx||1;yield*s({type:"stats",timings:[{label:"Plan",tokens:n.tokenCount,detail:n.intent,timeMs:n.timeMs},{label:"Passthrough",tokens:i.tokenCount,detail:"trunk stream",timeMs:i.timeMs}],ctxPct:Math.round(100*p.cellsUsed/l),ctxPos:p.cellsUsed,ctxTotal:l}),yield*s({type:"complete",data:{intent:n.intent,planTokens:n.tokenCount,passthroughTokens:i.tokenCount,wallTimeMs:Math.round(performance.now()-r),planMs:Math.round(n.timeMs),passthroughMs:Math.round(i.timeMs)}})}function*Dt(t,e,n,r,o,s,i){let a=yield*Bt.expect(),p=P=>a.send(P);if(e.intent!=="research")throw new Error(`runResearchBranch: expected plan.intent=research, got ${e.intent}`);let l=e.tasks,u=zn();yield*p({type:"research:start",agentCount:l.length,mode:s.reasoningMode});let h=at();for(let P of r)yield*P.bind({reranker:o});let x=new Map(r.map(P=>[P,P.createScorer(t)])),k=r.flatMap(P=>P.tools),M=r[0],H=x.get(M),R=r.some(P=>P.name==="web"),g=r.some(P=>typeof P.promptData=="function"),Q=Te(Fo,{hasWeb:R,hasCorpus:g}),L=Ro([...k,Nn]),Y=0,V=0,{answer:Z,totalTokens:te,totalToolCalls:ie,synthTokens:W}=yield*Po({parent:n.trunk??void 0,systemPrompt:Q,toolsJson:L.toolsJson},function*(P){s.reasoningMode==="flat"&&(yield*p({type:"fanout:tasks",tasks:l}));let ne=yield*Dn({tools:[...k,Nn],parent:P,terminalTool:"report",maxTurns:s.maxTurns,pruneOnReport:!0,policy:Uo(),scorer:H,enableThinking:!0,orchestrate:s.reasoningMode==="flat"?qn(l.map((we,re)=>({content:Ln(we),systemPrompt:$n(M,{maxTurns:s.maxTurns,agentCount:l.length,siblingTasks:l.filter((Ae,$e)=>$e!==re).map(Ae=>Ae.description),date:u,taskIndex:0}),seed:1e3+re}))):Ao(l,(we,re)=>({task:{content:Ln(we),systemPrompt:$n(M,{maxTurns:s.maxTurns,agentCount:1,siblingTasks:[],date:u,taskIndex:re})},userContent:`Research task: ${we.description}`,beforeSpawn:function*(){yield*p({type:"spine:task",taskIndex:re,taskCount:l.length,description:we.description}),yield*p({type:"spine:source",taskIndex:re,source:M.name})},afterExtend:function*(Ae,$e){yield*p({type:"spine:task:done",taskIndex:re,stageFindings:Ae,accumulated:$e})}}))});V=h(),yield*p({type:"research:done",totalTokens:ne.totalTokens,totalToolCalls:ne.totalToolCalls,timeMs:V}),yield*p({type:"synthesize:start"});let oo=at(),fn=s.reasoningMode==="flat"?qo:Do,so=s.reasoningMode==="flat"?ne.agents.map((we,re)=>{let Ae=l[re]?.description??`task ${re+1}`,$e=we.result?.trim()||"(no findings)";return`### Agent ${re+1}: ${Ae}
|
|
627
|
+
|
|
628
|
+
${$e}`}).join(`
|
|
629
|
+
|
|
630
|
+
`):void 0,gn={query:t,findings:so,agentCount:l.length},ke=yield*Eo({systemPrompt:Te(fn.system,gn),task:Te(fn.user,gn),parent:P,policy:new _t,maxTurns:s.maxTurns});Y=oo();let io=ke.result||"";return yield*p({type:"synthesize:done",agentId:ke.id,ppl:ke.branch.disposed?0:ke.branch.perplexity,tokenCount:ke.tokenCount,toolCallCount:ke.toolCallCount,timeMs:Y}),{answer:io,totalTokens:ne.totalTokens,totalToolCalls:ne.totalToolCalls,synthTokens:ke.tokenCount}});yield*p({type:"answer",text:Z});let C=Te(Fn.user,{agentFindings:Z||"(none)",sourcePassages:"(spine)",query:t}),Fe=at();yield*p({type:"verify:start",count:s.verifyCount,mode:s.reasoningMode});let de=yield*Dn({orchestrate:qn(Array.from({length:s.verifyCount},(P,ne)=>({content:C,systemPrompt:Fn.system,seed:2e3+ne})))});yield*p({type:"verify:done",count:s.verifyCount,timeMs:Fe()});let c=de.agents.map(P=>P.agent.rawOutput).map((P,ne)=>`Response ${ne+1}: ${P.trim()}`).join(`
|
|
631
|
+
|
|
632
|
+
`),m=at(),d=yield*So({systemPrompt:Un.system,task:Te(Un.user,{responses:c}),schema:{type:"object",properties:{converged:{type:"boolean"}},required:["converged"]}}),f=m(),w=null;try{w=JSON.parse(d.rawOutput).converged}catch{}yield*p({type:"eval:done",converged:w,tokenCount:d.tokenCount,sampleCount:s.verifyCount,timeMs:f}),Z&&(yield*Mt(()=>n.commitTurn(t,Z)));let Ue=(yield*Ot.expect())._storeKvPressure(),ot=Ue.nCtx||1,xe=[{label:"Plan",tokens:e.tokenCount,detail:e.intent,timeMs:e.timeMs},{label:"Research",tokens:te,detail:`${ie} tools`,timeMs:V},{label:"Synthesize",tokens:W,detail:"spine fork",timeMs:Y},{label:"Eval",tokens:d.tokenCount,detail:`converged: ${w?"yes":"no"}`,timeMs:f}];yield*p({type:"stats",timings:xe,ctxPct:Math.round(100*Ue.cellsUsed/ot),ctxPos:Ue.cellsUsed,ctxTotal:ot}),yield*p({type:"complete",data:{intent:e.intent,planTokens:e.tokenCount,agentTokens:te,synthTokens:W,evalTokens:d.tokenCount,converged:w,totalToolCalls:ie,agentCount:l.length,wallTimeMs:Math.round(performance.now()-i),planMs:Math.round(e.timeMs),researchMs:Math.round(V),synthMs:Math.round(Y),evalMs:Math.round(f)}})}function*Hn(t,e,n,r,o,s){let i=performance.now(),a=yield*Me(t,e,{reasoningMode:o.reasoningMode,context:s});return a.intent==="clarify"?{type:"clarify",questions:a.clarifyQuestions}:a.intent==="passthrough"?(yield*_e(t,e,a,i),{type:"done"}):(yield*Dt(t,a,e,n,r,o,i),{type:"done"})}import*as oe from"node:fs";import*as jn from"node:os";import*as ye from"node:path";var Yn={name:"reasoning.run",version:"0.1.0",description:"Local deep-research agent composer \u2014 runs on your machine, zero-config after the first query. Built on @lloyal-labs/*.",bin:{"reasoning.run":"bin/run.js"},files:["bin","dist","LICENSE","README.md"],scripts:{build:"esbuild src/main.ts --bundle --platform=node --target=node22 --format=esm --packages=external --loader:.eta=text --outfile=dist/bundle.mjs --minify --legal-comments=none","build:watch":"esbuild src/main.ts --bundle --platform=node --target=node22 --format=esm --packages=external --loader:.eta=text --outfile=dist/bundle.mjs --watch",start:"npm run build && node bin/run.js",smoke:"tsx src/tui-ink/__bus-smoke.ts && tsx src/tui-ink/__reducer-smoke.ts && tsx src/tui-ink/__config-smoke.ts && tsx src/__download-smoke.ts && tsx src/__rundir-smoke.ts","smoke:visual":"tsx src/tui-ink/__visual-smoke.tsx",prepublishOnly:"npm run build"},dependencies:{"@lloyal-labs/lloyal-agents":"^2.0.0","@lloyal-labs/lloyal.node":"^2.1.0","@lloyal-labs/rig":"^2.0.1","@lloyal-labs/sdk":"^2.0.0",effection:"^4.0.2",eta:"^4.5.1",ignore:"^7.0.5",ink:"^7.0.1",react:"^19.2.5"},devDependencies:{"@types/node":"^25.3.0","@types/react":"^19.2.14",esbuild:"^0.28.0",tsx:"^4.21.0",typescript:"^5.9.3"},engines:{node:">=22"},keywords:["deep-research","local-llm","agents","llama.cpp","cli","tui","ink"],repository:{type:"git",url:"git+https://github.com/lloyal-ai/reasoning-run.git"},license:"SEE LICENSE IN LICENSE"};var zo=`reasoning.run/${Yn.version}`,qt=[{id:"qwen3.5-4b-q4",label:"Qwen3.5-4B Q4_K_M",kind:"llm",urls:["https://huggingface.co/unsloth/Qwen3.5-4B-GGUF/resolve/main/Qwen3.5-4B-Q4_K_M.gguf","https://models.lloyal.ai/Qwen3.5-4B-Q4_K_M.gguf"],filename:"Qwen3.5-4B-Q4_K_M.gguf",sizeBytes:26e8,recommendedNCtx:32768},{id:"qwen3-reranker-0.6b-q8",label:"Qwen3-Reranker 0.6B Q8_0",kind:"reranker",urls:["https://huggingface.co/ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF/resolve/main/qwen3-reranker-0.6b-q8_0.gguf","https://models.lloyal.ai/qwen3-reranker-0.6b-q8_0.gguf"],filename:"qwen3-reranker-0.6b-q8_0.gguf",sizeBytes:63e7}],Ho=qt.find(t=>t.kind==="llm"),Yo=qt.find(t=>t.kind==="reranker");function lt(){let t=process.env.XDG_CACHE_HOME||ye.join(jn.homedir(),".cache");return ye.join(t,"lloyal","models")}function We(t,e){if(!t){let r=e==="llm"?Ho:Yo;return{path:ye.join(lt(),r.filename),entry:r}}let n=qt.find(r=>r.id===t);return n?{path:ye.join(lt(),n.filename),entry:n}:{path:ye.resolve(t),entry:null}}async function Kn(t,e={}){let n=ye.join(lt(),t.filename);if(oe.existsSync(n))return n;oe.mkdirSync(lt(),{recursive:!0});let r=n+".partial";try{oe.unlinkSync(r)}catch{}let o=[];for(let s of t.urls)try{return await jo(s,r,n,t.sizeBytes,e)}catch(i){o.push(` ${s}: ${i.message}`);try{oe.unlinkSync(r)}catch{}}throw new Error(`Failed to download ${t.label} from any source:
|
|
633
|
+
${o.join(`
|
|
634
|
+
`)}`)}async function jo(t,e,n,r,o){let s=await fetch(t,{redirect:"follow",headers:{"User-Agent":zo}});if(!s.ok||!s.body)throw new Error(`HTTP ${s.status} ${s.statusText}`);let i=Number(s.headers.get("content-length")??r),a=oe.createWriteStream(e),p=0,l=0,u=(h=!1)=>{if(!o.onProgress)return;let x=Date.now();!h&&x-l<200||(l=x,o.onProgress(p,i,t))};try{for await(let h of s.body)a.write(h),p+=h.byteLength,u()}catch(h){throw a.destroy(),h}return await new Promise((h,x)=>{a.end(k=>k?x(k):h())}),oe.renameSync(e,n),u(!0),n}import*as ze from"node:fs";import*as He from"node:path";var ct=class{currentDir=null;inResearch=!1;spawnOrdinal=0;agentToOrdinal=new Map;taskByOrdinal=new Map;lastAnswer=null;query=null;mode=null;startedAt=null;synthStats=null;start(e){let n=new Date().toISOString().replace(/[:.]/g,"-").replace("Z","");return this.currentDir=He.resolve(e.outputDir,n),ze.mkdirSync(this.currentDir,{recursive:!0}),this.inResearch=!1,this.spawnOrdinal=0,this.agentToOrdinal.clear(),this.taskByOrdinal.clear(),this.lastAnswer=null,this.query=e.query,this.mode=e.mode,this.startedAt=Date.now(),this.synthStats=null,this.currentDir}handle(e){if(this.currentDir)switch(e.type){case"research:start":this.inResearch=!0;break;case"research:done":this.inResearch=!1;break;case"fanout:tasks":e.tasks.forEach((n,r)=>this.taskByOrdinal.set(r+1,n.description));break;case"spine:task":this.taskByOrdinal.set(e.taskIndex+1,e.description);break;case"agent:spawn":this.inResearch&&!this.agentToOrdinal.has(e.agentId)&&(this.spawnOrdinal+=1,this.agentToOrdinal.set(e.agentId,this.spawnOrdinal));break;case"agent:report":{let n=this.agentToOrdinal.get(e.agentId);n!==void 0&&this.writeAnnexure(n,e.result);break}case"answer":this.lastAnswer=e.text;break;case"synthesize:done":this.synthStats={tokens:e.tokenCount,ppl:e.ppl,timeMs:e.timeMs};break;case"complete":this.finish();break;case"ui:error":this.reset();break}}writeAnnexure(e,n){if(!this.currentDir)return;let r=this.taskByOrdinal.get(e)??"",o=`# Annexure ${e}
|
|
635
|
+
|
|
636
|
+
${r?`**Task:** ${r}
|
|
637
|
+
|
|
638
|
+
`:""}---
|
|
639
|
+
|
|
640
|
+
`;ze.writeFileSync(He.join(this.currentDir,`annexure-${e}.md`),o+n.trimEnd()+`
|
|
641
|
+
`,"utf8")}finish(){if(this.currentDir&&this.lastAnswer&&this.query){let e=this.startedAt?Date.now()-this.startedAt:0,r=[...this.agentToOrdinal.values()].sort((p,l)=>p-l).map(p=>{let l=this.taskByOrdinal.get(p);return`- [Annexure ${p}](./annexure-${p}.md)${l?` \u2014 ${l}`:""}`}).join(`
|
|
642
|
+
`),o=this.synthStats?` \xB7 ${this.synthStats.tokens} synth tokens \xB7 ppl ${this.synthStats.ppl.toFixed(2)}`:"",s=`> ${new Date().toISOString()} \xB7 ${this.mode}${o} \xB7 ${(e/1e3).toFixed(1)}s`,i=r?`
|
|
643
|
+
---
|
|
644
|
+
|
|
645
|
+
## Annexures
|
|
646
|
+
|
|
647
|
+
${r}
|
|
648
|
+
`:"",a=`# ${this.query}
|
|
649
|
+
|
|
650
|
+
${s}
|
|
651
|
+
|
|
652
|
+
${this.lastAnswer.trim()}
|
|
653
|
+
${i}`;ze.writeFileSync(He.join(this.currentDir,"report.md"),a,"utf8")}this.reset()}reset(){this.currentDir=null,this.inResearch=!1,this.spawnOrdinal=0,this.agentToOrdinal.clear(),this.taskByOrdinal.clear(),this.lastAnswer=null,this.query=null,this.mode=null,this.startedAt=null,this.synthStats=null}};var di=ue.join(process.cwd(),"harness.json"),{values:B,positionals:pi}=Js({args:process.argv.slice(2),options:{query:{type:"string"},reranker:{type:"string"},corpus:{type:"string"},config:{type:"string"},"findings-budget":{type:"string"},"reasoning-mode":{type:"string"},"n-ctx":{type:"string"},"output-dir":{type:"string"},jsonl:{type:"boolean",default:!1},verbose:{type:"boolean",default:!1}},allowPositionals:!0}),me=B["reasoning-mode"];me!==void 0&&me!=="flat"&&me!=="deep"&&(process.stderr.write(`Invalid --reasoning-mode: ${me}. Expected "flat" or "deep".
|
|
654
|
+
`),process.exit(1));var et=pi[0]||void 0,hn=B.jsonl,no=B.verbose,tt=B["output-dir"],he=B.query,ce=B.config??di,nt=B["n-ctx"];nt!==void 0&&!/^\d+$/.test(nt)&&(process.stderr.write(`Invalid --n-ctx: ${nt}. Expected a positive integer.
|
|
655
|
+
`),process.exit(1));var ro=nt!==void 0?parseInt(nt,10):void 0,mn=Pe(ce,{modelPath:et,reranker:B.reranker,corpusPath:B.corpus,reasoningMode:me,nCtx:ro,outputDir:tt}),v=mn.config,be=mn.origin,hi=B["findings-budget"]?parseInt(B["findings-budget"],10):void 0,un=We(v.model.path,"llm"),dn=We(v.model.reranker,"reranker"),Zr=un.path,eo=dn.path,mi=v.model.nCtx??32768;hn&&bn(!0);no&&xn(!0);var fi=!no&&!hn;if(fi)try{N.closeSync(2),N.openSync(process.platform==="win32"?"\\\\.\\NUL":"/dev/null","w")}catch{}var gi=3,yi=10,pn=new Map;function*to(t,e){let n=pn.get(t);if(n)return n;let{cwd:r,pattern:o}=ci(t),s=o??"**/*.{md,mdx}",i=ue.join(r,".gitignore"),a=N.existsSync(i)?ui().add(N.readFileSync(i,"utf8")):null,p=N.globSync(s,{cwd:r}),l=(a?p.filter(k=>!a.ignores(k)):p).sort();l.length===0&&(process.stderr.write(`Error: no .md(x) files matched: ${r}/${s}
|
|
656
|
+
`),process.exit(1)),e.send({type:"weights:label",label:`Indexing corpus (${l.length} files)\u2026`});let u=[];for(let k=0;k<l.length;k++){let M=l[k];e.send({type:"weights:label",label:`Indexing: ${M} (${k+1}/${l.length})`}),yield*Le(()=>new Promise(H=>{setImmediate(()=>{try{u.push({name:M,content:N.readFileSync(ue.join(r,M),"utf8")})}catch{}H()})}))}e.send({type:"weights:label",label:"Chunking corpus\u2026"}),yield*Le(()=>new Promise(k=>setImmediate(k)));let h=li(u),x={resources:u,chunks:h};return pn.set(t,x),x}function Ze(t){let e=[];if(t.sources.corpusPath){let n=pn.get(t.sources.corpusPath);n&&e.push(new ai(n.resources,n.chunks,{grep:{maxResults:50,lineMaxChars:200},readFile:{defaultMaxLines:100}}))}return t.sources.tavilyKey&&e.push(new ii(new oi(t.sources.tavilyKey),{topN:5,fetch:{maxChars:3e3,topK:5,timeout:1e4,tokenBudget:1200}})),e}function ln(t){if(t.length===0)return"";let e=["Available research sources:"],n=!1;for(let r of t){let o=r;if(typeof o.promptData=="function"){let s=o.promptData();e.push("","## Local corpus"),e.push("Files and top-level topics (full-text searchable via grep/read/search tools):"),s.toc&&e.push(s.toc)}else r.name==="web"&&(n=!0)}return n&&(e.push("","## Web search"),e.push("web search is available for live web queries (web_search + fetch_page tools).")),e.join(`
|
|
657
|
+
`)}var cn=t=>t instanceof Error?t.message:String(t),bi=t=>t instanceof Error?t.stack??t.message:String(t);Xs(function*(){let t=ue.basename(Zr).replace(/-Q\w+\.gguf$/,""),e=ue.basename(eo).replace(/-q\w+\.gguf$/i,""),n=Et&&!hn;n||(st(),st(`${At.bold} Deep Research${At.reset}`),st());let r=vn(),o=Zs(),s=[un,dn].filter(c=>c.entry!==null&&!N.existsSync(c.path)).map(c=>({id:c.entry.id,label:c.entry.label,sizeBytes:c.entry.sizeBytes})),i=null;if(n){let c=yield*Le(()=>Promise.resolve().then(()=>(Xr(),Jr))),m=[{type:"config:loaded",config:v,origin:be,path:mn.path}];s.length>0&&m.push({type:"download:plan",entries:s}),i=c.render(r,d=>o.send(d),m),yield*an(()=>{i?.unmount()})}else r.subscribe(c=>{kn(c.type,c)});function*a(c){if(N.existsSync(c.path))return c.path;if(!c.entry)throw new Error(`Model not found: ${c.path}. Pass --model <path> or use /model <path> to set a local .gguf file.`);let m=c.entry;return r.send({type:"download:start",id:m.id,label:m.label,sizeBytes:m.sizeBytes}),yield*Le(()=>Kn(m,{onProgress:(d,f,w)=>{r.send({type:"download:progress",id:m.id,got:d,total:f,url:w})}})),r.send({type:"download:complete",id:m.id}),c.path}function p(c){let m=c.filter(d=>d.entry!==null&&!N.existsSync(d.path)).map(d=>({id:d.entry.id,label:d.entry.label,sizeBytes:d.entry.sizeBytes}));m.length>0&&r.send({type:"download:plan",entries:m})}function*l(){for(let c of yield*Ee(o)){if(c.type==="quit"||c.type==="set_model_path"||c.type==="set_reranker_path")return yield*Ee.next(),c;yield*Ee.next()}return{type:"quit"}}let u=un,h=Zr,x=t,k=dn,M=eo,H=e,R=null,g=null,Q=!0;for(;R===null||g===null;){let c="llm";try{Q||p([u,k]),Q=!1,c="llm",yield*a(u),c="reranker",yield*a(k),c="llm",r.send({type:"weights:start",label:`Loading ${x}\u2026`}),R=yield*Le(()=>ti({modelPath:h,nCtx:mi,nSeqMax:64,typeK:"q4_0",typeV:"q4_0"})),c="reranker",r.send({type:"weights:label",label:`Loading ${H}\u2026`}),g=yield*Le(()=>si(M,{nSeqMax:8,nCtx:16384}))}catch(m){if(R){try{R.dispose?.()}catch{}R=null}g=null,r.send({type:"boot:error",kind:c,message:cn(m)});let d=yield*l();d.type==="quit"&&(i?.unmount(),process.exit(0)),d.type==="set_model_path"?(Ie({model:{path:d.path}},ce),u=We(d.path,"llm"),h=u.path,x=u.entry?.label??ue.basename(h)):(Ie({model:{reranker:d.path}},ce),k=We(d.path,"reranker"),M=k.path,H=k.entry?.label??ue.basename(M));let f=Pe(ce,{modelPath:d.type==="set_model_path"?d.path:et,reranker:d.type==="set_reranker_path"?d.path:B.reranker,corpusPath:B.corpus,reasoningMode:me,outputDir:tt,nCtx:ro});v=f.config,be=f.origin}}yield*an(()=>{g.dispose()}),r.send({type:"weights:done"});let L=fe(v.sources.outputDir||process.cwd());N.mkdirSync(L,{recursive:!0});let Y=new Date().toISOString().replace(/[:.]/g,"-").replace("Z",""),V=ue.join(L,`trace-${Y}.jsonl`),Z=N.openSync(V,"w"),te=new ri(Z);yield*an(()=>{te.flush();try{N.closeSync(Z)}catch{}});let ie=new ct,{session:W,events:C}=yield*ni(R,{traceWriter:te});if(yield*ei(function*(){for(let c of yield*Ee(C))ie.handle(c),r.send(c),yield*Ee.next()}),v.sources.corpusPath){let c=yield*to(v.sources.corpusPath,r);r.send({type:"corpus:indexed",corpusPath:v.sources.corpusPath,fileCount:c.resources.length,chunkCount:c.chunks.length})}r.send({type:"ui:composer"});let Fe={verifyCount:gi,maxTurns:yi,findingsMaxChars:hi,reasoningMode:v.defaults.reasoningMode};function de(c,m){let d=v.sources.outputDir??process.cwd();ie.start({outputDir:d,query:c,mode:m})}if(!n){he||(process.stderr.write(`Non-TTY mode requires --query.
|
|
658
|
+
`),process.exit(2));let c=Ze(v);c.length===0&&(process.stderr.write(`No source configured. Set TAVILY_API_KEY, pass --corpus <dir>, or store one in harness.json.
|
|
659
|
+
`),process.exit(2)),de(he,v.defaults.reasoningMode),yield*Hn(he,W,c,g,Fe);return}let b=null;if(he){let c=v.defaults.reasoningMode,m=performance.now();yield*C.send({type:"plan:start",query:he,mode:c});let d=yield*Me(he,W,{reasoningMode:c});d.intent==="passthrough"?(de(he,c),yield*_e(he,W,d,m),yield*C.send({type:"ui:composer"})):(b={plan:d,query:he,mode:c,wallStartMs:m},yield*C.send({type:"ui:plan_review"}))}for(let c of yield*Ee(o))try{if(c.type==="quit")break;if(c.type==="set_tavily_key"){v={...v,sources:{...v.sources,tavilyKey:c.key}};let m=Ie({sources:{tavilyKey:c.key}},ce),d=Pe(ce,{modelPath:et,reranker:B.reranker,corpusPath:B.corpus,reasoningMode:me,outputDir:tt});v=d.config,be=d.origin,yield*C.send({type:"config:updated",config:v,origin:be,savedTo:m.path,gitignored:m.gitignored,skipped:m.skipped})}else if(c.type==="set_output_dir"){let m=c.path?fe(c.path):"",d=Ie({sources:{outputDir:m}},ce),f=Pe(ce,{modelPath:et,reranker:B.reranker,corpusPath:B.corpus,reasoningMode:me,outputDir:tt});v=f.config,be=f.origin,yield*C.send({type:"config:updated",config:v,origin:be,savedTo:d.path,gitignored:d.gitignored,skipped:d.skipped})}else if(c.type==="set_corpus_path"){let m=c.path?fe(c.path):"",d=Ie({sources:{corpusPath:m}},ce),f=Pe(ce,{modelPath:et,reranker:B.reranker,corpusPath:B.corpus,reasoningMode:me,outputDir:tt});if(v=f.config,be=f.origin,yield*C.send({type:"config:updated",config:v,origin:be,savedTo:d.path,gitignored:d.gitignored,skipped:d.skipped}),v.sources.corpusPath){r.send({type:"weights:start",label:"Indexing corpus\u2026"});let w=yield*to(v.sources.corpusPath,r);r.send({type:"corpus:indexed",corpusPath:v.sources.corpusPath,fileCount:w.resources.length,chunkCount:w.chunks.length}),r.send({type:"weights:done"}),yield*C.send({type:"ui:composer"})}}else if(c.type==="submit_query"){let m=performance.now(),d=Ze(v);if(d.length===0){yield*C.send({type:"ui:error",message:"No source configured. Add Tavily key or corpus path."});continue}let f=ln(d);yield*C.send({type:"plan:start",query:c.query,mode:c.mode});let w=yield*Me(c.query,W,{reasoningMode:c.mode,context:f});w.intent==="passthrough"?(de(c.query,c.mode),yield*_e(c.query,W,w,m),yield*C.send({type:"ui:composer"})):w.intent==="clarify"?b={plan:w,query:c.query,mode:c.mode,wallStartMs:m}:(b={plan:w,query:c.query,mode:c.mode,wallStartMs:m},yield*C.send({type:"ui:plan_review"}))}else if(c.type==="submit_clarification"&&b){let{query:m,plan:d,mode:f,wallStartMs:w}=b,rt=Ze(v),Ue=["Prior clarification exchange:",...d.clarifyQuestions.map((P,ne)=>`(${ne+1}) ${P}`),"",`User response: ${c.answer}`,"","Use this exchange to proceed with research if possible."].join(`
|
|
660
|
+
`),ot=[ln(rt),Ue].filter(Boolean).join(`
|
|
661
|
+
|
|
662
|
+
`);yield*C.send({type:"plan:start",query:m,mode:f});let xe=yield*Me(m,W,{reasoningMode:f,context:ot});xe.intent==="passthrough"?(de(m,f),yield*_e(m,W,xe,w),b=null,yield*C.send({type:"ui:composer"})):xe.intent==="clarify"?b={plan:xe,query:m,mode:f,wallStartMs:w}:(b={plan:xe,query:m,mode:f,wallStartMs:w},yield*C.send({type:"ui:plan_review"}))}else if(c.type==="change_mode"&&b){let m=Ze(v),d=ln(m);yield*C.send({type:"plan:start",query:b.query,mode:c.mode});let f=yield*Me(b.query,W,{reasoningMode:c.mode,context:d});f.intent==="passthrough"?(de(b.query,c.mode),yield*_e(b.query,W,f,b.wallStartMs),b=null,yield*C.send({type:"ui:composer"})):f.intent==="clarify"?b={...b,plan:f,mode:c.mode}:(b={...b,plan:f,mode:c.mode},yield*C.send({type:"ui:plan_review"}))}else if(c.type==="accept_plan"&&b){if(b.plan.intent==="clarify"){b=null,yield*C.send({type:"ui:composer"});continue}let m=Ze(v);if(m.length===0){yield*C.send({type:"ui:error",message:"No source configured. Add Tavily key or corpus path."}),b=null;continue}de(b.query,b.mode),yield*Dt(b.query,b.plan,W,m,g,{...Fe,reasoningMode:b.mode},b.wallStartMs),b=null,yield*C.send({type:"ui:composer"})}else c.type==="cancel_plan"?(b=null,yield*C.send({type:"ui:composer"})):c.type==="edit_plan"&&(b=null,yield*C.send({type:"ui:composer",prefill:c.query}))}catch(m){b=null,yield*C.send({type:"ui:error",message:cn(m)})}finally{yield*Ee.next()}}).catch(t=>{process.stderr.write(`Error: ${cn(t)}
|
|
663
|
+
${bi(t)}
|
|
664
|
+
`),process.exit(1)});
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "reasoning.run",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local deep-research agent composer — runs on your machine, zero-config after the first query. Built on @lloyal-labs/*.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"reasoning.run": "bin/run.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin",
|
|
10
|
+
"dist",
|
|
11
|
+
"LICENSE",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "esbuild src/main.ts --bundle --platform=node --target=node22 --format=esm --packages=external --loader:.eta=text --outfile=dist/bundle.mjs --minify --legal-comments=none",
|
|
16
|
+
"build:watch": "esbuild src/main.ts --bundle --platform=node --target=node22 --format=esm --packages=external --loader:.eta=text --outfile=dist/bundle.mjs --watch",
|
|
17
|
+
"start": "npm run build && node bin/run.js",
|
|
18
|
+
"smoke": "tsx src/tui-ink/__bus-smoke.ts && tsx src/tui-ink/__reducer-smoke.ts && tsx src/tui-ink/__config-smoke.ts && tsx src/__download-smoke.ts && tsx src/__rundir-smoke.ts",
|
|
19
|
+
"smoke:visual": "tsx src/tui-ink/__visual-smoke.tsx",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@lloyal-labs/lloyal-agents": "^2.0.0",
|
|
24
|
+
"@lloyal-labs/lloyal.node": "^2.1.0",
|
|
25
|
+
"@lloyal-labs/rig": "^2.0.1",
|
|
26
|
+
"@lloyal-labs/sdk": "^2.0.0",
|
|
27
|
+
"effection": "^4.0.2",
|
|
28
|
+
"eta": "^4.5.1",
|
|
29
|
+
"ignore": "^7.0.5",
|
|
30
|
+
"ink": "^7.0.1",
|
|
31
|
+
"react": "^19.2.5"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^25.3.0",
|
|
35
|
+
"@types/react": "^19.2.14",
|
|
36
|
+
"esbuild": "^0.28.0",
|
|
37
|
+
"tsx": "^4.21.0",
|
|
38
|
+
"typescript": "^5.9.3"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=22"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"deep-research",
|
|
45
|
+
"local-llm",
|
|
46
|
+
"agents",
|
|
47
|
+
"llama.cpp",
|
|
48
|
+
"cli",
|
|
49
|
+
"tui",
|
|
50
|
+
"ink"
|
|
51
|
+
],
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/lloyal-ai/reasoning-run.git"
|
|
55
|
+
},
|
|
56
|
+
"license": "SEE LICENSE IN LICENSE"
|
|
57
|
+
}
|