@researai/deepscientist 1.5.11 → 1.5.12
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/README.md +8 -8
- package/bin/ds.js +358 -61
- package/docs/en/00_QUICK_START.md +35 -3
- package/docs/en/01_SETTINGS_REFERENCE.md +11 -0
- package/docs/en/02_START_RESEARCH_GUIDE.md +68 -4
- package/docs/en/09_DOCTOR.md +28 -3
- package/docs/en/12_GUIDED_WORKFLOW_TOUR.md +21 -2
- package/docs/en/15_CODEX_PROVIDER_SETUP.md +284 -0
- package/docs/en/README.md +4 -0
- package/docs/zh/00_QUICK_START.md +34 -2
- package/docs/zh/01_SETTINGS_REFERENCE.md +11 -0
- package/docs/zh/02_START_RESEARCH_GUIDE.md +69 -3
- package/docs/zh/09_DOCTOR.md +28 -1
- package/docs/zh/12_GUIDED_WORKFLOW_TOUR.md +21 -2
- package/docs/zh/15_CODEX_PROVIDER_SETUP.md +285 -0
- package/docs/zh/README.md +4 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/deepscientist/__init__.py +1 -1
- package/src/deepscientist/bash_exec/monitor.py +7 -5
- package/src/deepscientist/bash_exec/service.py +84 -21
- package/src/deepscientist/channels/local.py +3 -3
- package/src/deepscientist/channels/qq.py +7 -7
- package/src/deepscientist/channels/relay.py +7 -7
- package/src/deepscientist/channels/weixin_ilink.py +90 -19
- package/src/deepscientist/config/models.py +1 -0
- package/src/deepscientist/config/service.py +121 -20
- package/src/deepscientist/daemon/app.py +314 -6
- package/src/deepscientist/doctor.py +1 -5
- package/src/deepscientist/mcp/server.py +124 -3
- package/src/deepscientist/prompts/builder.py +113 -11
- package/src/deepscientist/quest/service.py +247 -31
- package/src/deepscientist/runners/codex.py +121 -22
- package/src/deepscientist/runners/runtime_overrides.py +6 -0
- package/src/deepscientist/shared.py +33 -14
- package/src/prompts/connectors/qq.md +2 -1
- package/src/prompts/connectors/weixin.md +2 -1
- package/src/prompts/contracts/shared_interaction.md +4 -1
- package/src/prompts/system.md +59 -9
- package/src/skills/analysis-campaign/SKILL.md +46 -6
- package/src/skills/analysis-campaign/references/campaign-plan-template.md +21 -8
- package/src/skills/baseline/SKILL.md +1 -1
- package/src/skills/decision/SKILL.md +1 -1
- package/src/skills/experiment/SKILL.md +1 -1
- package/src/skills/finalize/SKILL.md +1 -1
- package/src/skills/idea/SKILL.md +1 -1
- package/src/skills/intake-audit/SKILL.md +1 -1
- package/src/skills/rebuttal/SKILL.md +74 -1
- package/src/skills/rebuttal/references/response-letter-template.md +55 -11
- package/src/skills/review/SKILL.md +118 -1
- package/src/skills/review/references/experiment-todo-template.md +23 -0
- package/src/skills/review/references/review-report-template.md +16 -0
- package/src/skills/review/references/revision-log-template.md +4 -0
- package/src/skills/scout/SKILL.md +1 -1
- package/src/skills/write/SKILL.md +168 -7
- package/src/skills/write/references/paper-experiment-matrix-template.md +131 -0
- package/src/tui/package.json +1 -1
- package/src/ui/dist/assets/{AiManusChatView-D0mTXG4-.js → AiManusChatView-CnJcXynW.js} +12 -12
- package/src/ui/dist/assets/{AnalysisPlugin-Db0cTXxm.js → AnalysisPlugin-DeyzPEhV.js} +1 -1
- package/src/ui/dist/assets/{CliPlugin-DrV8je02.js → CliPlugin-CB1YODQn.js} +9 -9
- package/src/ui/dist/assets/{CodeEditorPlugin-QXMSCH71.js → CodeEditorPlugin-B-xicq1e.js} +8 -8
- package/src/ui/dist/assets/{CodeViewerPlugin-7hhtWj_E.js → CodeViewerPlugin-DT54ysXa.js} +5 -5
- package/src/ui/dist/assets/{DocViewerPlugin-BWMSnRJe.js → DocViewerPlugin-DQtKT-VD.js} +3 -3
- package/src/ui/dist/assets/{GitDiffViewerPlugin-7J9h9Vy_.js → GitDiffViewerPlugin-hqHbCfnv.js} +20 -20
- package/src/ui/dist/assets/{ImageViewerPlugin-CHJl_0lr.js → ImageViewerPlugin-OcVo33jV.js} +5 -5
- package/src/ui/dist/assets/{LabCopilotPanel-1qSow1es.js → LabCopilotPanel-DdGwhEUV.js} +11 -11
- package/src/ui/dist/assets/{LabPlugin-eQpPPCEp.js → LabPlugin-Ciz1gDaX.js} +2 -2
- package/src/ui/dist/assets/{LatexPlugin-BwRfi89Z.js → LatexPlugin-BhmjNQRC.js} +37 -11
- package/src/ui/dist/assets/{MarkdownViewerPlugin-836PVQWV.js → MarkdownViewerPlugin-BzdVH9Bx.js} +4 -4
- package/src/ui/dist/assets/{MarketplacePlugin-C2y_556i.js → MarketplacePlugin-DmyHspXt.js} +3 -3
- package/src/ui/dist/assets/{NotebookEditor-DIX7Mlzu.js → NotebookEditor-BMXKrDRk.js} +1 -1
- package/src/ui/dist/assets/{NotebookEditor-BRzJbGsn.js → NotebookEditor-BTVYRGkm.js} +11 -11
- package/src/ui/dist/assets/{PdfLoader-DzRaTAlq.js → PdfLoader-CvcjJHXv.js} +1 -1
- package/src/ui/dist/assets/{PdfMarkdownPlugin-DZUfIUnp.js → PdfMarkdownPlugin-DW2ej8Vk.js} +2 -2
- package/src/ui/dist/assets/{PdfViewerPlugin-BwtICzue.js → PdfViewerPlugin-CmlDxbhU.js} +10 -10
- package/src/ui/dist/assets/{SearchPlugin-DHeIAMsx.js → SearchPlugin-DAjQZPSv.js} +1 -1
- package/src/ui/dist/assets/{TextViewerPlugin-C3tCmFox.js → TextViewerPlugin-C-nVAZb_.js} +5 -5
- package/src/ui/dist/assets/{VNCViewer-CQsKVm3t.js → VNCViewer-D7-dIYon.js} +10 -10
- package/src/ui/dist/assets/{bot-BEA2vWuK.js → bot-C_G4WtNI.js} +1 -1
- package/src/ui/dist/assets/{code-XfbSR8K2.js → code-Cd7WfiWq.js} +1 -1
- package/src/ui/dist/assets/{file-content-BjxNaIfy.js → file-content-B57zsL9y.js} +1 -1
- package/src/ui/dist/assets/{file-diff-panel-D_lLVQk0.js → file-diff-panel-DVoheLFq.js} +1 -1
- package/src/ui/dist/assets/{file-socket-D9x_5vlY.js → file-socket-B5kXFxZP.js} +1 -1
- package/src/ui/dist/assets/{image-BhWT33W1.js → image-LLOjkMHF.js} +1 -1
- package/src/ui/dist/assets/{index-Dqj-Mjb4.css → index-BQG-1s2o.css} +40 -2
- package/src/ui/dist/assets/{index--c4iXtuy.js → index-C3r2iGrp.js} +12 -12
- package/src/ui/dist/assets/{index-DZTZ8mWP.js → index-CLQauncb.js} +911 -120
- package/src/ui/dist/assets/{index-PJbSbPTy.js → index-Dxa2eYMY.js} +1 -1
- package/src/ui/dist/assets/{index-BDxipwrC.js → index-hOUOWbW2.js} +2 -2
- package/src/ui/dist/assets/{monaco-K8izTGgo.js → monaco-BGGAEii3.js} +1 -1
- package/src/ui/dist/assets/{pdf-effect-queue-DfBors6y.js → pdf-effect-queue-DlEr1_y5.js} +1 -1
- package/src/ui/dist/assets/{popover-yFK1J4fL.js → popover-CWJbJuYY.js} +1 -1
- package/src/ui/dist/assets/{project-sync-PENr2zcz.js → project-sync-CRJiucYO.js} +18 -4
- package/src/ui/dist/assets/{select-CAbJDfYv.js → select-CoHB7pvH.js} +2 -2
- package/src/ui/dist/assets/{sigma-DEuYJqTl.js → sigma-D5aJWR8J.js} +1 -1
- package/src/ui/dist/assets/{square-check-big-omoSUmcd.js → square-check-big-DUK_mnkS.js} +1 -1
- package/src/ui/dist/assets/{trash--F119N47.js → trash-ChU3SEE3.js} +1 -1
- package/src/ui/dist/assets/{useCliAccess-D31UR23I.js → useCliAccess-BrJBV3tY.js} +1 -1
- package/src/ui/dist/assets/{useFileDiffOverlay-BH6KcMzq.js → useFileDiffOverlay-C2OQaVWc.js} +1 -1
- package/src/ui/dist/assets/{wrap-text-CZ613PM5.js → wrap-text-C7Qqh-om.js} +1 -1
- package/src/ui/dist/assets/{zoom-out-BgDLAv3z.js → zoom-out-rtX0FKya.js} +1 -1
- package/src/ui/dist/index.html +2 -2
package/README.md
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<img src="assets/branding/logo.svg" alt="DeepScientist logo" width="84" />
|
|
3
|
+
DeepScientist
|
|
4
|
+
</h1>
|
|
2
5
|
|
|
3
|
-
<p
|
|
4
|
-
<img src="assets/branding/logo.svg" alt="DeepScientist logo" width="120" />
|
|
5
|
-
</p>
|
|
6
|
-
|
|
7
|
-
<p align="center">
|
|
6
|
+
<p>
|
|
8
7
|
<strong>DeepScientist is not just a long-running autonomous scientific discovery system. It is also a persistent research map that lives on your own machine.</strong>
|
|
9
8
|
</p>
|
|
10
9
|
|
|
11
|
-
<p
|
|
10
|
+
<p>
|
|
12
11
|
Local-first. Open-source. Git-backed. Built for verifiable computational research.
|
|
13
12
|
</p>
|
|
14
13
|
|
|
@@ -99,6 +98,7 @@ If `codex --login` is unavailable, run `codex` once and finish authentication th
|
|
|
99
98
|
For detailed install, troubleshooting, PDF compile, and other launch modes, use:
|
|
100
99
|
|
|
101
100
|
- [Quick Start](docs/en/00_QUICK_START.md)
|
|
101
|
+
- [Codex Provider Setup](docs/en/15_CODEX_PROVIDER_SETUP.md)
|
|
102
102
|
- [Doctor](docs/en/09_DOCTOR.md)
|
|
103
103
|
|
|
104
104
|
## Documentation
|
|
@@ -112,6 +112,7 @@ For detailed install, troubleshooting, PDF compile, and other launch modes, use:
|
|
|
112
112
|
- [Lingzhu / Rokid Guide (English)](docs/en/04_LINGZHU_CONNECTOR_GUIDE.md)
|
|
113
113
|
- [Memory and MCP Guide (English)](docs/en/07_MEMORY_AND_MCP.md)
|
|
114
114
|
- [Settings Reference (English)](docs/en/01_SETTINGS_REFERENCE.md)
|
|
115
|
+
- [Codex Provider Setup (English)](docs/en/15_CODEX_PROVIDER_SETUP.md)
|
|
115
116
|
|
|
116
117
|
## Maintainers
|
|
117
118
|
|
|
@@ -147,7 +148,6 @@ url={https://openreview.net/forum?id=cZFgsLq8Gs}
|
|
|
147
148
|
| [Dr. Claw](https://github.com/OpenLAIR/dr-claw) | Open-source | ✓ | | ✓ | | ✓ | |
|
|
148
149
|
| [FARS](https://analemma.ai/fars/) | Closed-source | ✓ | | | | | |
|
|
149
150
|
| [EvoScientist](https://github.com/EvoScientist/EvoScientist) | Open-source | ✓ | | ✓ | ✓ | ✓ | |
|
|
150
|
-
| [PaperClaw](https://github.com/meowscles69/PaperClaw) | Open-source | | | | | | ✓ |
|
|
151
151
|
| [ScienceClaw](https://github.com/beita6969/ScienceClaw) | Open-source | | | | ✓ | ✓ | |
|
|
152
152
|
| [claude-scholar](https://github.com/Galaxy-Dawn/claude-scholar) | Open-source | ✓ | | ✓ | ✓ | | |
|
|
153
153
|
| [Research-Claw](https://github.com/wentorai/Research-Claw) | Open-source | ✓ | | ✓ | ✓ | ✓ | |
|
package/bin/ds.js
CHANGED
|
@@ -36,15 +36,33 @@ const pythonCommands = new Set([
|
|
|
36
36
|
const UPDATE_PACKAGE_NAME = String(packageJson.name || '@researai/deepscientist').trim() || '@researai/deepscientist';
|
|
37
37
|
const UPDATE_CHECK_TTL_MS = 12 * 60 * 60 * 1000;
|
|
38
38
|
|
|
39
|
-
const optionsWithValues = new Set(['--home', '--host', '--port', '--quest-id', '--mode', '--proxy']);
|
|
39
|
+
const optionsWithValues = new Set(['--home', '--host', '--port', '--quest-id', '--mode', '--proxy', '--codex-profile']);
|
|
40
40
|
|
|
41
|
-
function buildCodexOverrideEnv({ yolo = false } = {}) {
|
|
41
|
+
function buildCodexOverrideEnv({ yolo = false, profile = null } = {}) {
|
|
42
|
+
const normalizedProfile = typeof profile === 'string' ? profile.trim() : '';
|
|
43
|
+
const overrides = {};
|
|
42
44
|
if (!yolo) {
|
|
43
|
-
|
|
45
|
+
if (normalizedProfile) {
|
|
46
|
+
overrides.DEEPSCIENTIST_CODEX_PROFILE = normalizedProfile;
|
|
47
|
+
overrides.DEEPSCIENTIST_CODEX_MODEL = 'inherit';
|
|
48
|
+
}
|
|
49
|
+
return overrides;
|
|
44
50
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
overrides.DEEPSCIENTIST_CODEX_YOLO = '1';
|
|
52
|
+
if (normalizedProfile) {
|
|
53
|
+
overrides.DEEPSCIENTIST_CODEX_PROFILE = normalizedProfile;
|
|
54
|
+
overrides.DEEPSCIENTIST_CODEX_MODEL = 'inherit';
|
|
55
|
+
}
|
|
56
|
+
return overrides;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function readOptionValue(argv, optionName) {
|
|
60
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
61
|
+
if (argv[index] === optionName && argv[index + 1]) {
|
|
62
|
+
return argv[index + 1];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
48
66
|
}
|
|
49
67
|
|
|
50
68
|
function printLauncherHelp() {
|
|
@@ -84,6 +102,7 @@ Launcher flags:
|
|
|
84
102
|
--here Create/use ./DeepScientist under the current working directory as home
|
|
85
103
|
--proxy <url> Use an outbound HTTP/WS proxy for npm and Python runtime traffic
|
|
86
104
|
--yolo Run Codex in YOLO mode: approval_policy=never and sandbox_mode=danger-full-access
|
|
105
|
+
--codex-profile <id> Run DeepScientist with a specific Codex profile, for example \`m27\`
|
|
87
106
|
--quest-id <id> Open the TUI on one quest directly
|
|
88
107
|
|
|
89
108
|
Update:
|
|
@@ -754,6 +773,13 @@ function writeCodexPreflightReport(home, probe) {
|
|
|
754
773
|
const errors = Array.isArray(probe?.errors) ? probe.errors : [];
|
|
755
774
|
const guidance = Array.isArray(probe?.guidance) ? probe.guidance : [];
|
|
756
775
|
const details = probe && typeof probe.details === 'object' ? probe.details : {};
|
|
776
|
+
const profile = typeof details.profile === 'string' ? details.profile.trim() : '';
|
|
777
|
+
const intro = profile
|
|
778
|
+
? `DeepScientist blocked startup because the Codex hello probe did not pass for profile \`${profile}\`. Verify that \`codex --profile ${profile}\` works on this machine and that the profile's provider-specific API key, Base URL, and model configuration are already set up.`
|
|
779
|
+
: 'DeepScientist blocked startup because the Codex hello probe did not pass. In most installs, `npm install -g @researai/deepscientist` also installs the bundled Codex dependency. If `codex` is still missing, repair it with `npm install -g @openai/codex`. Then run `codex --login` (or `codex`), finish authentication, run `ds doctor`, and launch `ds` again.';
|
|
780
|
+
const introZh = profile
|
|
781
|
+
? `DeepScientist 启动前进行了 Codex 可用性检查,但 profile \`${profile}\` 的 hello 探测没有通过。请先确认 \`codex --profile ${profile}\` 在当前机器上可以正常启动,并确保该 profile 依赖的 provider API Key、Base URL 和模型配置都已经在 Codex 中配置好。`
|
|
782
|
+
: 'DeepScientist 启动前进行了 Codex 可用性检查,但 hello 探测没有通过。正常情况下,`npm install -g @researai/deepscientist` 也会一并安装 bundled Codex 依赖;如果此后 `codex` 仍不可用,请再执行 `npm install -g @openai/codex` 修复。然后运行 `codex --login`(或 `codex`)完成认证,再执行 `ds doctor`,最后重新启动 `ds`。';
|
|
757
783
|
const renderItems = (items, tone) =>
|
|
758
784
|
items
|
|
759
785
|
.map(
|
|
@@ -814,8 +840,8 @@ function writeCodexPreflightReport(home, probe) {
|
|
|
814
840
|
<main class="page">
|
|
815
841
|
<section class="panel">
|
|
816
842
|
<h1>DeepScientist could not start Codex</h1>
|
|
817
|
-
<p class="meta"
|
|
818
|
-
<p class="meta"
|
|
843
|
+
<p class="meta">${escapeHtml(intro)}</p>
|
|
844
|
+
<p class="meta">${escapeHtml(introZh)}</p>
|
|
819
845
|
|
|
820
846
|
<h2>Summary</h2>
|
|
821
847
|
<p>${escapeHtml(probe?.summary || 'Codex startup probe failed.')}</p>
|
|
@@ -838,6 +864,10 @@ function writeCodexPreflightReport(home, probe) {
|
|
|
838
864
|
<dt>Model</dt>
|
|
839
865
|
<dd>${escapeHtml(details.model || '')}</dd>
|
|
840
866
|
</dl>
|
|
867
|
+
<dl class="kv">
|
|
868
|
+
<dt>Profile</dt>
|
|
869
|
+
<dd>${escapeHtml(details.profile || '')}</dd>
|
|
870
|
+
</dl>
|
|
841
871
|
<dl class="kv">
|
|
842
872
|
<dt>Exit code</dt>
|
|
843
873
|
<dd>${escapeHtml(details.exit_code ?? '')}</dd>
|
|
@@ -950,6 +980,7 @@ function parseLauncherArgs(argv) {
|
|
|
950
980
|
let daemonOnly = false;
|
|
951
981
|
let skipUpdateCheck = false;
|
|
952
982
|
let yolo = false;
|
|
983
|
+
let codexProfile = null;
|
|
953
984
|
|
|
954
985
|
if (args[0] === 'ui') {
|
|
955
986
|
args.shift();
|
|
@@ -969,6 +1000,7 @@ function parseLauncherArgs(argv) {
|
|
|
969
1000
|
else if (arg === '--daemon-only') daemonOnly = true;
|
|
970
1001
|
else if (arg === '--skip-update-check') skipUpdateCheck = true;
|
|
971
1002
|
else if (arg === '--yolo') yolo = true;
|
|
1003
|
+
else if (arg === '--codex-profile' && args[index + 1]) codexProfile = args[++index];
|
|
972
1004
|
else if (arg === '--host' && args[index + 1]) host = args[++index];
|
|
973
1005
|
else if (arg === '--port' && args[index + 1]) port = Number(args[++index]);
|
|
974
1006
|
else if (arg === '--home' && args[index + 1]) home = path.resolve(args[++index]);
|
|
@@ -994,6 +1026,7 @@ function parseLauncherArgs(argv) {
|
|
|
994
1026
|
daemonOnly,
|
|
995
1027
|
skipUpdateCheck,
|
|
996
1028
|
yolo,
|
|
1029
|
+
codexProfile,
|
|
997
1030
|
};
|
|
998
1031
|
}
|
|
999
1032
|
|
|
@@ -2284,6 +2317,10 @@ function normalizePythonCliArgs(args, home) {
|
|
|
2284
2317
|
if (arg === '--yolo') {
|
|
2285
2318
|
continue;
|
|
2286
2319
|
}
|
|
2320
|
+
if (arg === '--codex-profile') {
|
|
2321
|
+
index += 1;
|
|
2322
|
+
continue;
|
|
2323
|
+
}
|
|
2287
2324
|
normalized.push(arg);
|
|
2288
2325
|
}
|
|
2289
2326
|
return ['--home', home, ...normalized];
|
|
@@ -2492,6 +2529,270 @@ function removeDaemonState(home) {
|
|
|
2492
2529
|
}
|
|
2493
2530
|
}
|
|
2494
2531
|
|
|
2532
|
+
function daemonSupervisorLogPath(home) {
|
|
2533
|
+
return path.join(home, 'logs', 'daemon-supervisor.log');
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2536
|
+
function appendDaemonSupervisorLog(home, message) {
|
|
2537
|
+
try {
|
|
2538
|
+
const logPath = daemonSupervisorLogPath(home);
|
|
2539
|
+
ensureDir(path.dirname(logPath));
|
|
2540
|
+
fs.appendFileSync(logPath, `[${new Date().toISOString()}] ${String(message || '').trim()}\n`, 'utf8');
|
|
2541
|
+
} catch {}
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
function observeManagedDaemonChild(home, child, daemonId) {
|
|
2545
|
+
if (!child || typeof child.once !== 'function') {
|
|
2546
|
+
return;
|
|
2547
|
+
}
|
|
2548
|
+
const normalizedDaemonId = String(daemonId || '').trim() || 'unknown';
|
|
2549
|
+
child.once('exit', (code, signal) => {
|
|
2550
|
+
appendDaemonSupervisorLog(
|
|
2551
|
+
home,
|
|
2552
|
+
`daemon ${normalizedDaemonId} exited with code=${code === null ? 'null' : code} signal=${signal || 'null'}`
|
|
2553
|
+
);
|
|
2554
|
+
});
|
|
2555
|
+
child.once('error', (error) => {
|
|
2556
|
+
appendDaemonSupervisorLog(
|
|
2557
|
+
home,
|
|
2558
|
+
`daemon ${normalizedDaemonId} child process error: ${error instanceof Error ? error.message : String(error)}`
|
|
2559
|
+
);
|
|
2560
|
+
});
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
function encodeSupervisorEnvPayload(envOverrides) {
|
|
2564
|
+
const payload = envOverrides && typeof envOverrides === 'object' && !Array.isArray(envOverrides) ? envOverrides : {};
|
|
2565
|
+
return Buffer.from(JSON.stringify(payload), 'utf8').toString('base64');
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
function decodeSupervisorEnvPayload(rawValue) {
|
|
2569
|
+
const normalized = String(rawValue || '').trim();
|
|
2570
|
+
if (!normalized) {
|
|
2571
|
+
return {};
|
|
2572
|
+
}
|
|
2573
|
+
try {
|
|
2574
|
+
const parsed = JSON.parse(Buffer.from(normalized, 'base64').toString('utf8'));
|
|
2575
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
|
2576
|
+
} catch {
|
|
2577
|
+
return {};
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2581
|
+
function spawnManagedDaemonProcess({ home, runtimePython, host, port, proxy = null, envOverrides = {}, daemonId = null }) {
|
|
2582
|
+
const browserUrl = browserUiUrl(host, port);
|
|
2583
|
+
const daemonBindUrl = bindUiUrl(host, port);
|
|
2584
|
+
const logPath = path.join(home, 'logs', 'daemon.log');
|
|
2585
|
+
ensureDir(path.dirname(logPath));
|
|
2586
|
+
const out = fs.openSync(logPath, 'a');
|
|
2587
|
+
const resolvedDaemonId = String(daemonId || crypto.randomUUID()).trim();
|
|
2588
|
+
const launcherPath = path.join(repoRoot, 'bin', 'ds.js');
|
|
2589
|
+
const child = spawn(
|
|
2590
|
+
runtimePython,
|
|
2591
|
+
[
|
|
2592
|
+
'-m',
|
|
2593
|
+
'deepscientist.cli',
|
|
2594
|
+
'--home',
|
|
2595
|
+
home,
|
|
2596
|
+
...(normalizeProxyUrl(proxy) ? ['--proxy', normalizeProxyUrl(proxy)] : []),
|
|
2597
|
+
'daemon',
|
|
2598
|
+
'--host',
|
|
2599
|
+
host,
|
|
2600
|
+
'--port',
|
|
2601
|
+
String(port),
|
|
2602
|
+
],
|
|
2603
|
+
{
|
|
2604
|
+
cwd: repoRoot,
|
|
2605
|
+
detached: true,
|
|
2606
|
+
stdio: ['ignore', out, out],
|
|
2607
|
+
env: {
|
|
2608
|
+
...process.env,
|
|
2609
|
+
...envOverrides,
|
|
2610
|
+
DEEPSCIENTIST_REPO_ROOT: repoRoot,
|
|
2611
|
+
DEEPSCIENTIST_NODE_BINARY: process.execPath,
|
|
2612
|
+
DEEPSCIENTIST_LAUNCHER_PATH: launcherPath,
|
|
2613
|
+
DS_DAEMON_ID: resolvedDaemonId,
|
|
2614
|
+
DS_DAEMON_MANAGED_BY: 'ds-launcher',
|
|
2615
|
+
},
|
|
2616
|
+
}
|
|
2617
|
+
);
|
|
2618
|
+
child.unref();
|
|
2619
|
+
const statePayload = {
|
|
2620
|
+
pid: child.pid,
|
|
2621
|
+
host,
|
|
2622
|
+
port,
|
|
2623
|
+
url: browserUrl,
|
|
2624
|
+
bind_url: daemonBindUrl,
|
|
2625
|
+
log_path: logPath,
|
|
2626
|
+
started_at: new Date().toISOString(),
|
|
2627
|
+
home: normalizeHomePath(home),
|
|
2628
|
+
daemon_id: resolvedDaemonId,
|
|
2629
|
+
};
|
|
2630
|
+
writeDaemonState(home, statePayload);
|
|
2631
|
+
return {
|
|
2632
|
+
child,
|
|
2633
|
+
statePayload,
|
|
2634
|
+
browserUrl,
|
|
2635
|
+
bindUrl: daemonBindUrl,
|
|
2636
|
+
logPath,
|
|
2637
|
+
};
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
function spawnDaemonSupervisor({ home, runtimePython, host, port, proxy = null, envOverrides = {}, daemonId }) {
|
|
2641
|
+
const launcherPath = resolveLauncherPath() || path.join(repoRoot, 'bin', 'ds.js');
|
|
2642
|
+
const args = [
|
|
2643
|
+
launcherPath,
|
|
2644
|
+
'--daemon-supervisor',
|
|
2645
|
+
'--home',
|
|
2646
|
+
home,
|
|
2647
|
+
'--runtime-python',
|
|
2648
|
+
runtimePython,
|
|
2649
|
+
'--host',
|
|
2650
|
+
host,
|
|
2651
|
+
'--port',
|
|
2652
|
+
String(port),
|
|
2653
|
+
'--daemon-id',
|
|
2654
|
+
String(daemonId || '').trim(),
|
|
2655
|
+
];
|
|
2656
|
+
const normalizedProxy = normalizeProxyUrl(proxy);
|
|
2657
|
+
if (normalizedProxy) {
|
|
2658
|
+
args.push('--proxy', normalizedProxy);
|
|
2659
|
+
}
|
|
2660
|
+
const envPayload = encodeSupervisorEnvPayload(envOverrides);
|
|
2661
|
+
if (envPayload) {
|
|
2662
|
+
args.push('--env-json', envPayload);
|
|
2663
|
+
}
|
|
2664
|
+
const child = spawn(process.execPath, args, {
|
|
2665
|
+
cwd: repoRoot,
|
|
2666
|
+
detached: true,
|
|
2667
|
+
stdio: 'ignore',
|
|
2668
|
+
env: {
|
|
2669
|
+
...process.env,
|
|
2670
|
+
DEEPSCIENTIST_REPO_ROOT: repoRoot,
|
|
2671
|
+
DEEPSCIENTIST_NODE_BINARY: process.execPath,
|
|
2672
|
+
DEEPSCIENTIST_LAUNCHER_PATH: launcherPath,
|
|
2673
|
+
},
|
|
2674
|
+
});
|
|
2675
|
+
child.unref();
|
|
2676
|
+
return child.pid || null;
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
function parseDaemonSupervisorArgs(argv) {
|
|
2680
|
+
const args = [...argv];
|
|
2681
|
+
let home = null;
|
|
2682
|
+
let runtimePython = null;
|
|
2683
|
+
let host = '0.0.0.0';
|
|
2684
|
+
let port = 20999;
|
|
2685
|
+
let proxy = null;
|
|
2686
|
+
let daemonId = null;
|
|
2687
|
+
let envJson = '';
|
|
2688
|
+
|
|
2689
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
2690
|
+
const arg = args[index];
|
|
2691
|
+
if (arg === '--home' && args[index + 1]) home = path.resolve(args[++index]);
|
|
2692
|
+
else if (arg === '--runtime-python' && args[index + 1]) runtimePython = args[++index];
|
|
2693
|
+
else if (arg === '--host' && args[index + 1]) host = args[++index];
|
|
2694
|
+
else if (arg === '--port' && args[index + 1]) port = Number(args[++index]);
|
|
2695
|
+
else if (arg === '--proxy' && args[index + 1]) proxy = args[++index];
|
|
2696
|
+
else if (arg === '--daemon-id' && args[index + 1]) daemonId = args[++index];
|
|
2697
|
+
else if (arg === '--env-json' && args[index + 1]) envJson = args[++index];
|
|
2698
|
+
else if (arg === '--help' || arg === '-h') return { help: true };
|
|
2699
|
+
else return null;
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
if (!home || !runtimePython || !daemonId || !Number.isFinite(port) || port <= 0) {
|
|
2703
|
+
return null;
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
return {
|
|
2707
|
+
help: false,
|
|
2708
|
+
home,
|
|
2709
|
+
runtimePython,
|
|
2710
|
+
host,
|
|
2711
|
+
port,
|
|
2712
|
+
proxy,
|
|
2713
|
+
daemonId,
|
|
2714
|
+
envOverrides: decodeSupervisorEnvPayload(envJson),
|
|
2715
|
+
};
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2718
|
+
async function daemonSupervisorMain(rawArgs) {
|
|
2719
|
+
const options = parseDaemonSupervisorArgs(rawArgs);
|
|
2720
|
+
if (!options) {
|
|
2721
|
+
console.error('Invalid daemon supervisor arguments.');
|
|
2722
|
+
process.exit(1);
|
|
2723
|
+
}
|
|
2724
|
+
if (options.help) {
|
|
2725
|
+
process.exit(0);
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2728
|
+
const home = options.home;
|
|
2729
|
+
let trackedDaemonId = String(options.daemonId || '').trim();
|
|
2730
|
+
let restartBackoffMs = 1000;
|
|
2731
|
+
appendDaemonSupervisorLog(home, `supervisor started for daemon ${trackedDaemonId}`);
|
|
2732
|
+
|
|
2733
|
+
while (true) {
|
|
2734
|
+
const state = readDaemonState(home);
|
|
2735
|
+
if (!state) {
|
|
2736
|
+
appendDaemonSupervisorLog(home, 'daemon state removed; supervisor exiting');
|
|
2737
|
+
return;
|
|
2738
|
+
}
|
|
2739
|
+
if (state.shutdown_requested_at) {
|
|
2740
|
+
appendDaemonSupervisorLog(home, 'managed shutdown requested; supervisor exiting');
|
|
2741
|
+
return;
|
|
2742
|
+
}
|
|
2743
|
+
const stateHome = normalizeHomePath(state.home || home);
|
|
2744
|
+
if (stateHome !== normalizeHomePath(home)) {
|
|
2745
|
+
appendDaemonSupervisorLog(home, `daemon state home changed to ${stateHome}; supervisor exiting`);
|
|
2746
|
+
return;
|
|
2747
|
+
}
|
|
2748
|
+
const stateDaemonId = String(state.daemon_id || '').trim();
|
|
2749
|
+
if (trackedDaemonId && stateDaemonId && stateDaemonId !== trackedDaemonId) {
|
|
2750
|
+
appendDaemonSupervisorLog(home, `daemon id changed to ${stateDaemonId}; supervisor exiting`);
|
|
2751
|
+
return;
|
|
2752
|
+
}
|
|
2753
|
+
const health = await fetchHealth(state.url || browserUiUrl(options.host, options.port));
|
|
2754
|
+
if (health && health.status === 'ok' && healthMatchesManagedState({ health, state, home })) {
|
|
2755
|
+
restartBackoffMs = 1000;
|
|
2756
|
+
await sleep(2500);
|
|
2757
|
+
continue;
|
|
2758
|
+
}
|
|
2759
|
+
if (state.pid && isPidAlive(state.pid)) {
|
|
2760
|
+
await sleep(2500);
|
|
2761
|
+
continue;
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
appendDaemonSupervisorLog(
|
|
2765
|
+
home,
|
|
2766
|
+
`daemon ${stateDaemonId || trackedDaemonId || 'unknown'} is not healthy; attempting restart`
|
|
2767
|
+
);
|
|
2768
|
+
try {
|
|
2769
|
+
const restarted = spawnManagedDaemonProcess({
|
|
2770
|
+
home,
|
|
2771
|
+
runtimePython: options.runtimePython,
|
|
2772
|
+
host: options.host,
|
|
2773
|
+
port: options.port,
|
|
2774
|
+
proxy: options.proxy,
|
|
2775
|
+
envOverrides: options.envOverrides,
|
|
2776
|
+
});
|
|
2777
|
+
trackedDaemonId = String(restarted.statePayload.daemon_id || '').trim();
|
|
2778
|
+
observeManagedDaemonChild(home, restarted.child, trackedDaemonId);
|
|
2779
|
+
appendDaemonSupervisorLog(
|
|
2780
|
+
home,
|
|
2781
|
+
`restarted daemon ${trackedDaemonId} with pid ${restarted.statePayload.pid}`
|
|
2782
|
+
);
|
|
2783
|
+
restartBackoffMs = 1000;
|
|
2784
|
+
await sleep(2500);
|
|
2785
|
+
} catch (error) {
|
|
2786
|
+
appendDaemonSupervisorLog(
|
|
2787
|
+
home,
|
|
2788
|
+
`restart failed: ${error instanceof Error ? error.message : String(error)}`
|
|
2789
|
+
);
|
|
2790
|
+
await sleep(restartBackoffMs);
|
|
2791
|
+
restartBackoffMs = Math.min(restartBackoffMs * 2, 30000);
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2495
2796
|
function sleep(ms) {
|
|
2496
2797
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2497
2798
|
}
|
|
@@ -2663,6 +2964,13 @@ async function stopDaemon(home) {
|
|
|
2663
2964
|
}
|
|
2664
2965
|
}
|
|
2665
2966
|
|
|
2967
|
+
if (state) {
|
|
2968
|
+
writeDaemonState(home, {
|
|
2969
|
+
...state,
|
|
2970
|
+
shutdown_requested_at: new Date().toISOString(),
|
|
2971
|
+
});
|
|
2972
|
+
}
|
|
2973
|
+
|
|
2666
2974
|
let stopped = false;
|
|
2667
2975
|
|
|
2668
2976
|
if (healthyBefore) {
|
|
@@ -3253,61 +3561,36 @@ async function startDaemon(home, runtimePython, host, port, proxy = null, envOve
|
|
|
3253
3561
|
}
|
|
3254
3562
|
|
|
3255
3563
|
ensureNodeBundle('src/ui', 'dist/index.html');
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
ensureDir(path.dirname(logPath));
|
|
3259
|
-
const out = fs.openSync(logPath, 'a');
|
|
3260
|
-
const daemonId = crypto.randomUUID();
|
|
3261
|
-
const child = spawn(
|
|
3564
|
+
const startedProcess = spawnManagedDaemonProcess({
|
|
3565
|
+
home,
|
|
3262
3566
|
runtimePython,
|
|
3263
|
-
[
|
|
3264
|
-
'-m',
|
|
3265
|
-
'deepscientist.cli',
|
|
3266
|
-
'--home',
|
|
3267
|
-
home,
|
|
3268
|
-
...(normalizeProxyUrl(proxy) ? ['--proxy', normalizeProxyUrl(proxy)] : []),
|
|
3269
|
-
'daemon',
|
|
3270
|
-
'--host',
|
|
3271
|
-
host,
|
|
3272
|
-
'--port',
|
|
3273
|
-
String(port),
|
|
3274
|
-
],
|
|
3275
|
-
{
|
|
3276
|
-
cwd: repoRoot,
|
|
3277
|
-
detached: true,
|
|
3278
|
-
stdio: ['ignore', out, out],
|
|
3279
|
-
env: {
|
|
3280
|
-
...process.env,
|
|
3281
|
-
...envOverrides,
|
|
3282
|
-
DEEPSCIENTIST_REPO_ROOT: repoRoot,
|
|
3283
|
-
DEEPSCIENTIST_NODE_BINARY: process.execPath,
|
|
3284
|
-
DEEPSCIENTIST_LAUNCHER_PATH: path.join(repoRoot, 'bin', 'ds.js'),
|
|
3285
|
-
DS_DAEMON_ID: daemonId,
|
|
3286
|
-
DS_DAEMON_MANAGED_BY: 'ds-launcher',
|
|
3287
|
-
},
|
|
3288
|
-
}
|
|
3289
|
-
);
|
|
3290
|
-
child.unref();
|
|
3291
|
-
const statePayload = {
|
|
3292
|
-
pid: child.pid,
|
|
3293
3567
|
host,
|
|
3294
3568
|
port,
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
home: normalizeHomePath(home),
|
|
3300
|
-
daemon_id: daemonId,
|
|
3301
|
-
};
|
|
3302
|
-
writeDaemonState(home, statePayload);
|
|
3569
|
+
proxy,
|
|
3570
|
+
envOverrides,
|
|
3571
|
+
});
|
|
3572
|
+
const logPath = startedProcess.logPath;
|
|
3303
3573
|
|
|
3304
3574
|
for (let attempt = 0; attempt < 60; attempt += 1) {
|
|
3305
3575
|
const health = await fetchHealth(browserUrl);
|
|
3306
3576
|
if (health && health.status === 'ok') {
|
|
3307
|
-
|
|
3308
|
-
|
|
3577
|
+
const liveState = readDaemonState(home);
|
|
3578
|
+
if (!healthMatchesManagedState({ health, state: liveState, home })) {
|
|
3579
|
+
console.error(daemonIdentityError({ url: browserUrl, home, health, state: liveState }));
|
|
3309
3580
|
process.exit(1);
|
|
3310
3581
|
}
|
|
3582
|
+
const supervisorPid = spawnDaemonSupervisor({
|
|
3583
|
+
home,
|
|
3584
|
+
runtimePython,
|
|
3585
|
+
host,
|
|
3586
|
+
port,
|
|
3587
|
+
proxy,
|
|
3588
|
+
envOverrides,
|
|
3589
|
+
daemonId: String((liveState || {}).daemon_id || ''),
|
|
3590
|
+
});
|
|
3591
|
+
if (supervisorPid) {
|
|
3592
|
+
appendDaemonSupervisorLog(home, `supervisor started with pid ${supervisorPid}`);
|
|
3593
|
+
}
|
|
3311
3594
|
return { url: browserUrl, bindUrl: daemonBindUrl, reused: false };
|
|
3312
3595
|
}
|
|
3313
3596
|
await sleep(250);
|
|
@@ -3380,11 +3663,18 @@ function handleCodexPreflightFailure(error) {
|
|
|
3380
3663
|
}
|
|
3381
3664
|
}
|
|
3382
3665
|
console.error(`${warningLabel} Recommended fix:`);
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3666
|
+
const guidance = Array.isArray(error.probe?.guidance) && error.probe.guidance.length > 0
|
|
3667
|
+
? error.probe.guidance
|
|
3668
|
+
: [
|
|
3669
|
+
'In most installs, `npm install -g @researai/deepscientist` also installs the bundled Codex dependency.',
|
|
3670
|
+
'If `codex` is still missing, run `npm install -g @openai/codex`.',
|
|
3671
|
+
'Run `codex --login` (or `codex`) and finish authentication.',
|
|
3672
|
+
'Run `ds doctor` and confirm the Codex check passes.',
|
|
3673
|
+
'Run `ds` again.',
|
|
3674
|
+
];
|
|
3675
|
+
guidance.forEach((item, index) => {
|
|
3676
|
+
console.error(`${warningLabel} ${index + 1}. ${item}`);
|
|
3677
|
+
});
|
|
3388
3678
|
openBrowser(error.reportUrl);
|
|
3389
3679
|
process.exit(1);
|
|
3390
3680
|
return true;
|
|
@@ -3712,7 +4002,7 @@ async function launcherMain(rawArgs) {
|
|
|
3712
4002
|
|
|
3713
4003
|
const pythonRuntime = ensurePythonRuntime(home);
|
|
3714
4004
|
const runtimePython = pythonRuntime.runtimePython;
|
|
3715
|
-
const codexOverrideEnv = buildCodexOverrideEnv({ yolo: options.yolo });
|
|
4005
|
+
const codexOverrideEnv = buildCodexOverrideEnv({ yolo: options.yolo, profile: options.codexProfile });
|
|
3716
4006
|
ensureInitialized(home, runtimePython);
|
|
3717
4007
|
if (await maybeHandleStartupUpdate(home, rawArgs, options)) {
|
|
3718
4008
|
return true;
|
|
@@ -3765,6 +4055,10 @@ async function launcherMain(rawArgs) {
|
|
|
3765
4055
|
|
|
3766
4056
|
async function main() {
|
|
3767
4057
|
const args = process.argv.slice(2);
|
|
4058
|
+
if (args[0] === '--daemon-supervisor') {
|
|
4059
|
+
await daemonSupervisorMain(args.slice(1));
|
|
4060
|
+
return;
|
|
4061
|
+
}
|
|
3768
4062
|
const positional = findFirstPositionalArg(args);
|
|
3769
4063
|
if (positional && positional.value === 'update') {
|
|
3770
4064
|
await updateMain(args);
|
|
@@ -3786,7 +4080,10 @@ async function main() {
|
|
|
3786
4080
|
const home = resolveHome(args);
|
|
3787
4081
|
const pythonRuntime = ensurePythonRuntime(home);
|
|
3788
4082
|
const runtimePython = pythonRuntime.runtimePython;
|
|
3789
|
-
const codexOverrideEnv = buildCodexOverrideEnv({
|
|
4083
|
+
const codexOverrideEnv = buildCodexOverrideEnv({
|
|
4084
|
+
yolo: args.includes('--yolo'),
|
|
4085
|
+
profile: readOptionValue(args, '--codex-profile'),
|
|
4086
|
+
});
|
|
3790
4087
|
if (positional.value === 'run' || positional.value === 'daemon') {
|
|
3791
4088
|
maybePrintOptionalLatexNotice(home);
|
|
3792
4089
|
}
|
|
@@ -36,7 +36,9 @@ See the full notice here:
|
|
|
36
36
|
Prepare these first:
|
|
37
37
|
|
|
38
38
|
- Node.js `>=18.18` and npm `>=9`; install them from the official download page: https://nodejs.org/en/download
|
|
39
|
-
-
|
|
39
|
+
- one working Codex path:
|
|
40
|
+
- default OpenAI login path: `codex --login` (or `codex`)
|
|
41
|
+
- provider-backed path: one working Codex profile such as `minimax`, `glm`, `ark`, or `bailian`
|
|
40
42
|
- a model or API credential if your project needs external inference
|
|
41
43
|
- GPU or server access if your experiments are compute-heavy
|
|
42
44
|
- if you plan to run DeepScientist for real work, prepare Docker or another isolated environment and a dedicated non-root user
|
|
@@ -52,6 +54,10 @@ If you are still choosing a coding plan or subscription, these are practical sta
|
|
|
52
54
|
- Alibaba Cloud Bailian Coding Plan: https://help.aliyun.com/zh/model-studio/coding-plan
|
|
53
55
|
- Volcengine Ark Coding Plan: https://www.volcengine.com/docs/82379/1925115?lang=zh
|
|
54
56
|
|
|
57
|
+
If you plan to use a provider-backed Codex profile instead of the default OpenAI login flow, read this next:
|
|
58
|
+
|
|
59
|
+
- [15 Codex Provider Setup](./15_CODEX_PROVIDER_SETUP.md)
|
|
60
|
+
|
|
55
61
|
## 1. Install Node.js and DeepScientist
|
|
56
62
|
|
|
57
63
|
DeepScientist currently supports Linux and macOS only.
|
|
@@ -89,6 +95,10 @@ This installs a lightweight TinyTeX runtime for local paper compilation.
|
|
|
89
95
|
|
|
90
96
|
## 2. Finish Codex Setup Before The First `ds`
|
|
91
97
|
|
|
98
|
+
Choose one of these two paths.
|
|
99
|
+
|
|
100
|
+
### 2.1 Default OpenAI login path
|
|
101
|
+
|
|
92
102
|
Run:
|
|
93
103
|
|
|
94
104
|
```bash
|
|
@@ -103,13 +113,35 @@ codex
|
|
|
103
113
|
|
|
104
114
|
and finish the interactive authentication there.
|
|
105
115
|
|
|
106
|
-
Then verify
|
|
116
|
+
Then verify:
|
|
107
117
|
|
|
108
118
|
```bash
|
|
109
119
|
ds doctor
|
|
110
120
|
```
|
|
111
121
|
|
|
112
|
-
|
|
122
|
+
### 2.2 Provider-backed Codex profile path
|
|
123
|
+
|
|
124
|
+
If you already use a named Codex profile for MiniMax, GLM, Volcengine Ark, Alibaba Bailian, or another provider-backed path, verify that profile first in a terminal:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
codex --profile minimax
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Then run DeepScientist through the same profile:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
ds doctor --codex-profile minimax
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
and later:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
ds --codex-profile minimax
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Replace `minimax` with the real profile name you created, such as `m27`, `glm`, `ark`, or `bailian`.
|
|
143
|
+
|
|
144
|
+
DeepScientist blocks startup until Codex can pass a real hello probe. By default, the runner model in `~/DeepScientist/config/runners.yaml` is `gpt-5.4`. If your profile expects the model to come from the profile itself, use `model: inherit` in `runners.yaml`, or simply launch with `--codex-profile <name>` and let that session inherit the profile-defined model.
|
|
113
145
|
|
|
114
146
|
## 3. Start the Local Runtime
|
|
115
147
|
|
|
@@ -392,6 +392,7 @@ codex:
|
|
|
392
392
|
enabled: true
|
|
393
393
|
binary: codex
|
|
394
394
|
config_dir: ~/.codex
|
|
395
|
+
profile: ""
|
|
395
396
|
model: gpt-5.4
|
|
396
397
|
model_reasoning_effort: xhigh
|
|
397
398
|
approval_policy: on-request
|
|
@@ -439,6 +440,15 @@ claude:
|
|
|
439
440
|
- UI label: `Config directory`
|
|
440
441
|
- Meaning: global runner home for auth and global config.
|
|
441
442
|
|
|
443
|
+
**`profile`**
|
|
444
|
+
|
|
445
|
+
- Type: `string`
|
|
446
|
+
- Default: `""`
|
|
447
|
+
- UI label: `Codex profile`
|
|
448
|
+
- Meaning: optional Codex profile name passed through as `codex --profile <name>`.
|
|
449
|
+
- Use this when your Codex CLI is already configured for a provider-backed setup such as MiniMax, GLM, Volcengine Ark, or Alibaba Bailian.
|
|
450
|
+
- One-off note: you can also leave this field empty and launch with `ds --codex-profile <name>`.
|
|
451
|
+
|
|
442
452
|
**`model`**
|
|
443
453
|
|
|
444
454
|
- Type: `string`
|
|
@@ -446,6 +456,7 @@ claude:
|
|
|
446
456
|
- UI label: `Default model`
|
|
447
457
|
- Meaning: default model used when a project does not override it.
|
|
448
458
|
- Startup note: DeepScientist's Codex readiness probe uses this configured model first. If your Codex account cannot access it, DeepScientist falls back to the current Codex default model and persists `model: inherit`.
|
|
459
|
+
- Provider-profile note: when `profile` is set, `model: inherit` is usually the right choice so the Codex profile itself controls the provider model.
|
|
449
460
|
|
|
450
461
|
**`model_reasoning_effort`**
|
|
451
462
|
|