mindvest-atlas 0.53.0 → 0.55.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 +49 -2
- package/src/remote-control.js +1 -1
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.55.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
|
@@ -57,8 +57,21 @@ export async function atlas(tool, params = {}) {
|
|
|
57
57
|
* for pure text. fresh:false keeps ONE conversation for this job (the model
|
|
58
58
|
* starts up once, later questions can refer to earlier ones); fresh:true is for
|
|
59
59
|
* independent questions that should not pile into one context.
|
|
60
|
+
*
|
|
61
|
+
* model:"" uses whichever model is connected, which is the usual case. Name one
|
|
62
|
+
* to send THIS question somewhere else - a cheap fast one for twenty
|
|
63
|
+
* classifications and a strong one for the judgement call at the end, in the
|
|
64
|
+
* same script:
|
|
65
|
+
*
|
|
66
|
+
* const kind = await ask(`Sector or company?\n${line}`, { model: "claude-haiku-4-5" });
|
|
67
|
+
* const call = await ask("Given all of the above, do we buy?", { model: "claude-opus-4-8" });
|
|
68
|
+
*
|
|
69
|
+
* models() lists what this computer can reach, with their ids and the effort
|
|
70
|
+
* words each one takes. A name it does not have is refused BY NAME rather than
|
|
71
|
+
* quietly answered by the default, because a script that asked for a specific
|
|
72
|
+
* model and silently got another one is worse than one that stops.
|
|
60
73
|
*/
|
|
61
|
-
export async function ask(prompt, { tools = true, fresh = false, timeoutMs = 600000 } = {}) {
|
|
74
|
+
export async function ask(prompt, { tools = true, fresh = false, timeoutMs = 600000, model = "" } = {}) {
|
|
62
75
|
const url = process.env.ATLAS_ASK_URL;
|
|
63
76
|
const token = process.env.ATLAS_ASK_TOKEN;
|
|
64
77
|
if (!url || !token) {
|
|
@@ -67,10 +80,14 @@ export async function ask(prompt, { tools = true, fresh = false, timeoutMs = 600
|
|
|
67
80
|
"Connect a model in Atlas Studio, or do this step in code."
|
|
68
81
|
);
|
|
69
82
|
}
|
|
83
|
+
const body = { job: process.env.ATLAS_JOB || "", prompt: String(prompt), tools, fresh };
|
|
84
|
+
// Sent only when named, so a script that does not care keeps whatever is
|
|
85
|
+
// connected rather than pinning itself to today's default.
|
|
86
|
+
if (String(model || "").trim()) body.model = String(model).trim();
|
|
70
87
|
const res = await fetch(url, {
|
|
71
88
|
method: "POST",
|
|
72
89
|
headers: { "Content-Type": "application/json", "X-Atlas-Token": token },
|
|
73
|
-
body: JSON.stringify(
|
|
90
|
+
body: JSON.stringify(body),
|
|
74
91
|
signal: AbortSignal.timeout(timeoutMs),
|
|
75
92
|
});
|
|
76
93
|
const out = await res.json().catch(() => ({}));
|
|
@@ -78,6 +95,36 @@ export async function ask(prompt, { tools = true, fresh = false, timeoutMs = 600
|
|
|
78
95
|
return out.answer || "";
|
|
79
96
|
}
|
|
80
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Every model this computer can reach, asked of the app itself.
|
|
100
|
+
*
|
|
101
|
+
* Returns rows of {id, label, vendor, ready, effort, effortDefault} - the id to
|
|
102
|
+
* pass to ask({model}), and the effort words THAT model takes, which differ per
|
|
103
|
+
* vendor and are the other thing that gets guessed wrong. An empty list means
|
|
104
|
+
* no model is connected, in which case ask() will say so too.
|
|
105
|
+
*
|
|
106
|
+
* const roster = await models();
|
|
107
|
+
* const cheap = roster.find((m) => m.ready && m.id.includes("haiku"));
|
|
108
|
+
* await ask("Sector or company?", { model: cheap?.id });
|
|
109
|
+
*/
|
|
110
|
+
export async function models() {
|
|
111
|
+
const url = process.env.ATLAS_ASK_URL;
|
|
112
|
+
const token = process.env.ATLAS_ASK_TOKEN;
|
|
113
|
+
if (!url || !token) return [];
|
|
114
|
+
try {
|
|
115
|
+
const res = await fetch(url.replace("/ask", "/models"), {
|
|
116
|
+
headers: { "X-Atlas-Token": token },
|
|
117
|
+
signal: AbortSignal.timeout(20000),
|
|
118
|
+
});
|
|
119
|
+
const out = await res.json().catch(() => ({}));
|
|
120
|
+
return (out.models || []).filter((m) => m && m.id);
|
|
121
|
+
} catch {
|
|
122
|
+
// A roster that cannot be read is not a reason to take the job down: the
|
|
123
|
+
// script can still ask the connected model without naming one.
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
81
128
|
/**
|
|
82
129
|
* Call a tool on one of YOUR connected MCP servers.
|
|
83
130
|
*
|
package/src/remote-control.js
CHANGED
|
@@ -1502,7 +1502,7 @@ const STARTER_README = (name) => [
|
|
|
1502
1502
|
'- `main.py` what runs. Replaced by the model on the first build.',
|
|
1503
1503
|
'- `.env` your keys. Values stay on this computer and are never read',
|
|
1504
1504
|
' back by anything, including the model.',
|
|
1505
|
-
'- `atlas_env.py` helpers: secret(), require(), atlas(), ask().',
|
|
1505
|
+
'- `atlas_env.py` helpers: secret(), require(), atlas(), ask(), models().',
|
|
1506
1506
|
'- `plan.md` a diagram of what happens, written after the first build.',
|
|
1507
1507
|
'- `dashboard.js` how this job draws itself on the Dashboard tab. Atlas owns',
|
|
1508
1508
|
' the page; this is the drawing.',
|