@melaya/runner 1.0.106 → 1.0.109

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.
@@ -421,8 +421,11 @@ def _build_agent():
421
421
  # the task is finished. Give phone runs real headroom (they are HITL-gated,
422
422
  # so each write still needs the user's tap — cost stays bounded). Connector
423
423
  # WRITE fan-outs (1 list + N sends, each its own reasoning+HITL round) keep
424
- # the 40 that fits them; read-only Q&A needs very few.
425
- max_iters=100 if phone_enabled else (40 if connector_services else 8),
424
+ # the 40 that fits them; read-only Q&A needs very few. Phone raised + env-tunable
425
+ # for long-horizon tasks (100s of steps) now that per-step tokens are pruned +
426
+ # cached; each write is still HITL-gated so cost stays bounded.
427
+ max_iters=(int(os.environ.get("MEL_ASSISTANT_MAX_ITERS_PHONE", "300") or "300") if phone_enabled
428
+ else (40 if connector_services else 8)),
426
429
  reliability=True,
427
430
  bounded_memory=True,
428
431
  )
@@ -1030,6 +1030,13 @@ export async function connect(opts) {
1030
1030
  activeAssistants.set(sid, session);
1031
1031
  console.log(chalk.hex("#7c6ff0")(` ◆ Assistant session ${sid.slice(0, 10)}… (${payload.provider})`));
1032
1032
  proc.stdout?.on("data", (data) => {
1033
+ // ANY host output means the turn is actively working — refresh the idle
1034
+ // clock. Without this, lastActivity was set ONLY at turn start (assistant_turn),
1035
+ // so a SINGLE long turn (a phone task is one turn with ~100 tool calls streaming
1036
+ // for >15 min) was reaped mid-action by the idle sweep despite continuous
1037
+ // activity ("idle-swept" while properly working). Now only a genuinely silent
1038
+ // host (no output for ASSISTANT_IDLE_MS) is swept.
1039
+ session.lastActivity = Date.now();
1033
1040
  session.stdoutBuf += data.toString();
1034
1041
  let idx;
1035
1042
  while ((idx = session.stdoutBuf.indexOf("\n")) >= 0) {
@@ -1170,6 +1177,14 @@ export async function connect(opts) {
1170
1177
  activeAssistants.delete(String(payload.sessionId));
1171
1178
  }
1172
1179
  });
1180
+ // Keepalive: the server is blocked waiting on the user's behalf (a HITL approval
1181
+ // poll, a slow phone action) so the host emits no stdout, but the turn is ALIVE.
1182
+ // Refresh the idle clock so the idle sweep doesn't reap a host mid-approval.
1183
+ socket.on("runner:assistant_keepalive", (payload) => {
1184
+ const s = activeAssistants.get(String(payload.sessionId || ""));
1185
+ if (s)
1186
+ s.lastActivity = Date.now();
1187
+ });
1173
1188
  // Cooperative cancel: the user pressed STOP in chat. Write a cancel line to the
1174
1189
  // host's stdin — its stdin reader thread flips a flag the running turn's
1175
1190
  // hooks poll, so the agent loop aborts BETWEEN steps (right where the next
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melaya/runner",
3
- "version": "1.0.106",
3
+ "version": "1.0.109",
4
4
  "description": "Run Melaya AI pipelines locally with your own LM Studio or Ollama models",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,