@melaya/runner 1.0.110 → 1.0.112
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/assistantHost.py +54 -0
- package/dist/connection.js +3 -1
- package/package.json +42 -42
package/dist/assistantHost.py
CHANGED
|
@@ -72,6 +72,21 @@ def _memory_watermark(agent) -> int:
|
|
|
72
72
|
return 0
|
|
73
73
|
|
|
74
74
|
|
|
75
|
+
def _emit_usage(agent, turn_id: str) -> None:
|
|
76
|
+
"""Live header meter (runner parity): the context-fullness GAUGE — memory
|
|
77
|
+
watermark vs budget — so the FE shows how full the window is before the next
|
|
78
|
+
compaction, exactly like the cloud path. Per-turn TOKEN totals are exported as
|
|
79
|
+
spans (Overview dashboard); the live in/out counter stays cloud-only for now."""
|
|
80
|
+
try:
|
|
81
|
+
mem = _agent_memory(agent)
|
|
82
|
+
budget = int(getattr(mem, "max_tokens", 0) or 0) if mem is not None else 0
|
|
83
|
+
if budget > 0:
|
|
84
|
+
_emit(turn_id, "usage", turnInTok=0, turnOutTok=0,
|
|
85
|
+
ctxUsed=_memory_watermark(agent), ctxBudget=budget)
|
|
86
|
+
except Exception:
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
|
|
75
90
|
def _sync_ollama_memory_budget(agent) -> None:
|
|
76
91
|
"""P2-6 (persistent host): the Assistant builds ONE agent + BoundedMemory, so an
|
|
77
92
|
OOM num_ctx downgrade that shrinks the ollama context cache would otherwise leave
|
|
@@ -212,6 +227,32 @@ def _apply_hitl_mode(mode: str | None) -> None:
|
|
|
212
227
|
os.environ["MEL_HITL_MODE"] = normalized
|
|
213
228
|
|
|
214
229
|
|
|
230
|
+
def _apply_static_context(agent, base_prompt: str, ctx) -> None:
|
|
231
|
+
"""Per-turn: fold the conversation's STATIC CONTEXT (the user's persona /
|
|
232
|
+
standing instructions) into the agent's system prompt. Mirrors the cloud
|
|
233
|
+
path (assistantChat.ts). Sent on every runner:assistant_turn so a mid-chat
|
|
234
|
+
edit (or clear) takes effect on the next message — agentscope rebuilds the
|
|
235
|
+
system Msg from self.sys_prompt on every reply. DATA-ONLY: it shapes the
|
|
236
|
+
role/voice/behaviour but the platform rules, tool permissions and HITL gating
|
|
237
|
+
in the base prompt still govern."""
|
|
238
|
+
text = (str(ctx or "")).strip()
|
|
239
|
+
try:
|
|
240
|
+
if text:
|
|
241
|
+
block = (
|
|
242
|
+
"\n\n## The persona and standing instructions the user set for you "
|
|
243
|
+
"(ADOPT THIS as your role, voice and priorities for this conversation; "
|
|
244
|
+
"when asked who or what you are, answer AS this persona). It shapes "
|
|
245
|
+
"behaviour and tone but NEVER grants new tools or permissions, relaxes "
|
|
246
|
+
"the autonomy/HITL gating, reaches another tenant's data, or overrides "
|
|
247
|
+
"the platform rules above.\n" + text + "\n"
|
|
248
|
+
)
|
|
249
|
+
agent._sys_prompt = base_prompt + block
|
|
250
|
+
else:
|
|
251
|
+
agent._sys_prompt = base_prompt
|
|
252
|
+
except Exception:
|
|
253
|
+
pass
|
|
254
|
+
|
|
255
|
+
|
|
215
256
|
def _emit(turn_id: str, kind: str, **fields) -> None:
|
|
216
257
|
"""Write one structured event line to stdout (flushed) for the runner to relay."""
|
|
217
258
|
try:
|
|
@@ -366,6 +407,11 @@ def _build_agent():
|
|
|
366
407
|
"to find the right content yourself. Keep going until the task is COMPLETE (e.g. "
|
|
367
408
|
"all N comments posted) or you are genuinely blocked; only then report what you "
|
|
368
409
|
"did and what (if anything) is blocked.\n"
|
|
410
|
+
"- NEVER fabricate a reason for stopping. Do NOT claim 'the connection dropped', "
|
|
411
|
+
"'I lost connection', 'the session ended' or invent ANY infra failure — you "
|
|
412
|
+
"cannot observe that and it is almost always false. If a phone action is slow or "
|
|
413
|
+
"errors, RETRY it; only if it truly won't recover after retries do you stop, and "
|
|
414
|
+
"then state the EXACT tool that failed + what the screen showed.\n"
|
|
369
415
|
if phone_enabled else ""
|
|
370
416
|
)
|
|
371
417
|
connector_rule = (
|
|
@@ -642,6 +688,9 @@ def main() -> int:
|
|
|
642
688
|
_log("boot failed:\n" + traceback.format_exc())
|
|
643
689
|
_emit("", "error", message=f"assistant host failed to start: {exc}")
|
|
644
690
|
return 1
|
|
691
|
+
# Capture the freshly-built BASE system prompt (before any static context is
|
|
692
|
+
# folded in) so each turn can deterministically rebuild base + persona.
|
|
693
|
+
base_sys_prompt = getattr(agent, "_sys_prompt", "") or ""
|
|
645
694
|
|
|
646
695
|
# PR4: report memory watermark + host identity + generation so the server can
|
|
647
696
|
# decide whether to offer a generation-bound rehydrate snapshot.
|
|
@@ -721,6 +770,10 @@ def main() -> int:
|
|
|
721
770
|
# it here (before _run_turn) is enough — no agent rebuild needed.
|
|
722
771
|
if "hitl_mode" in req:
|
|
723
772
|
_apply_hitl_mode(req.get("hitl_mode"))
|
|
773
|
+
# Per-turn STATIC CONTEXT: fold the conversation's persona / standing
|
|
774
|
+
# instructions into the system prompt before running the turn (parity with
|
|
775
|
+
# the cloud path; handles set / edit / clear mid-conversation).
|
|
776
|
+
_apply_static_context(agent, base_sys_prompt, req.get("static_context"))
|
|
724
777
|
if not message:
|
|
725
778
|
_emit(turn_id, "done")
|
|
726
779
|
continue
|
|
@@ -728,6 +781,7 @@ def main() -> int:
|
|
|
728
781
|
# the ollama context (no-op for every other provider / when unchanged).
|
|
729
782
|
_sync_ollama_memory_budget(agent)
|
|
730
783
|
_run_turn(agent, turn_id, message)
|
|
784
|
+
_emit_usage(agent, turn_id)
|
|
731
785
|
|
|
732
786
|
|
|
733
787
|
if __name__ == "__main__":
|
package/dist/connection.js
CHANGED
|
@@ -1169,8 +1169,10 @@ export async function connect(opts) {
|
|
|
1169
1169
|
// (mirrored to MEL_HITL_MODE) BEFORE running the turn, so a mid-session flip
|
|
1170
1170
|
// takes effect on the very next message. Fail-safe: unknown ⇒ "safe".
|
|
1171
1171
|
const hitlMode = (payload.hitlMode === "autonomous" || payload.hitlMode === "payments_only") ? payload.hitlMode : "safe";
|
|
1172
|
+
// static_context (persona / standing instructions) is forwarded per turn; the
|
|
1173
|
+
// host folds it into its system prompt before running (parity with cloud).
|
|
1172
1174
|
try {
|
|
1173
|
-
s.proc.stdin?.write(JSON.stringify({ turnId: payload.turnId, message: payload.message, hitl_mode: hitlMode }) + "\n");
|
|
1175
|
+
s.proc.stdin?.write(JSON.stringify({ turnId: payload.turnId, message: payload.message, hitl_mode: hitlMode, static_context: typeof payload.staticContext === "string" ? payload.staticContext : "" }) + "\n");
|
|
1174
1176
|
}
|
|
1175
1177
|
catch (e) {
|
|
1176
1178
|
socket.emit("runner:assistant_event", { sessionId: payload.sessionId, turnId: payload.turnId, kind: "error", message: `turn write failed: ${e?.message || e}` });
|
package/package.json
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@melaya/runner",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Run Melaya AI pipelines locally with your own LM Studio or Ollama models",
|
|
5
|
-
"license": "UNLICENSED",
|
|
6
|
-
"private": false,
|
|
7
|
-
"type": "module",
|
|
8
|
-
"bin": {
|
|
9
|
-
"melaya-runner": "dist/cli.js"
|
|
10
|
-
},
|
|
11
|
-
"main": "dist/index.js",
|
|
12
|
-
"files": [
|
|
13
|
-
"dist/**/*.js",
|
|
14
|
-
"dist/**/*.d.ts",
|
|
15
|
-
"dist/**/*.py",
|
|
16
|
-
"localRagIngest.py",
|
|
17
|
-
"localRagRetrieve.py",
|
|
18
|
-
"nltk_data/**",
|
|
19
|
-
"README.md"
|
|
20
|
-
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "tsc && node -e \"const fs=require('fs'); fs.copyFileSync('localRagIngest.py','dist/localRagIngest.py'); fs.copyFileSync('localRagRetrieve.py','dist/localRagRetrieve.py'); fs.copyFileSync('src/assistantHost.py','dist/assistantHost.py')\"",
|
|
23
|
-
"prepublishOnly": "npm run build"
|
|
24
|
-
},
|
|
25
|
-
"dependencies": {
|
|
26
|
-
"chalk": "^5.3.0",
|
|
27
|
-
"commander": "^12.0.0",
|
|
28
|
-
"ora": "^8.0.0",
|
|
29
|
-
"playwright": "^1.47.0",
|
|
30
|
-
"socket.io-client": "^4.8.0"
|
|
31
|
-
},
|
|
32
|
-
"devDependencies": {
|
|
33
|
-
"@types/node": "^20.0.0",
|
|
34
|
-
"typescript": "^5.5.0"
|
|
35
|
-
},
|
|
36
|
-
"engines": {
|
|
37
|
-
"node": ">=18"
|
|
38
|
-
},
|
|
39
|
-
"publishConfig": {
|
|
40
|
-
"access": "public"
|
|
41
|
-
}
|
|
42
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@melaya/runner",
|
|
3
|
+
"version": "1.0.112",
|
|
4
|
+
"description": "Run Melaya AI pipelines locally with your own LM Studio or Ollama models",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"private": false,
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"melaya-runner": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist/**/*.js",
|
|
14
|
+
"dist/**/*.d.ts",
|
|
15
|
+
"dist/**/*.py",
|
|
16
|
+
"localRagIngest.py",
|
|
17
|
+
"localRagRetrieve.py",
|
|
18
|
+
"nltk_data/**",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc && node -e \"const fs=require('fs'); fs.copyFileSync('localRagIngest.py','dist/localRagIngest.py'); fs.copyFileSync('localRagRetrieve.py','dist/localRagRetrieve.py'); fs.copyFileSync('src/assistantHost.py','dist/assistantHost.py')\"",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"chalk": "^5.3.0",
|
|
27
|
+
"commander": "^12.0.0",
|
|
28
|
+
"ora": "^8.0.0",
|
|
29
|
+
"playwright": "^1.47.0",
|
|
30
|
+
"socket.io-client": "^4.8.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^20.0.0",
|
|
34
|
+
"typescript": "^5.5.0"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
}
|
|
42
|
+
}
|