mindvest-atlas 0.65.0 → 0.67.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/config.js +1 -1
- package/src/helpers/atlas_env.js +46 -6
- package/src/helpers/atlas_env.py +20 -12
package/package.json
CHANGED
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.67.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/helpers/atlas_env.js
CHANGED
|
@@ -53,6 +53,19 @@ export async function atlas(tool, params = {}) {
|
|
|
53
53
|
*
|
|
54
54
|
* const verdict = await ask(`Is this headline about AAPL itself or the sector?\n${line}`);
|
|
55
55
|
*
|
|
56
|
+
* IT IS A CHAT SESSION, NOT A TEXT BOX (owner, 2026-09-11). The model runs in
|
|
57
|
+
* this project's folder with everything the chat has: the files, the shell, the
|
|
58
|
+
* `atlas` command line, Atlas's own tools, the skills, and the computer when the
|
|
59
|
+
* switch is on. Ask it to open the broker and read a balance and it drives the
|
|
60
|
+
* screen; its last message is what you get back. Nobody is watching, so it never
|
|
61
|
+
* asks back: it decides. Say what shape you want the answer in.
|
|
62
|
+
*
|
|
63
|
+
* const balance = await ask("Open the broker in Edge and read me the cash balance. Answer with the number only.");
|
|
64
|
+
*
|
|
65
|
+
* commands:true (the default) is that whole session; commands:false is pure
|
|
66
|
+
* judgement — twenty classifications — where the model answers from what it was
|
|
67
|
+
* given and runs nothing, faster and cheaper.
|
|
68
|
+
*
|
|
56
69
|
* tools:true lets the model reach Atlas data while it answers; false is faster
|
|
57
70
|
* for pure text. fresh:false keeps ONE conversation for this job (the model
|
|
58
71
|
* starts up once, later questions can refer to earlier ones); fresh:true is for
|
|
@@ -71,7 +84,7 @@ export async function atlas(tool, params = {}) {
|
|
|
71
84
|
* quietly answered by the default, because a script that asked for a specific
|
|
72
85
|
* model and silently got another one is worse than one that stops.
|
|
73
86
|
*/
|
|
74
|
-
export async function ask(prompt, { tools = true, fresh = false, timeoutMs = 600000, model = "" } = {}) {
|
|
87
|
+
export async function ask(prompt, { tools = true, fresh = false, timeoutMs = 600000, model = "", commands = true } = {}) {
|
|
75
88
|
const url = process.env.ATLAS_ASK_URL;
|
|
76
89
|
const token = process.env.ATLAS_ASK_TOKEN;
|
|
77
90
|
if (!url || !token) {
|
|
@@ -80,7 +93,7 @@ export async function ask(prompt, { tools = true, fresh = false, timeoutMs = 600
|
|
|
80
93
|
"Connect a model in Atlas Studio, or do this step in code."
|
|
81
94
|
);
|
|
82
95
|
}
|
|
83
|
-
const body = { job: process.env.ATLAS_JOB || "", prompt: String(prompt), tools, fresh };
|
|
96
|
+
const body = { job: process.env.ATLAS_JOB || "", prompt: String(prompt), tools, fresh, commands: commands !== false };
|
|
84
97
|
// Sent only when named, so a script that does not care keeps whatever is
|
|
85
98
|
// connected rather than pinning itself to today's default.
|
|
86
99
|
if (String(model || "").trim()) body.model = String(model).trim();
|
|
@@ -346,19 +359,30 @@ export const dashboard = {
|
|
|
346
359
|
* await computer.type("hello");
|
|
347
360
|
* await computer.note("signing in");
|
|
348
361
|
*
|
|
362
|
+
* ONE CALL IS ONE PYTHON. Each of those starts an interpreter, so a sequence of
|
|
363
|
+
* them pays that start-up per click and the run crawls (owner, 2026-09-10: "the
|
|
364
|
+
* slowness is the per command round trip"). Say the whole sequence instead and
|
|
365
|
+
* it is ONE start, with the picture already taken at the end:
|
|
366
|
+
*
|
|
367
|
+
* await computer.do([["click", x, y, "Sign in"],
|
|
368
|
+
* ["type", "someone@example.com"],
|
|
369
|
+
* ["key", "tab"],
|
|
370
|
+
* ["type", secret("PASSWORD")],
|
|
371
|
+
* ["key", "enter"]]);
|
|
372
|
+
*
|
|
349
373
|
* Off until the person turns it on, under This Computer in Atlas Studio. Read skills/computer-use before using any of it.
|
|
350
374
|
*/
|
|
351
|
-
async function useComputer(op, args = []) {
|
|
375
|
+
async function useComputer(op, args = [], kw = {}) {
|
|
352
376
|
const { spawn } = await import("node:child_process");
|
|
353
377
|
const dir = path.dirname(url_.fileURLToPath(import.meta.url));
|
|
354
378
|
const py = process.env.ATLAS_PYTHON || (process.platform === "win32" ? "python" : "python3");
|
|
355
379
|
const code =
|
|
356
380
|
"import json,sys,atlas_env\n"
|
|
357
|
-
+ "op=sys.argv[1]; args=json.loads(sys.argv[2])\n"
|
|
358
|
-
+ "out=getattr(atlas_env,op)(*args)\n"
|
|
381
|
+
+ "op=sys.argv[1]; args=json.loads(sys.argv[2]); kw=json.loads(sys.argv[3])\n"
|
|
382
|
+
+ "out=getattr(atlas_env,op)(*args,**kw)\n"
|
|
359
383
|
+ "sys.stdout.write('\\n__ATLAS__'+json.dumps(out,default=str))\n";
|
|
360
384
|
return await new Promise((done, fail) => {
|
|
361
|
-
const p = spawn(py, ["-c", code, op, JSON.stringify(args)], { cwd: dir });
|
|
385
|
+
const p = spawn(py, ["-c", code, op, JSON.stringify(args), JSON.stringify(kw || {})], { cwd: dir });
|
|
362
386
|
let out = "", err = "";
|
|
363
387
|
p.stdout.on("data", (d) => { out += d; });
|
|
364
388
|
p.stderr.on("data", (d) => { err += d; });
|
|
@@ -392,6 +416,22 @@ export const computer = {
|
|
|
392
416
|
region: (x, y, w, h) => useComputer("region", [x, y, w, h]),
|
|
393
417
|
screens: () => useComputer("screens"),
|
|
394
418
|
useScreen: (n) => useComputer("use_screen", [n]),
|
|
419
|
+
/**
|
|
420
|
+
* SEVERAL THINGS, ONE ROUND TRIP, ONE LOOK AT THE END. The fast loop, and the
|
|
421
|
+
* answer to a run that feels slow: every other call here starts its own
|
|
422
|
+
* Python, so five separate steps pay that five times before anything is even
|
|
423
|
+
* clicked (owner, 2026-09-10: "add option to batch command, this is better").
|
|
424
|
+
*
|
|
425
|
+
* await computer.do([["click", 820, 410, "Sign in"], ["type", "hi"], ["key", "enter"]]);
|
|
426
|
+
* // -> { did: [...], screen: "...png", changed: true, x: 1920, y: 0 }
|
|
427
|
+
*
|
|
428
|
+
* Each step is [name, ...args] with the same names the calls below use.
|
|
429
|
+
* Stops at the first refusal and says what had already happened, with a
|
|
430
|
+
* picture of where it stopped. `settle` is a CEILING in seconds (default 1.2)
|
|
431
|
+
* on waiting for the screen to stop moving, not a pause; `look: false` skips
|
|
432
|
+
* the picture when the next thing you do does not depend on it.
|
|
433
|
+
*/
|
|
434
|
+
do: (steps, opts = {}) => useComputer("do", (steps || []).map((s) => (Array.isArray(s) ? s : [s])), opts),
|
|
395
435
|
click: (x, y) => useComputer("click", [x, y]),
|
|
396
436
|
doubleClick: (x, y) => useComputer("double_click", [x, y]),
|
|
397
437
|
rightClick: (x, y) => useComputer("right_click", [x, y]),
|
package/src/helpers/atlas_env.py
CHANGED
|
@@ -54,24 +54,32 @@ def atlas(tool, **params):
|
|
|
54
54
|
raise RuntimeError("Atlas %s failed (%d): %s" % (tool, e.code, body))
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
def ask(prompt, tools=True, fresh=False, timeout=600, model=""):
|
|
58
|
-
"""Ask YOUR OWN model
|
|
57
|
+
def ask(prompt, tools=True, fresh=False, timeout=600, model="", commands=True):
|
|
58
|
+
"""Ask YOUR OWN model, the way you would in the chat, and get its answer back.
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
It runs on this computer, through the model already connected in Atlas
|
|
67
|
-
Remote Control. The prompt never reaches Atlas.
|
|
60
|
+
IT IS A CHAT SESSION, NOT A TEXT BOX (owner, 2026-09-11). The model runs on
|
|
61
|
+
this computer, in this project's folder, with everything the chat has: the
|
|
62
|
+
files here, the shell, the `atlas` command line, Atlas's own tools, the
|
|
63
|
+
skills, and the computer when the switch is on. Ask it to open the broker
|
|
64
|
+
and read a balance and it will drive the screen; ask it to write and run
|
|
65
|
+
something and it will. Its last message is what you get back.
|
|
68
66
|
|
|
69
67
|
verdict = ask("Is this headline about AAPL itself or the sector?\n" + line)
|
|
70
68
|
if "itself" in verdict.lower():
|
|
71
69
|
...
|
|
70
|
+
balance = ask("Open the broker in Edge and read me the cash balance. "
|
|
71
|
+
"Answer with the number only.")
|
|
72
|
+
|
|
73
|
+
Nobody is watching, so it never asks a question back: it decides. Say what
|
|
74
|
+
shape you want the answer in ("the number only", "one of: buy, sell, wait")
|
|
75
|
+
and that is what arrives.
|
|
76
|
+
|
|
77
|
+
commands=True (the default) is that whole session. commands=False is for
|
|
78
|
+
pure judgement - twenty headline classifications - where the model should
|
|
79
|
+
answer from what you gave it and run nothing; it is faster and cheaper.
|
|
72
80
|
|
|
73
81
|
tools=True lets the model reach Atlas data while it answers; pass
|
|
74
|
-
tools=False for
|
|
82
|
+
tools=False for text work that needs none of it.
|
|
75
83
|
|
|
76
84
|
fresh=False keeps ONE conversation for this job, so later questions can
|
|
77
85
|
refer to earlier ones and the model starts up only once. Pass fresh=True
|
|
@@ -104,7 +112,7 @@ def ask(prompt, tools=True, fresh=False, timeout=600, model=""):
|
|
|
104
112
|
"Connect a model in Atlas Studio, or do this step in code."
|
|
105
113
|
)
|
|
106
114
|
body = {"job": os.environ.get("ATLAS_JOB", ""), "prompt": str(prompt),
|
|
107
|
-
"tools": bool(tools), "fresh": bool(fresh)}
|
|
115
|
+
"tools": bool(tools), "fresh": bool(fresh), "commands": bool(commands)}
|
|
108
116
|
# Sent only when named, so a script that does not care keeps whatever is
|
|
109
117
|
# connected rather than pinning itself to today's default.
|
|
110
118
|
if str(model or "").strip():
|