@melaya/runner 1.0.71 → 1.0.73
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/dist/cli.js +2 -2
- package/dist/detect.d.ts +1 -4
- package/dist/detect.js +33 -1
- package/dist/localRelay.js +42 -0
- package/dist/pythonEnv.js +8 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -63,8 +63,8 @@ async function main() {
|
|
|
63
63
|
// Detect local models
|
|
64
64
|
const models = await detectModels();
|
|
65
65
|
if (models.length === 0) {
|
|
66
|
-
console.log(chalk.yellow(" ⚠ No local models detected (LM Studio / Ollama not running)"));
|
|
67
|
-
console.log(chalk.gray(" Start LM Studio or Ollama, then restart the runner"));
|
|
66
|
+
console.log(chalk.yellow(" ⚠ No local models detected (LM Studio / Ollama not running, Claude Code not logged in)"));
|
|
67
|
+
console.log(chalk.gray(" Start LM Studio or Ollama (or log in to Claude Code), then restart the runner"));
|
|
68
68
|
}
|
|
69
69
|
else {
|
|
70
70
|
for (const m of models) {
|
package/dist/detect.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-detect local LLM providers (LM Studio, Ollama) and list models.
|
|
3
|
-
*/
|
|
4
1
|
export interface DetectedModel {
|
|
5
|
-
provider: "lmstudio" | "ollama";
|
|
2
|
+
provider: "lmstudio" | "ollama" | "claude_code";
|
|
6
3
|
name: string;
|
|
7
4
|
}
|
|
8
5
|
export declare function detectModels(): Promise<DetectedModel[]>;
|
package/dist/detect.js
CHANGED
|
@@ -1,6 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Auto-detect local LLM providers (LM Studio, Ollama
|
|
2
|
+
* Auto-detect local LLM providers (LM Studio, Ollama, Claude Code CLI)
|
|
3
|
+
* and list models.
|
|
3
4
|
*/
|
|
5
|
+
import { execFile } from "child_process";
|
|
6
|
+
import { promisify } from "util";
|
|
7
|
+
const execFileAsync = promisify(execFile);
|
|
8
|
+
/** Claude Code is a subscription CLI — when it's installed AND logged in on
|
|
9
|
+
* this machine, report its model aliases so the platform's model picker can
|
|
10
|
+
* show the TRUE availability for local runs (the cloud host's CLI status is
|
|
11
|
+
* the wrong signal: claude_code pipelines execute HERE, on the runner). */
|
|
12
|
+
async function detectClaudeCode() {
|
|
13
|
+
// npm global installs on Windows expose claude.cmd — execFile with a bare
|
|
14
|
+
// name won't resolve .cmd without a shell, so try the .cmd wrapper first.
|
|
15
|
+
const candidates = process.platform === "win32" ? ["claude.cmd", "claude"] : ["claude"];
|
|
16
|
+
for (const exe of candidates) {
|
|
17
|
+
try {
|
|
18
|
+
const { stdout } = await execFileAsync(exe, ["auth", "status"], {
|
|
19
|
+
timeout: 10_000,
|
|
20
|
+
windowsHide: true,
|
|
21
|
+
// .cmd files need a shell on win32; harmless elsewhere.
|
|
22
|
+
shell: process.platform === "win32",
|
|
23
|
+
});
|
|
24
|
+
const status = JSON.parse(stdout);
|
|
25
|
+
if (status.loggedIn) {
|
|
26
|
+
return ["sonnet", "opus", "haiku"].map((name) => ({ provider: "claude_code", name }));
|
|
27
|
+
}
|
|
28
|
+
return []; // installed but logged out — don't advertise models
|
|
29
|
+
}
|
|
30
|
+
catch { /* not installed / not on PATH / non-JSON — try next candidate */ }
|
|
31
|
+
}
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
4
34
|
export async function detectModels() {
|
|
5
35
|
const models = [];
|
|
6
36
|
// LM Studio — OpenAI-compatible at :1234
|
|
@@ -25,5 +55,7 @@ export async function detectModels() {
|
|
|
25
55
|
}
|
|
26
56
|
}
|
|
27
57
|
catch { /* not running */ }
|
|
58
|
+
// Claude Code CLI — subscription auth on THIS machine
|
|
59
|
+
models.push(...await detectClaudeCode());
|
|
28
60
|
return models;
|
|
29
61
|
}
|
package/dist/localRelay.js
CHANGED
|
@@ -105,6 +105,48 @@ export function startLocalRelay(socket, verbose, serverUrl) {
|
|
|
105
105
|
});
|
|
106
106
|
return;
|
|
107
107
|
}
|
|
108
|
+
// ── Mode C RAG search proxy ─────────────────────────────────────
|
|
109
|
+
// A runner-dispatched pipeline's `rag_retrieve` (Mode C: cloud store +
|
|
110
|
+
// local embedder) embeds the query locally then POSTs the vector to
|
|
111
|
+
// `${MEL_BUILDER_URL}/pipelines/<name>/docs/retrieval/search_by_vector`.
|
|
112
|
+
// We forward it over the authenticated socket (the runner is the trust
|
|
113
|
+
// anchor) to `runner:ragSearch`, which calls the server's
|
|
114
|
+
// _forwardSearchByVector → builder search_by_vector on the prod store.
|
|
115
|
+
const sm = req.method === "POST" && req.url
|
|
116
|
+
? req.url.match(/^\/pipelines\/([^/]+)\/docs\/retrieval\/search_by_vector\/?$/)
|
|
117
|
+
: null;
|
|
118
|
+
if (sm) {
|
|
119
|
+
const pipelineName = decodeURIComponent(sm[1]);
|
|
120
|
+
let sbody = "";
|
|
121
|
+
req.on("data", (chunk) => { sbody += chunk.toString(); });
|
|
122
|
+
req.on("end", () => {
|
|
123
|
+
const replyOnce = (status, body) => {
|
|
124
|
+
if (res.headersSent)
|
|
125
|
+
return;
|
|
126
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
127
|
+
res.end(JSON.stringify(body));
|
|
128
|
+
};
|
|
129
|
+
let parsed;
|
|
130
|
+
try {
|
|
131
|
+
parsed = JSON.parse(sbody || "{}");
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
replyOnce(400, { results: [], error: "invalid_json" });
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// Relay timeout < the pipeline's urlopen timeout (30s) so the
|
|
138
|
+
// pipeline always gets a JSON reply rather than its own abort.
|
|
139
|
+
const t = setTimeout(() => replyOnce(504, { results: [], error: "upstream_timeout" }), 25000);
|
|
140
|
+
socket.emit("runner:ragSearch", { name: pipelineName, vector: parsed.vector, limit: parsed.limit }, (resp) => {
|
|
141
|
+
clearTimeout(t);
|
|
142
|
+
if (resp && typeof resp === "object")
|
|
143
|
+
replyOnce(200, resp);
|
|
144
|
+
else
|
|
145
|
+
replyOnce(502, { results: [], error: "no_response" });
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
108
150
|
if (req.method !== "POST" || req.url !== expectedPath) {
|
|
109
151
|
res.writeHead(404);
|
|
110
152
|
res.end("Not found");
|
package/dist/pythonEnv.js
CHANGED
|
@@ -109,6 +109,14 @@ const PIP_DEPS = [
|
|
|
109
109
|
// shared.tools.telegram_user_tools. The bot-API path in
|
|
110
110
|
// shared.tools.messaging.py uses plain HTTP and needs no extra dep.
|
|
111
111
|
"telethon",
|
|
112
|
+
// yfinance — TradFi/macro price history + live FX spot for the financial
|
|
113
|
+
// tools (shared.tools.alphavantage_tools yf_* + shared.tools.fx_tools live
|
|
114
|
+
// spot). BOTH modules guard the import (try/except at load + a
|
|
115
|
+
// _require_yfinance() that raises a clear "pip install yfinance" only when a
|
|
116
|
+
// yf_ tool is actually CALLED), so a runner without it still imports every
|
|
117
|
+
// tool module cleanly — this just makes the dep present so the yf_ tools work
|
|
118
|
+
// when attached. Pulls pandas transitively.
|
|
119
|
+
"yfinance",
|
|
112
120
|
// ── Vector RAG (retrieval mode) ────────────────────────────────────────
|
|
113
121
|
// ollama — Python client used by agentscope.embedding.OllamaTextEmbedding.
|
|
114
122
|
// Talks to localhost:11434 (the user's local Ollama daemon) to embed
|