@juspay/neurolink 9.52.0 → 9.54.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/CHANGELOG.md +12 -0
- package/README.md +19 -0
- package/dist/adapters/tts/cartesiaHandler.d.ts +12 -0
- package/dist/adapters/tts/cartesiaHandler.js +130 -0
- package/dist/agent/directTools.d.ts +2 -2
- package/dist/auth/errors.d.ts +1 -1
- package/dist/auth/middleware/AuthMiddleware.d.ts +1 -1
- package/dist/auth/providers/BaseAuthProvider.d.ts +1 -1
- package/dist/autoresearch/config.d.ts +11 -0
- package/dist/autoresearch/config.js +108 -0
- package/dist/autoresearch/errors.d.ts +40 -0
- package/dist/autoresearch/errors.js +20 -0
- package/dist/autoresearch/index.d.ts +23 -0
- package/dist/autoresearch/index.js +34 -0
- package/dist/autoresearch/phasePolicy.d.ts +9 -0
- package/dist/autoresearch/phasePolicy.js +69 -0
- package/dist/autoresearch/promptCompiler.d.ts +15 -0
- package/dist/autoresearch/promptCompiler.js +120 -0
- package/dist/autoresearch/repoPolicy.d.ts +32 -0
- package/dist/autoresearch/repoPolicy.js +128 -0
- package/dist/autoresearch/resultRecorder.d.ts +20 -0
- package/dist/autoresearch/resultRecorder.js +130 -0
- package/dist/autoresearch/runner.d.ts +10 -0
- package/dist/autoresearch/runner.js +102 -0
- package/dist/autoresearch/stateStore.d.ts +12 -0
- package/dist/autoresearch/stateStore.js +163 -0
- package/dist/autoresearch/summaryParser.d.ts +16 -0
- package/dist/autoresearch/summaryParser.js +94 -0
- package/dist/autoresearch/tools.d.ts +257 -0
- package/dist/autoresearch/tools.js +617 -0
- package/dist/autoresearch/worker.d.ts +71 -0
- package/dist/autoresearch/worker.js +417 -0
- package/dist/browser/neurolink.min.js +340 -326
- package/dist/cli/commands/autoresearch.d.ts +41 -0
- package/dist/cli/commands/autoresearch.js +487 -0
- package/dist/cli/commands/config.d.ts +1 -1
- package/dist/cli/commands/task.d.ts +2 -0
- package/dist/cli/commands/task.js +32 -3
- package/dist/cli/commands/voiceServer.d.ts +6 -0
- package/dist/cli/commands/voiceServer.js +17 -0
- package/dist/cli/parser.js +7 -1
- package/dist/core/baseProvider.js +18 -0
- package/dist/evaluation/errors/EvaluationError.d.ts +1 -1
- package/dist/lib/adapters/tts/cartesiaHandler.d.ts +12 -0
- package/dist/lib/adapters/tts/cartesiaHandler.js +131 -0
- package/dist/lib/agent/directTools.d.ts +2 -2
- package/dist/lib/auth/errors.d.ts +1 -1
- package/dist/lib/auth/middleware/AuthMiddleware.d.ts +1 -1
- package/dist/lib/auth/providers/BaseAuthProvider.d.ts +1 -1
- package/dist/lib/autoresearch/config.d.ts +11 -0
- package/dist/lib/autoresearch/config.js +109 -0
- package/dist/lib/autoresearch/errors.d.ts +40 -0
- package/dist/lib/autoresearch/errors.js +21 -0
- package/dist/lib/autoresearch/index.d.ts +23 -0
- package/dist/lib/autoresearch/index.js +35 -0
- package/dist/lib/autoresearch/phasePolicy.d.ts +9 -0
- package/dist/lib/autoresearch/phasePolicy.js +70 -0
- package/dist/lib/autoresearch/promptCompiler.d.ts +15 -0
- package/dist/lib/autoresearch/promptCompiler.js +121 -0
- package/dist/lib/autoresearch/repoPolicy.d.ts +32 -0
- package/dist/lib/autoresearch/repoPolicy.js +129 -0
- package/dist/lib/autoresearch/resultRecorder.d.ts +20 -0
- package/dist/lib/autoresearch/resultRecorder.js +131 -0
- package/dist/lib/autoresearch/runner.d.ts +10 -0
- package/dist/lib/autoresearch/runner.js +103 -0
- package/dist/lib/autoresearch/stateStore.d.ts +12 -0
- package/dist/lib/autoresearch/stateStore.js +164 -0
- package/dist/lib/autoresearch/summaryParser.d.ts +16 -0
- package/dist/lib/autoresearch/summaryParser.js +95 -0
- package/dist/lib/autoresearch/tools.d.ts +257 -0
- package/dist/lib/autoresearch/tools.js +618 -0
- package/dist/lib/autoresearch/worker.d.ts +71 -0
- package/dist/lib/autoresearch/worker.js +418 -0
- package/dist/lib/core/baseProvider.js +18 -0
- package/dist/lib/evaluation/errors/EvaluationError.d.ts +1 -1
- package/dist/lib/files/fileTools.d.ts +1 -1
- package/dist/lib/neurolink.js +22 -2
- package/dist/lib/providers/azureOpenai.d.ts +4 -1
- package/dist/lib/providers/azureOpenai.js +9 -3
- package/dist/lib/providers/litellm.js +2 -2
- package/dist/lib/providers/openRouter.js +2 -2
- package/dist/lib/providers/openaiCompatible.js +3 -1
- package/dist/lib/server/voice/frameBus.d.ts +8 -0
- package/dist/lib/server/voice/frameBus.js +25 -0
- package/dist/lib/server/voice/turnManager.d.ts +15 -0
- package/dist/lib/server/voice/turnManager.js +36 -0
- package/dist/lib/server/voice/types.d.ts +20 -0
- package/dist/lib/server/voice/types.js +2 -0
- package/dist/lib/server/voice/voiceServerApp.d.ts +1 -0
- package/dist/lib/server/voice/voiceServerApp.js +118 -0
- package/dist/lib/server/voice/voiceWebSocketHandler.d.ts +11 -0
- package/dist/lib/server/voice/voiceWebSocketHandler.js +536 -0
- package/dist/lib/tasks/autoresearchTaskExecutor.d.ts +32 -0
- package/dist/lib/tasks/autoresearchTaskExecutor.js +303 -0
- package/dist/lib/tasks/errors.d.ts +3 -1
- package/dist/lib/tasks/errors.js +1 -0
- package/dist/lib/tasks/taskExecutor.d.ts +4 -2
- package/dist/lib/tasks/taskExecutor.js +8 -1
- package/dist/lib/tasks/taskManager.js +27 -3
- package/dist/lib/tasks/tools/taskTools.d.ts +1 -1
- package/dist/lib/telemetry/attributes.d.ts +15 -0
- package/dist/lib/telemetry/attributes.js +16 -0
- package/dist/lib/telemetry/tracers.d.ts +1 -0
- package/dist/lib/telemetry/tracers.js +1 -0
- package/dist/lib/types/autoresearchTypes.d.ts +194 -0
- package/dist/lib/types/autoresearchTypes.js +18 -0
- package/dist/lib/types/common.d.ts +11 -0
- package/dist/lib/types/index.d.ts +16 -14
- package/dist/lib/types/index.js +21 -17
- package/dist/lib/types/taskTypes.d.ts +38 -0
- package/dist/lib/workflow/config.d.ts +3 -3
- package/dist/neurolink.js +22 -2
- package/dist/providers/azureOpenai.d.ts +4 -1
- package/dist/providers/azureOpenai.js +9 -3
- package/dist/providers/litellm.js +2 -2
- package/dist/providers/openRouter.js +2 -2
- package/dist/providers/openaiCompatible.js +3 -1
- package/dist/rag/errors/RAGError.d.ts +1 -1
- package/dist/server/voice/frameBus.d.ts +8 -0
- package/dist/server/voice/frameBus.js +24 -0
- package/dist/server/voice/public/app.js +275 -0
- package/dist/server/voice/public/index.html +18 -0
- package/dist/server/voice/public/pcm-worklet.js +67 -0
- package/dist/server/voice/public/styles.css +102 -0
- package/dist/server/voice/turnManager.d.ts +15 -0
- package/dist/server/voice/turnManager.js +35 -0
- package/dist/server/voice/types.d.ts +20 -0
- package/dist/server/voice/types.js +1 -0
- package/dist/server/voice/voiceServerApp.d.ts +1 -0
- package/dist/server/voice/voiceServerApp.js +117 -0
- package/dist/server/voice/voiceWebSocketHandler.d.ts +11 -0
- package/dist/server/voice/voiceWebSocketHandler.js +535 -0
- package/dist/tasks/autoresearchTaskExecutor.d.ts +32 -0
- package/dist/tasks/autoresearchTaskExecutor.js +302 -0
- package/dist/tasks/errors.d.ts +3 -1
- package/dist/tasks/errors.js +1 -0
- package/dist/tasks/taskExecutor.d.ts +4 -2
- package/dist/tasks/taskExecutor.js +8 -1
- package/dist/tasks/taskManager.js +27 -3
- package/dist/tasks/tools/taskTools.d.ts +1 -1
- package/dist/telemetry/attributes.d.ts +15 -0
- package/dist/telemetry/attributes.js +16 -0
- package/dist/telemetry/tracers.d.ts +1 -0
- package/dist/telemetry/tracers.js +1 -0
- package/dist/types/autoresearchTypes.d.ts +194 -0
- package/dist/types/autoresearchTypes.js +17 -0
- package/dist/types/common.d.ts +11 -0
- package/dist/types/index.d.ts +16 -14
- package/dist/types/index.js +21 -17
- package/dist/types/taskTypes.d.ts +38 -0
- package/package.json +2 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutoResearch CLI Commands for NeuroLink
|
|
3
|
+
*
|
|
4
|
+
* - neurolink autoresearch init — Initialize autoresearch for a repo
|
|
5
|
+
* - neurolink autoresearch status — Show current research state
|
|
6
|
+
* - neurolink autoresearch results — Show experiment results
|
|
7
|
+
* - neurolink autoresearch run-once — Run one experiment cycle
|
|
8
|
+
* - neurolink autoresearch start — Start a scheduled autoresearch task
|
|
9
|
+
* - neurolink autoresearch pause — Pause a running autoresearch task
|
|
10
|
+
* - neurolink autoresearch resume — Resume a paused autoresearch task
|
|
11
|
+
* - neurolink autoresearch stop — Stop and cancel an autoresearch task
|
|
12
|
+
* - neurolink autoresearch reset — Reset autoresearch state for a repo
|
|
13
|
+
*/
|
|
14
|
+
import type { CommandModule } from "yargs";
|
|
15
|
+
export declare class AutoresearchCommandFactory {
|
|
16
|
+
static createAutoresearchCommands(): CommandModule;
|
|
17
|
+
/**
|
|
18
|
+
* Get a direct TaskStore instance for store operations.
|
|
19
|
+
* Respects the same backend selection as TaskManager so both paths
|
|
20
|
+
* read/write the same store (Redis for bullmq, file for node-timeout).
|
|
21
|
+
*/
|
|
22
|
+
private static getStore;
|
|
23
|
+
private static executeInit;
|
|
24
|
+
private static executeStatus;
|
|
25
|
+
private static executeResults;
|
|
26
|
+
private static executeRunOnce;
|
|
27
|
+
/**
|
|
28
|
+
* Start a scheduled autoresearch task via TaskManager.
|
|
29
|
+
* Reads config.json from .autoresearch/ and creates a TaskManager task.
|
|
30
|
+
*/
|
|
31
|
+
private static executeStart;
|
|
32
|
+
/**
|
|
33
|
+
* Lifecycle operations: pause, resume, stop.
|
|
34
|
+
* Reads from the file task store and updates task status.
|
|
35
|
+
*/
|
|
36
|
+
private static executeLifecycle;
|
|
37
|
+
/**
|
|
38
|
+
* Reset autoresearch state by removing the .autoresearch directory.
|
|
39
|
+
*/
|
|
40
|
+
private static executeReset;
|
|
41
|
+
}
|
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutoResearch CLI Commands for NeuroLink
|
|
3
|
+
*
|
|
4
|
+
* - neurolink autoresearch init — Initialize autoresearch for a repo
|
|
5
|
+
* - neurolink autoresearch status — Show current research state
|
|
6
|
+
* - neurolink autoresearch results — Show experiment results
|
|
7
|
+
* - neurolink autoresearch run-once — Run one experiment cycle
|
|
8
|
+
* - neurolink autoresearch start — Start a scheduled autoresearch task
|
|
9
|
+
* - neurolink autoresearch pause — Pause a running autoresearch task
|
|
10
|
+
* - neurolink autoresearch resume — Resume a paused autoresearch task
|
|
11
|
+
* - neurolink autoresearch stop — Stop and cancel an autoresearch task
|
|
12
|
+
* - neurolink autoresearch reset — Reset autoresearch state for a repo
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
|
|
15
|
+
import { resolve } from "node:path";
|
|
16
|
+
import chalk from "chalk";
|
|
17
|
+
import ora from "ora";
|
|
18
|
+
import { TASK_DEFAULTS } from "../../lib/types/index.js";
|
|
19
|
+
export class AutoresearchCommandFactory {
|
|
20
|
+
static createAutoresearchCommands() {
|
|
21
|
+
return {
|
|
22
|
+
command: "autoresearch <subcommand>",
|
|
23
|
+
describe: "Run automated AI-driven research experiments",
|
|
24
|
+
builder: (yargs) => {
|
|
25
|
+
return yargs
|
|
26
|
+
.command("init <repoPath>", "Initialize autoresearch for a repository", (y) => y
|
|
27
|
+
.positional("repoPath", {
|
|
28
|
+
type: "string",
|
|
29
|
+
description: "Path to the repository",
|
|
30
|
+
demandOption: true,
|
|
31
|
+
})
|
|
32
|
+
.option("tag", {
|
|
33
|
+
type: "string",
|
|
34
|
+
alias: "t",
|
|
35
|
+
description: "Run tag (e.g. apr3)",
|
|
36
|
+
demandOption: true,
|
|
37
|
+
})
|
|
38
|
+
.option("target", {
|
|
39
|
+
type: "string",
|
|
40
|
+
default: "train.py",
|
|
41
|
+
description: "Mutable file(s), comma-separated",
|
|
42
|
+
})
|
|
43
|
+
.option("immutable", {
|
|
44
|
+
type: "string",
|
|
45
|
+
default: "",
|
|
46
|
+
description: "Immutable file(s), comma-separated",
|
|
47
|
+
})
|
|
48
|
+
.option("run-command", {
|
|
49
|
+
type: "string",
|
|
50
|
+
description: "Experiment command to execute",
|
|
51
|
+
demandOption: true,
|
|
52
|
+
})
|
|
53
|
+
.option("metric-name", {
|
|
54
|
+
type: "string",
|
|
55
|
+
default: "val_bpb",
|
|
56
|
+
})
|
|
57
|
+
.option("metric-pattern", {
|
|
58
|
+
type: "string",
|
|
59
|
+
default: "^val_bpb:\\s+([\\d.]+)",
|
|
60
|
+
})
|
|
61
|
+
.option("metric-direction", {
|
|
62
|
+
type: "string",
|
|
63
|
+
choices: ["lower", "higher"],
|
|
64
|
+
default: "lower",
|
|
65
|
+
})
|
|
66
|
+
.option("timeout", { type: "number", default: 600 })
|
|
67
|
+
.option("provider", { type: "string" })
|
|
68
|
+
.option("model", { type: "string" }), async (argv) => {
|
|
69
|
+
await AutoresearchCommandFactory.executeInit(argv);
|
|
70
|
+
})
|
|
71
|
+
.command("status [repoPath]", "Show current research state", (y) => y
|
|
72
|
+
.positional("repoPath", {
|
|
73
|
+
type: "string",
|
|
74
|
+
default: ".",
|
|
75
|
+
})
|
|
76
|
+
.option("format", {
|
|
77
|
+
type: "string",
|
|
78
|
+
choices: ["text", "json"],
|
|
79
|
+
default: "text",
|
|
80
|
+
}), async (argv) => {
|
|
81
|
+
await AutoresearchCommandFactory.executeStatus(argv);
|
|
82
|
+
})
|
|
83
|
+
.command("results [repoPath]", "Show experiment results", (y) => y
|
|
84
|
+
.positional("repoPath", {
|
|
85
|
+
type: "string",
|
|
86
|
+
default: ".",
|
|
87
|
+
})
|
|
88
|
+
.option("last", { type: "number", default: 20 })
|
|
89
|
+
.option("format", {
|
|
90
|
+
type: "string",
|
|
91
|
+
choices: ["text", "json", "table"],
|
|
92
|
+
default: "table",
|
|
93
|
+
}), async (argv) => {
|
|
94
|
+
await AutoresearchCommandFactory.executeResults(argv);
|
|
95
|
+
})
|
|
96
|
+
.command("run-once [repoPath]", "Run one experiment cycle", (y) => y
|
|
97
|
+
.positional("repoPath", {
|
|
98
|
+
type: "string",
|
|
99
|
+
default: ".",
|
|
100
|
+
})
|
|
101
|
+
.option("description", {
|
|
102
|
+
type: "string",
|
|
103
|
+
default: "manual run",
|
|
104
|
+
}), async (argv) => {
|
|
105
|
+
await AutoresearchCommandFactory.executeRunOnce(argv);
|
|
106
|
+
})
|
|
107
|
+
.command("start <repoPath>", "Start a scheduled autoresearch task via TaskManager", (y) => y
|
|
108
|
+
.positional("repoPath", {
|
|
109
|
+
type: "string",
|
|
110
|
+
description: "Path to the repository",
|
|
111
|
+
demandOption: true,
|
|
112
|
+
})
|
|
113
|
+
.option("interval", {
|
|
114
|
+
type: "number",
|
|
115
|
+
default: 300,
|
|
116
|
+
description: "Interval between ticks in seconds",
|
|
117
|
+
})
|
|
118
|
+
.option("max-runs", {
|
|
119
|
+
type: "number",
|
|
120
|
+
description: "Max experiment ticks (omit for unlimited)",
|
|
121
|
+
}), async (argv) => {
|
|
122
|
+
await AutoresearchCommandFactory.executeStart(argv);
|
|
123
|
+
})
|
|
124
|
+
.command("pause <taskId>", "Pause a running autoresearch task", (y) => y.positional("taskId", {
|
|
125
|
+
type: "string",
|
|
126
|
+
description: "Task ID to pause",
|
|
127
|
+
demandOption: true,
|
|
128
|
+
}), async (argv) => {
|
|
129
|
+
await AutoresearchCommandFactory.executeLifecycle(argv.taskId, "pause");
|
|
130
|
+
})
|
|
131
|
+
.command("resume <taskId>", "Resume a paused autoresearch task", (y) => y.positional("taskId", {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "Task ID to resume",
|
|
134
|
+
demandOption: true,
|
|
135
|
+
}), async (argv) => {
|
|
136
|
+
await AutoresearchCommandFactory.executeLifecycle(argv.taskId, "resume");
|
|
137
|
+
})
|
|
138
|
+
.command("stop <taskId>", "Stop and cancel an autoresearch task", (y) => y.positional("taskId", {
|
|
139
|
+
type: "string",
|
|
140
|
+
description: "Task ID to stop",
|
|
141
|
+
demandOption: true,
|
|
142
|
+
}), async (argv) => {
|
|
143
|
+
await AutoresearchCommandFactory.executeLifecycle(argv.taskId, "stop");
|
|
144
|
+
})
|
|
145
|
+
.command("reset [repoPath]", "Reset autoresearch state for a repository", (y) => y.positional("repoPath", {
|
|
146
|
+
type: "string",
|
|
147
|
+
default: ".",
|
|
148
|
+
}), async (argv) => {
|
|
149
|
+
await AutoresearchCommandFactory.executeReset(argv.repoPath);
|
|
150
|
+
})
|
|
151
|
+
.demandCommand(1, "Please specify an autoresearch subcommand");
|
|
152
|
+
},
|
|
153
|
+
handler: () => { },
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get a direct TaskStore instance for store operations.
|
|
158
|
+
* Respects the same backend selection as TaskManager so both paths
|
|
159
|
+
* read/write the same store (Redis for bullmq, file for node-timeout).
|
|
160
|
+
*/
|
|
161
|
+
static async getStore(config) {
|
|
162
|
+
const backendName = config?.backend ?? TASK_DEFAULTS.backend;
|
|
163
|
+
if (backendName === "bullmq") {
|
|
164
|
+
const { RedisTaskStore } = await import("../../lib/tasks/store/redisTaskStore.js");
|
|
165
|
+
const store = new RedisTaskStore(config ?? {});
|
|
166
|
+
await store.initialize();
|
|
167
|
+
return store;
|
|
168
|
+
}
|
|
169
|
+
const { FileTaskStore } = await import("../../lib/tasks/store/fileTaskStore.js");
|
|
170
|
+
const store = new FileTaskStore(config ?? {});
|
|
171
|
+
await store.initialize();
|
|
172
|
+
return store;
|
|
173
|
+
}
|
|
174
|
+
static async executeInit(argv) {
|
|
175
|
+
const spinner = ora("Initializing autoresearch...").start();
|
|
176
|
+
try {
|
|
177
|
+
const repoPath = resolve(argv.repoPath);
|
|
178
|
+
if (!existsSync(repoPath)) {
|
|
179
|
+
spinner.fail(chalk.red(`Repository not found: ${repoPath}`));
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
const { ResearchWorker } = await import("../../lib/autoresearch/worker.js");
|
|
183
|
+
const mutablePaths = argv.target
|
|
184
|
+
.split(",")
|
|
185
|
+
.map((f) => f.trim())
|
|
186
|
+
.filter(Boolean);
|
|
187
|
+
const immutablePaths = argv.immutable
|
|
188
|
+
.split(",")
|
|
189
|
+
.map((f) => f.trim())
|
|
190
|
+
.filter(Boolean);
|
|
191
|
+
const worker = new ResearchWorker({
|
|
192
|
+
repoPath,
|
|
193
|
+
mutablePaths,
|
|
194
|
+
immutablePaths,
|
|
195
|
+
runCommand: argv.runCommand,
|
|
196
|
+
metric: {
|
|
197
|
+
name: argv.metricName,
|
|
198
|
+
direction: argv.metricDirection,
|
|
199
|
+
pattern: argv.metricPattern,
|
|
200
|
+
},
|
|
201
|
+
timeoutMs: argv.timeout * 1000,
|
|
202
|
+
provider: argv.provider,
|
|
203
|
+
model: argv.model,
|
|
204
|
+
});
|
|
205
|
+
const state = await worker.initialize(argv.tag);
|
|
206
|
+
// Persist config for run-once to read
|
|
207
|
+
const configDir = resolve(repoPath, ".autoresearch");
|
|
208
|
+
mkdirSync(configDir, { recursive: true });
|
|
209
|
+
writeFileSync(resolve(configDir, "config.json"), JSON.stringify({
|
|
210
|
+
tag: argv.tag,
|
|
211
|
+
mutablePaths,
|
|
212
|
+
immutablePaths,
|
|
213
|
+
runCommand: argv.runCommand,
|
|
214
|
+
metric: {
|
|
215
|
+
name: argv.metricName,
|
|
216
|
+
direction: argv.metricDirection,
|
|
217
|
+
pattern: argv.metricPattern,
|
|
218
|
+
},
|
|
219
|
+
timeoutMs: argv.timeout * 1000,
|
|
220
|
+
provider: argv.provider,
|
|
221
|
+
model: argv.model,
|
|
222
|
+
}, null, 2), "utf-8");
|
|
223
|
+
spinner.succeed(chalk.green("Autoresearch initialized"));
|
|
224
|
+
console.info(` Branch: ${state.branch} Tag: ${argv.tag} Target: ${mutablePaths.join(", ")}`);
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
spinner.fail(chalk.red("Failed to initialize"));
|
|
228
|
+
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
static async executeStatus(argv) {
|
|
233
|
+
const repoPath = resolve(argv.repoPath);
|
|
234
|
+
const statePath = resolve(repoPath, ".autoresearch", "state.json");
|
|
235
|
+
if (!existsSync(statePath)) {
|
|
236
|
+
console.info(chalk.yellow("Not initialized. Run `neurolink autoresearch init` first."));
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
let state;
|
|
240
|
+
try {
|
|
241
|
+
state = JSON.parse(readFileSync(statePath, "utf-8"));
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
console.error(chalk.red(`Failed to parse state file: ${statePath}`));
|
|
245
|
+
console.error(chalk.dim(err instanceof Error ? err.message : String(err)));
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (argv.format === "json") {
|
|
249
|
+
console.info(JSON.stringify(state, null, 2));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
console.info(` Tag: ${state.tag} Branch: ${state.branch} Phase: ${state.currentPhase}`);
|
|
253
|
+
console.info(` Runs: ${state.runCount} Keeps: ${state.keepCount} Best: ${state.bestMetric ?? "none"}`);
|
|
254
|
+
}
|
|
255
|
+
static async executeResults(argv) {
|
|
256
|
+
const repoPath = resolve(argv.repoPath);
|
|
257
|
+
const configPath = resolve(repoPath, ".autoresearch", "config.json");
|
|
258
|
+
let resultsPath = resolve(repoPath, "results.tsv");
|
|
259
|
+
if (existsSync(configPath)) {
|
|
260
|
+
try {
|
|
261
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
262
|
+
if (config.resultsPath) {
|
|
263
|
+
resultsPath = resolve(repoPath, config.resultsPath);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
/* use default */
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if (!existsSync(resultsPath)) {
|
|
271
|
+
console.info(chalk.yellow("No results file."));
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const lines = readFileSync(resultsPath, "utf-8").trim().split("\n");
|
|
275
|
+
if (lines.length < 2) {
|
|
276
|
+
console.info(chalk.yellow("No results yet."));
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const rows = lines.slice(1).slice(-argv.last);
|
|
280
|
+
if (argv.format === "json") {
|
|
281
|
+
console.info(JSON.stringify(rows.map((l) => l.split("\t")), null, 2));
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
console.info(lines[0]);
|
|
285
|
+
for (const r of rows) {
|
|
286
|
+
console.info(r);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
static async executeRunOnce(argv) {
|
|
290
|
+
const spinner = ora("Running experiment...").start();
|
|
291
|
+
try {
|
|
292
|
+
const repoPath = resolve(argv.repoPath);
|
|
293
|
+
const configPath = resolve(repoPath, ".autoresearch", "config.json");
|
|
294
|
+
if (!existsSync(configPath)) {
|
|
295
|
+
spinner.fail(chalk.red("No config. Run init first."));
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
let configRaw;
|
|
299
|
+
try {
|
|
300
|
+
configRaw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
301
|
+
}
|
|
302
|
+
catch (err) {
|
|
303
|
+
spinner.fail(chalk.red(`Failed to parse config: ${configPath}`));
|
|
304
|
+
console.error(chalk.dim(err instanceof Error ? err.message : String(err)));
|
|
305
|
+
process.exit(1);
|
|
306
|
+
}
|
|
307
|
+
const { ResearchWorker } = await import("../../lib/autoresearch/worker.js");
|
|
308
|
+
if (!configRaw.mutablePaths ||
|
|
309
|
+
!configRaw.runCommand ||
|
|
310
|
+
!configRaw.metric) {
|
|
311
|
+
spinner.fail(chalk.red("Config missing required fields (mutablePaths, runCommand, metric)"));
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
const worker = new ResearchWorker({
|
|
315
|
+
repoPath,
|
|
316
|
+
mutablePaths: configRaw.mutablePaths,
|
|
317
|
+
runCommand: configRaw.runCommand,
|
|
318
|
+
metric: configRaw.metric,
|
|
319
|
+
...configRaw,
|
|
320
|
+
});
|
|
321
|
+
await worker.resume();
|
|
322
|
+
const record = await worker.runExperimentCycle(argv.description);
|
|
323
|
+
const c = record.status === "keep"
|
|
324
|
+
? "green"
|
|
325
|
+
: record.status === "discard"
|
|
326
|
+
? "yellow"
|
|
327
|
+
: "red";
|
|
328
|
+
spinner.succeed(chalk[c](`${record.status}: metric=${record.metric ?? "N/A"} commit=${record.commit}`));
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
spinner.fail(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
332
|
+
process.exit(1);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Start a scheduled autoresearch task via TaskManager.
|
|
337
|
+
* Reads config.json from .autoresearch/ and creates a TaskManager task.
|
|
338
|
+
*/
|
|
339
|
+
static async executeStart(argv) {
|
|
340
|
+
const spinner = ora("Starting autoresearch task...").start();
|
|
341
|
+
try {
|
|
342
|
+
const repoPath = resolve(argv.repoPath);
|
|
343
|
+
const configPath = resolve(repoPath, ".autoresearch", "config.json");
|
|
344
|
+
if (!existsSync(configPath)) {
|
|
345
|
+
spinner.fail(chalk.red("No config. Run `neurolink autoresearch init` first."));
|
|
346
|
+
process.exit(1);
|
|
347
|
+
}
|
|
348
|
+
let configRaw;
|
|
349
|
+
try {
|
|
350
|
+
configRaw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
351
|
+
}
|
|
352
|
+
catch (err) {
|
|
353
|
+
spinner.fail(chalk.red(`Failed to parse config: ${configPath}`));
|
|
354
|
+
console.error(chalk.dim(err instanceof Error ? err.message : String(err)));
|
|
355
|
+
process.exit(1);
|
|
356
|
+
}
|
|
357
|
+
// Dynamic import to avoid pulling NeuroLink into CLI cold path
|
|
358
|
+
const { nanoid } = await import("nanoid");
|
|
359
|
+
if (!configRaw.mutablePaths ||
|
|
360
|
+
!configRaw.runCommand ||
|
|
361
|
+
!configRaw.metric) {
|
|
362
|
+
spinner.fail(chalk.red("Config missing required fields (mutablePaths, runCommand, metric)"));
|
|
363
|
+
process.exit(1);
|
|
364
|
+
}
|
|
365
|
+
const store = await AutoresearchCommandFactory.getStore();
|
|
366
|
+
const now = new Date().toISOString();
|
|
367
|
+
const task = {
|
|
368
|
+
id: `task_${nanoid(12)}`,
|
|
369
|
+
name: `autoresearch-${repoPath.split("/").pop()}`,
|
|
370
|
+
prompt: "Autonomous ML experiment loop",
|
|
371
|
+
schedule: { type: "interval", every: argv.interval * 1000 },
|
|
372
|
+
mode: "isolated",
|
|
373
|
+
type: "autoresearch",
|
|
374
|
+
status: "active",
|
|
375
|
+
tools: true,
|
|
376
|
+
timeout: configRaw.timeoutMs ?? 600_000,
|
|
377
|
+
retry: { maxAttempts: 1, backoffMs: [60_000] },
|
|
378
|
+
runCount: 0,
|
|
379
|
+
createdAt: now,
|
|
380
|
+
updatedAt: now,
|
|
381
|
+
autoresearch: {
|
|
382
|
+
repoPath,
|
|
383
|
+
mutablePaths: configRaw.mutablePaths,
|
|
384
|
+
runCommand: configRaw.runCommand,
|
|
385
|
+
metric: configRaw.metric,
|
|
386
|
+
...(configRaw.immutablePaths?.length
|
|
387
|
+
? { immutablePaths: configRaw.immutablePaths }
|
|
388
|
+
: {}),
|
|
389
|
+
...(configRaw.programPath
|
|
390
|
+
? { programPath: configRaw.programPath }
|
|
391
|
+
: {}),
|
|
392
|
+
...(configRaw.resultsPath
|
|
393
|
+
? { resultsPath: configRaw.resultsPath }
|
|
394
|
+
: {}),
|
|
395
|
+
...(configRaw.statePath ? { statePath: configRaw.statePath } : {}),
|
|
396
|
+
...(configRaw.logPath ? { logPath: configRaw.logPath } : {}),
|
|
397
|
+
...(configRaw.branchPrefix
|
|
398
|
+
? { branchPrefix: configRaw.branchPrefix }
|
|
399
|
+
: {}),
|
|
400
|
+
...(configRaw.memoryMetric
|
|
401
|
+
? { memoryMetric: configRaw.memoryMetric }
|
|
402
|
+
: {}),
|
|
403
|
+
...(configRaw.timeoutMs ? { timeoutMs: configRaw.timeoutMs } : {}),
|
|
404
|
+
...(configRaw.provider ? { provider: configRaw.provider } : {}),
|
|
405
|
+
...(configRaw.model ? { model: configRaw.model } : {}),
|
|
406
|
+
...(configRaw.thinkingLevel
|
|
407
|
+
? { thinkingLevel: configRaw.thinkingLevel }
|
|
408
|
+
: {}),
|
|
409
|
+
...(configRaw.maxExperiments
|
|
410
|
+
? { maxExperiments: configRaw.maxExperiments }
|
|
411
|
+
: {}),
|
|
412
|
+
},
|
|
413
|
+
...(argv.maxRuns ? { maxRuns: argv.maxRuns } : {}),
|
|
414
|
+
};
|
|
415
|
+
await store.save(task);
|
|
416
|
+
await store.shutdown();
|
|
417
|
+
spinner.succeed(chalk.green(`Autoresearch task created: ${task.id}`));
|
|
418
|
+
console.info(` Interval: ${argv.interval}s Max runs: ${argv.maxRuns ?? "unlimited"}`);
|
|
419
|
+
console.info(chalk.dim(" Note: Start the task worker with `neurolink task start` to begin execution."));
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
spinner.fail(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
423
|
+
process.exit(1);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Lifecycle operations: pause, resume, stop.
|
|
428
|
+
* Reads from the file task store and updates task status.
|
|
429
|
+
*/
|
|
430
|
+
static async executeLifecycle(taskId, action) {
|
|
431
|
+
const spinner = ora(`${action}ing task ${taskId}...`).start();
|
|
432
|
+
try {
|
|
433
|
+
const store = await AutoresearchCommandFactory.getStore();
|
|
434
|
+
const task = await store.get(taskId);
|
|
435
|
+
if (!task) {
|
|
436
|
+
spinner.fail(chalk.red(`Task not found: ${taskId}`));
|
|
437
|
+
process.exit(1);
|
|
438
|
+
}
|
|
439
|
+
if (task.type !== "autoresearch") {
|
|
440
|
+
spinner.fail(chalk.red(`Task ${taskId} is not an autoresearch task (type: ${task.type})`));
|
|
441
|
+
process.exit(1);
|
|
442
|
+
}
|
|
443
|
+
let newStatus;
|
|
444
|
+
if (action === "pause") {
|
|
445
|
+
if (task.status !== "active") {
|
|
446
|
+
spinner.fail(chalk.red(`Cannot pause task with status: ${task.status}`));
|
|
447
|
+
process.exit(1);
|
|
448
|
+
}
|
|
449
|
+
newStatus = "paused";
|
|
450
|
+
}
|
|
451
|
+
else if (action === "resume") {
|
|
452
|
+
if (task.status !== "paused") {
|
|
453
|
+
spinner.fail(chalk.red(`Cannot resume task with status: ${task.status}`));
|
|
454
|
+
process.exit(1);
|
|
455
|
+
}
|
|
456
|
+
newStatus = "active";
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
// stop
|
|
460
|
+
newStatus = "cancelled";
|
|
461
|
+
}
|
|
462
|
+
await store.update(taskId, {
|
|
463
|
+
status: newStatus,
|
|
464
|
+
});
|
|
465
|
+
await store.shutdown();
|
|
466
|
+
spinner.succeed(chalk.green(`Task ${taskId} → ${newStatus}`));
|
|
467
|
+
}
|
|
468
|
+
catch (error) {
|
|
469
|
+
spinner.fail(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
470
|
+
process.exit(1);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Reset autoresearch state by removing the .autoresearch directory.
|
|
475
|
+
*/
|
|
476
|
+
static async executeReset(repoPath) {
|
|
477
|
+
const resolved = resolve(repoPath);
|
|
478
|
+
const arDir = resolve(resolved, ".autoresearch");
|
|
479
|
+
if (!existsSync(arDir)) {
|
|
480
|
+
console.info(chalk.yellow("No .autoresearch directory found."));
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
rmSync(arDir, { recursive: true, force: true });
|
|
484
|
+
console.info(chalk.green(`Reset autoresearch state for ${resolved}`));
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
//# sourceMappingURL=autoresearch.js.map
|
|
@@ -81,9 +81,9 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
81
81
|
enableLogging: z.ZodDefault<z.ZodBoolean>;
|
|
82
82
|
enableCaching: z.ZodDefault<z.ZodBoolean>;
|
|
83
83
|
cacheStrategy: z.ZodDefault<z.ZodEnum<{
|
|
84
|
+
file: "file";
|
|
84
85
|
memory: "memory";
|
|
85
86
|
redis: "redis";
|
|
86
|
-
file: "file";
|
|
87
87
|
}>>;
|
|
88
88
|
defaultEvaluationDomain: z.ZodOptional<z.ZodString>;
|
|
89
89
|
enableAnalyticsByDefault: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -32,6 +32,8 @@ export declare class TaskCommandFactory {
|
|
|
32
32
|
* Used by all management commands: create, list, get, delete, logs, pause, resume, update.
|
|
33
33
|
*/
|
|
34
34
|
private static getStore;
|
|
35
|
+
/** Attach autoresearch-specific event listeners for worker log output */
|
|
36
|
+
private static attachAutoresearchEventListeners;
|
|
35
37
|
/** Attach event listeners and keep the process alive for scheduled task execution */
|
|
36
38
|
private static enterWorkerMode;
|
|
37
39
|
/**
|
|
@@ -16,14 +16,13 @@
|
|
|
16
16
|
* - neurolink task status — Show worker status
|
|
17
17
|
*/
|
|
18
18
|
import { spawn } from "node:child_process";
|
|
19
|
-
import { openSync } from "node:fs";
|
|
19
|
+
import { mkdirSync, openSync } from "node:fs";
|
|
20
20
|
import { join } from "node:path";
|
|
21
|
-
import { mkdirSync } from "node:fs";
|
|
22
21
|
import chalk from "chalk";
|
|
23
22
|
import { nanoid } from "nanoid";
|
|
24
23
|
import ora from "ora";
|
|
25
24
|
import { TASK_DEFAULTS } from "../../lib/types/index.js";
|
|
26
|
-
import {
|
|
25
|
+
import { ensureStateDir, formatUptime, getNeuroLinkDir, isProcessRunning, StateFileManager, } from "../utils/serverUtils.js";
|
|
27
26
|
const workerState = new StateFileManager("task-worker-state.json");
|
|
28
27
|
/**
|
|
29
28
|
* Parse human-readable duration to milliseconds.
|
|
@@ -284,6 +283,31 @@ export class TaskCommandFactory {
|
|
|
284
283
|
await store.initialize();
|
|
285
284
|
return store;
|
|
286
285
|
}
|
|
286
|
+
/** Attach autoresearch-specific event listeners for worker log output */
|
|
287
|
+
static attachAutoresearchEventListeners(emitter) {
|
|
288
|
+
emitter.on("autoresearch:phase-changed", (event) => {
|
|
289
|
+
const e = event;
|
|
290
|
+
console.info(` ${chalk.magenta("⟳")} ${chalk.dim(new Date().toLocaleTimeString())} ${chalk.magenta("phase")} ${e.from} → ${chalk.bold(e.to ?? "?")}${e.tag ? ` [${e.tag}]` : ""}`);
|
|
291
|
+
});
|
|
292
|
+
emitter.on("autoresearch:experiment-completed", (event) => {
|
|
293
|
+
const e = event;
|
|
294
|
+
const icon = e.status === "keep"
|
|
295
|
+
? chalk.green("✔")
|
|
296
|
+
: e.status === "discard"
|
|
297
|
+
? chalk.yellow("↩")
|
|
298
|
+
: chalk.red("✘");
|
|
299
|
+
console.info(` ${icon} ${chalk.dim(new Date().toLocaleTimeString())} ${chalk.cyan("experiment")} ${e.status} metric=${e.metric ?? "N/A"} commit=${(e.commit ?? "").slice(0, 7)} ${e.durationMs ? `${e.durationMs}ms` : ""}`);
|
|
300
|
+
});
|
|
301
|
+
emitter.on("autoresearch:metric-improved", (event) => {
|
|
302
|
+
const e = event;
|
|
303
|
+
console.info(` ${chalk.green("★")} ${chalk.dim(new Date().toLocaleTimeString())} ${chalk.green("new best metric")} ${e.previousBest} → ${chalk.bold(String(e.newBest))} (${e.direction})`);
|
|
304
|
+
});
|
|
305
|
+
emitter.on("autoresearch:error", (event) => {
|
|
306
|
+
const e = event;
|
|
307
|
+
const errMsg = e.error ?? e.message ?? "unknown";
|
|
308
|
+
console.info(` ${chalk.red("⚠")} ${chalk.dim(new Date().toLocaleTimeString())} ${chalk.red("autoresearch error")} [${e.code}] ${errMsg.slice(0, 100)}${e.phase ? ` (phase: ${e.phase})` : ""}`);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
287
311
|
/** Attach event listeners and keep the process alive for scheduled task execution */
|
|
288
312
|
static enterWorkerMode(neurolink, manager) {
|
|
289
313
|
console.info(chalk.gray(" Worker running. Tasks will auto-execute on schedule."));
|
|
@@ -305,6 +329,8 @@ export class TaskCommandFactory {
|
|
|
305
329
|
const r = result;
|
|
306
330
|
console.info(` ${chalk.red("✘")} ${chalk.dim(new Date().toLocaleTimeString())} ${chalk.cyan(r.taskId)} — ${chalk.red(r.error?.slice(0, 100) || "unknown error")}`);
|
|
307
331
|
});
|
|
332
|
+
// Autoresearch lifecycle events
|
|
333
|
+
TaskCommandFactory.attachAutoresearchEventListeners(emitter);
|
|
308
334
|
}
|
|
309
335
|
// Graceful shutdown on Ctrl+C
|
|
310
336
|
const shutdown = async () => {
|
|
@@ -354,6 +380,7 @@ export class TaskCommandFactory {
|
|
|
354
380
|
prompt: argv.prompt,
|
|
355
381
|
schedule,
|
|
356
382
|
mode,
|
|
383
|
+
type: "standard",
|
|
357
384
|
status: "active",
|
|
358
385
|
tools: TASK_DEFAULTS.tools,
|
|
359
386
|
timeout: TASK_DEFAULTS.timeout,
|
|
@@ -796,6 +823,8 @@ export class TaskCommandFactory {
|
|
|
796
823
|
const r = result;
|
|
797
824
|
console.error(`[task-worker] ✘ ${new Date().toISOString()} ${r.taskId} — ${r.error?.slice(0, 200) || "unknown error"}`);
|
|
798
825
|
});
|
|
826
|
+
// Autoresearch lifecycle events
|
|
827
|
+
TaskCommandFactory.attachAutoresearchEventListeners(emitter);
|
|
799
828
|
}
|
|
800
829
|
// Graceful shutdown
|
|
801
830
|
const shutdown = async () => {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { startVoiceServer } from "../../lib/server/voice/voiceServerApp.js";
|
|
2
|
+
import { configureVoiceServerEnvironment } from "../../lib/server/voice/voiceWebSocketHandler.js";
|
|
3
|
+
export const voiceServerCommand = {
|
|
4
|
+
command: "voice-server",
|
|
5
|
+
describe: "Start the real-time voice assistant server (Soniox STT + Cartesia TTS + Cobra VAD)",
|
|
6
|
+
builder: (yargs) => yargs.option("port", {
|
|
7
|
+
alias: "p",
|
|
8
|
+
type: "number",
|
|
9
|
+
default: 3000,
|
|
10
|
+
describe: "Port to listen on",
|
|
11
|
+
}),
|
|
12
|
+
handler: async (argv) => {
|
|
13
|
+
configureVoiceServerEnvironment();
|
|
14
|
+
await startVoiceServer(argv.port);
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=voiceServer.js.map
|
package/dist/cli/parser.js
CHANGED
|
@@ -16,6 +16,8 @@ import { TelemetryCommandFactory } from "./commands/telemetry.js";
|
|
|
16
16
|
import { proxyStartCommand, proxyStatusCommand, proxyTelemetryCommand, proxySetupCommand, proxyGuardCommand, proxyInstallCommand, proxyUninstallCommand, } from "./commands/proxy.js";
|
|
17
17
|
import { EvaluateCommandFactory } from "./commands/evaluate.js";
|
|
18
18
|
import { TaskCommandFactory } from "./commands/task.js";
|
|
19
|
+
import { AutoresearchCommandFactory } from "./commands/autoresearch.js";
|
|
20
|
+
import { voiceServerCommand } from "./commands/voiceServer.js";
|
|
19
21
|
// Enhanced CLI with Professional UX
|
|
20
22
|
export function initializeCliParser() {
|
|
21
23
|
return (yargs(hideBin(process.argv))
|
|
@@ -203,6 +205,10 @@ export function initializeCliParser() {
|
|
|
203
205
|
// Evaluate Command Group - Using EvaluateCommandFactory
|
|
204
206
|
.command(EvaluateCommandFactory.createEvaluateCommand())
|
|
205
207
|
// Task Command Group - Scheduled and self-running tasks
|
|
206
|
-
.command(TaskCommandFactory.createTaskCommands())
|
|
208
|
+
.command(TaskCommandFactory.createTaskCommands())
|
|
209
|
+
// AutoResearch Command Group - Automated AI-driven research experiments
|
|
210
|
+
.command(AutoresearchCommandFactory.createAutoresearchCommands())
|
|
211
|
+
// Real-time voice server (Soniox STT + Cartesia TTS + Cobra VAD)
|
|
212
|
+
.command(voiceServerCommand)); // Close the main return statement
|
|
207
213
|
}
|
|
208
214
|
//# sourceMappingURL=parser.js.map
|