mindvest-atlas 0.52.0 → 0.53.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/package.json +1 -1
- package/src/cli.js +5 -0
- package/src/commands/models.js +81 -0
- package/src/config.js +1 -1
- package/src/remote-control.js +10 -2
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ import { loginCommand } from './commands/login.js';
|
|
|
10
10
|
import { logoutCommand } from './commands/logout.js';
|
|
11
11
|
import { whoamiCommand } from './commands/whoami.js';
|
|
12
12
|
import { toolsCommand } from './commands/tools.js';
|
|
13
|
+
import { modelsCommand, askCommand } from './commands/models.js';
|
|
13
14
|
import { alertsCommand } from './commands/alerts.js';
|
|
14
15
|
import { flowCommand } from './commands/flow.js';
|
|
15
16
|
import { remoteControlCommand } from './commands/remote-control.js';
|
|
@@ -82,6 +83,10 @@ export async function main(rawArgs) {
|
|
|
82
83
|
case 'logout': return await logoutCommand(withoutCommand(args));
|
|
83
84
|
case 'whoami': return await whoamiCommand(withoutCommand(args));
|
|
84
85
|
case 'tools': return await toolsCommand(withoutCommand(args));
|
|
86
|
+
// WHICH MODELS ARE HERE, and handing one piece of work to one of them —
|
|
87
|
+
// together, the whole mechanism behind orchestration.
|
|
88
|
+
case 'models': return await modelsCommand(withoutCommand(args));
|
|
89
|
+
case 'ask': return await askCommand(withoutCommand(args));
|
|
85
90
|
case 'alerts': return await alertsCommand(withoutCommand(args));
|
|
86
91
|
case 'flow': return await flowCommand(withoutCommand(args));
|
|
87
92
|
// Long-lived: hold the job stream and run this computer's jobs.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Which models this computer can reach, and handing work to one of them.
|
|
2
|
+
//
|
|
3
|
+
// TWO COMMANDS, AND THE SECOND IS THE POINT. `atlas models` is the catalogue:
|
|
4
|
+
// every model, who runs it, whether it is actually reachable, and the effort
|
|
5
|
+
// levels it takes — because anything CHOOSING a model needs to know what is
|
|
6
|
+
// there, and a guessed id is a session that fails a minute later for a reason
|
|
7
|
+
// nobody can see.
|
|
8
|
+
//
|
|
9
|
+
// `atlas ask --model X "..."` hands one piece of work to one named model. The
|
|
10
|
+
// helper has been able to do that from inside a script for a long time; it was
|
|
11
|
+
// never reachable from a SHELL, which is where an agent lives. That one gap is
|
|
12
|
+
// what stood between this and a model that can delegate: an orchestrator is not
|
|
13
|
+
// a new mechanism, it is a model with this command and a roster.
|
|
14
|
+
import { color, println, eprintln } from '../util/ui.js';
|
|
15
|
+
import { askModel, listModels } from '../remote-control.js';
|
|
16
|
+
|
|
17
|
+
export async function modelsCommand(args) {
|
|
18
|
+
const flags = args.flags || {};
|
|
19
|
+
const catalog = await listModels();
|
|
20
|
+
const rows = catalog.models || [];
|
|
21
|
+
if (flags.json) {
|
|
22
|
+
println(JSON.stringify(catalog, null, 2));
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
if (!rows.length) {
|
|
26
|
+
eprintln(color.red('No model is connected on this computer yet.'));
|
|
27
|
+
eprintln(color.dim(' Open Atlas Studio > Model Settings and sign in to one.'));
|
|
28
|
+
return 1;
|
|
29
|
+
}
|
|
30
|
+
const width = Math.max(...rows.map((r) => String(r.id || '').length));
|
|
31
|
+
println(color.bold('Models on this computer'));
|
|
32
|
+
for (const r of rows) {
|
|
33
|
+
// READY FIRST: a model that cannot be reached is not a choice, and it is the
|
|
34
|
+
// one fact a caller cannot work out for itself.
|
|
35
|
+
const mark = r.ready ? ' ' : '! ';
|
|
36
|
+
const star = r.id === catalog.default ? ' *' : '';
|
|
37
|
+
const effort = (r.effort || []).join(', ') || '-';
|
|
38
|
+
println(`${mark}${String(r.id || '').padEnd(width)} ${String(r.agent || '').padEnd(14)}`
|
|
39
|
+
+ ` ${String(r.vendor || '').padEnd(22)} effort: ${effort}${star}`);
|
|
40
|
+
}
|
|
41
|
+
println('');
|
|
42
|
+
println(color.dim(' * the one used when nothing is named'));
|
|
43
|
+
println(color.dim(' ! not reachable right now — sign in under Model Settings'));
|
|
44
|
+
println(color.dim(' atlas ask --model <id> "..." hand one piece of work to one of them'));
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function askCommand(args) {
|
|
49
|
+
const flags = args.flags || {};
|
|
50
|
+
const rest = args.positional || args._ || [];
|
|
51
|
+
const prompt = (rest.join(' ') || String(flags.prompt || '')).trim();
|
|
52
|
+
if (!prompt) {
|
|
53
|
+
eprintln(color.red('Say what to ask.'));
|
|
54
|
+
eprintln(color.dim(' atlas ask --model gpt-5.6-sol "summarise this filing"'));
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
const model = String(flags.model || '').trim();
|
|
58
|
+
if (model) {
|
|
59
|
+
// NAMED, AND CHECKED. A typo would otherwise fall back to the default model
|
|
60
|
+
// in silence, and an orchestrator would believe it had asked three different
|
|
61
|
+
// models when it had asked one three times.
|
|
62
|
+
const known = ((await listModels()).models || []).map((r) => String(r.id));
|
|
63
|
+
if (known.length && !known.includes(model)) {
|
|
64
|
+
eprintln(color.red(`No model here is called "${model}".`));
|
|
65
|
+
eprintln(color.dim(' atlas models lists them'));
|
|
66
|
+
return 1;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const said = await askModel(prompt, {
|
|
71
|
+
job: String(flags.job || ''),
|
|
72
|
+
model,
|
|
73
|
+
timeoutMs: Number(flags.timeout || 900) * 1000,
|
|
74
|
+
});
|
|
75
|
+
println(typeof said === 'string' ? said : JSON.stringify(said, null, 2));
|
|
76
|
+
return 0;
|
|
77
|
+
} catch (err) {
|
|
78
|
+
eprintln(color.red(err.message || String(err)));
|
|
79
|
+
return 1;
|
|
80
|
+
}
|
|
81
|
+
}
|
package/src/config.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
|
|
5
|
-
export const VERSION = '0.
|
|
5
|
+
export const VERSION = '0.53.0';
|
|
6
6
|
export const DEFAULT_BASE_URL = 'https://atlasmcp.finmanagerai.com';
|
|
7
7
|
export const DEFAULT_SCOPE = 'atlas broker';
|
|
8
8
|
export const CLIENT_NAME = 'Atlas CLI';
|
package/src/remote-control.js
CHANGED
|
@@ -1360,7 +1360,15 @@ export function listRuns(root, limit = 50) {
|
|
|
1360
1360
|
*
|
|
1361
1361
|
* Returns the model's account of what it did. Throws if no model is connected.
|
|
1362
1362
|
*/
|
|
1363
|
-
export async function askModel(
|
|
1363
|
+
export async function askModel(
|
|
1364
|
+
prompt,
|
|
1365
|
+
// `model` NAMES WHICH ONE ANSWERS, and its absence here was a real gap: the
|
|
1366
|
+
// python helper has taken it for a long time, so the same call delegated to a
|
|
1367
|
+
// named model in one runtime and quietly used the default in the other. That
|
|
1368
|
+
// is the shape of bug where an orchestrator believes it asked three models and
|
|
1369
|
+
// asked one three times.
|
|
1370
|
+
{ job = '', tools = true, fresh = false, timeoutMs = 900000, model = '' } = {},
|
|
1371
|
+
) {
|
|
1364
1372
|
const url = process.env.ATLAS_ASK_URL;
|
|
1365
1373
|
const token = process.env.ATLAS_ASK_TOKEN;
|
|
1366
1374
|
if (!url || !token) {
|
|
@@ -1372,7 +1380,7 @@ export async function askModel(prompt, { job = '', tools = true, fresh = false,
|
|
|
1372
1380
|
const res = await fetch(url, {
|
|
1373
1381
|
method: 'POST',
|
|
1374
1382
|
headers: { 'Content-Type': 'application/json', 'X-Atlas-Token': token },
|
|
1375
|
-
body: JSON.stringify({ job, prompt: String(prompt), tools, fresh }),
|
|
1383
|
+
body: JSON.stringify({ job, prompt: String(prompt), tools, fresh, ...(model ? { model } : {}) }),
|
|
1376
1384
|
signal: AbortSignal.timeout(timeoutMs),
|
|
1377
1385
|
});
|
|
1378
1386
|
const out = await res.json().catch(() => ({}));
|