@melaya/runner 1.0.94 → 1.0.95
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 +34 -0
- package/dist/connection.js +20 -1
- package/package.json +1 -1
package/dist/assistantHost.py
CHANGED
|
@@ -95,6 +95,30 @@ if not isinstance(sys.stdout, _RedactingStdout):
|
|
|
95
95
|
sys.stdout = _RedactingStdout(sys.stdout)
|
|
96
96
|
|
|
97
97
|
|
|
98
|
+
_HITL_MODES = ("safe", "autonomous", "payments_only")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _apply_hitl_mode(mode: str | None) -> None:
|
|
102
|
+
"""Set the assistant autonomy mode env AND mirror it into MEL_HITL_MODE.
|
|
103
|
+
|
|
104
|
+
The runner spawns this host with MEL_ASSISTANT_HITL_MODE (the assistant's
|
|
105
|
+
autonomy mode). The connector-write gate (lazy_registry._maybe_gate_write)
|
|
106
|
+
reads MEL_ASSISTANT_HITL_MODE, but phone.py._cmd — running INSIDE this same
|
|
107
|
+
host process — stamps the device command body from MEL_HITL_MODE. So we
|
|
108
|
+
MIRROR the assistant mode into MEL_HITL_MODE here, giving the phone tools
|
|
109
|
+
the operator's choice too. Called once at boot and again per turn (the TS
|
|
110
|
+
side passes an updated `hitl_mode` on each turn payload; absent ⇒ keep the
|
|
111
|
+
current/spawn value). Unknown / empty ⇒ "safe" (fail-safe)."""
|
|
112
|
+
if mode is None:
|
|
113
|
+
# Boot-time mirror: honour whatever the runner exported at spawn.
|
|
114
|
+
mode = os.environ.get("MEL_ASSISTANT_HITL_MODE", "safe")
|
|
115
|
+
normalized = (str(mode or "safe")).strip().lower()
|
|
116
|
+
if normalized not in _HITL_MODES:
|
|
117
|
+
normalized = "safe"
|
|
118
|
+
os.environ["MEL_ASSISTANT_HITL_MODE"] = normalized
|
|
119
|
+
os.environ["MEL_HITL_MODE"] = normalized
|
|
120
|
+
|
|
121
|
+
|
|
98
122
|
def _emit(turn_id: str, kind: str, **fields) -> None:
|
|
99
123
|
"""Write one structured event line to stdout (flushed) for the runner to relay."""
|
|
100
124
|
try:
|
|
@@ -450,6 +474,9 @@ def _stdin_reader(q: "queue.Queue[str]") -> None:
|
|
|
450
474
|
|
|
451
475
|
def main() -> int:
|
|
452
476
|
_log(f"booting (provider={os.environ.get('MEL_ASSISTANT_PROVIDER')})")
|
|
477
|
+
# Mirror the spawn-time assistant autonomy mode into MEL_HITL_MODE so the
|
|
478
|
+
# in-process phone tools (phone.py._cmd) see it from turn one.
|
|
479
|
+
_apply_hitl_mode(None)
|
|
453
480
|
try:
|
|
454
481
|
agent = _build_agent()
|
|
455
482
|
except Exception as exc:
|
|
@@ -482,6 +509,13 @@ def main() -> int:
|
|
|
482
509
|
continue
|
|
483
510
|
turn_id = str(req.get("turnId") or "")
|
|
484
511
|
message = str(req.get("message") or "")
|
|
512
|
+
# Per-turn autonomy mode: the TS side carries an updated `hitl_mode`
|
|
513
|
+
# on runner:assistant_turn so a mid-session flip takes effect next
|
|
514
|
+
# turn. Absent ⇒ keep the current (spawn / previous-turn) mode. The
|
|
515
|
+
# connector gate + phone tools read the env at call-time, so setting
|
|
516
|
+
# it here (before _run_turn) is enough — no agent rebuild needed.
|
|
517
|
+
if "hitl_mode" in req:
|
|
518
|
+
_apply_hitl_mode(req.get("hitl_mode"))
|
|
485
519
|
if not message:
|
|
486
520
|
_emit(turn_id, "done")
|
|
487
521
|
continue
|
package/dist/connection.js
CHANGED
|
@@ -907,6 +907,21 @@ export async function connect(opts) {
|
|
|
907
907
|
MEL_ASSISTANT_CONNECTORS: Array.isArray(payload.connectors) ? payload.connectors.join(",") : "",
|
|
908
908
|
// Gate write connector-tools behind the in-chat approval card (fail-safe).
|
|
909
909
|
MEL_ASSISTANT_CONNECTOR_HITL: Array.isArray(payload.connectors) && payload.connectors.length ? "1" : "",
|
|
910
|
+
// HITL autonomy mode ("safe" | "autonomous" | "payments_only"). The host
|
|
911
|
+
// reads this at start; each turn's frame can flip it (see assistant_turn).
|
|
912
|
+
// Fail-safe: unknown ⇒ "safe".
|
|
913
|
+
MEL_ASSISTANT_HITL_MODE: (payload.hitlMode === "autonomous" || payload.hitlMode === "payments_only") ? payload.hitlMode : "safe",
|
|
914
|
+
// Run context for phone-driving assistant turns. The assistant host has
|
|
915
|
+
// no pipeline MEL_RUN_ID, so without this phone.py._cmd omits `run_id`,
|
|
916
|
+
// the server's arm block (phone.ts, `if (runId)`) never fires, and the
|
|
917
|
+
// device never receives `hitlMode` — Autonomous still shows publish
|
|
918
|
+
// cards on the runner-assistant surface. Use the SAME stable
|
|
919
|
+
// `assistant:{userId}` runId the cloud assistant path uses (sid is
|
|
920
|
+
// `userId:conversationId`) so the arm / kill / active-run plumbing stays
|
|
921
|
+
// consistent across surfaces. assistantHost mirrors MEL_ASSISTANT_HITL_MODE
|
|
922
|
+
// → MEL_HITL_MODE so phone.py stamps the mode on the command body.
|
|
923
|
+
MEL_RUN_ID: `assistant:${sid.split(":")[0]}`,
|
|
924
|
+
MEL_PIPELINE_NAME: "Melaya · Assistant",
|
|
910
925
|
// Luma browser bridge (same injection as pipeline runs, line ~431): lets
|
|
911
926
|
// shared/tools/luma.py route /event/register through Playwright and bypass
|
|
912
927
|
// Cloudflare's write rule. Reads keep using aiohttp. Empty when no signed-in
|
|
@@ -970,8 +985,12 @@ export async function connect(opts) {
|
|
|
970
985
|
return;
|
|
971
986
|
}
|
|
972
987
|
s.lastActivity = Date.now();
|
|
988
|
+
// Per-turn hitl_mode: the host applies it to os.environ["MEL_ASSISTANT_HITL_MODE"]
|
|
989
|
+
// (mirrored to MEL_HITL_MODE) BEFORE running the turn, so a mid-session flip
|
|
990
|
+
// takes effect on the very next message. Fail-safe: unknown ⇒ "safe".
|
|
991
|
+
const hitlMode = (payload.hitlMode === "autonomous" || payload.hitlMode === "payments_only") ? payload.hitlMode : "safe";
|
|
973
992
|
try {
|
|
974
|
-
s.proc.stdin?.write(JSON.stringify({ turnId: payload.turnId, message: payload.message }) + "\n");
|
|
993
|
+
s.proc.stdin?.write(JSON.stringify({ turnId: payload.turnId, message: payload.message, hitl_mode: hitlMode }) + "\n");
|
|
975
994
|
}
|
|
976
995
|
catch (e) {
|
|
977
996
|
socket.emit("runner:assistant_event", { sessionId: payload.sessionId, turnId: payload.turnId, kind: "error", message: `turn write failed: ${e?.message || e}` });
|