@melaya/runner 1.0.88 → 1.0.90

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.
@@ -248,7 +248,11 @@ def _build_agent():
248
248
  api_key="", # model.py resolves the provider's own creds (OAuth off disk / localhost)
249
249
  # Phone tasks are many-step (each comment ≈ screen_tree→tap→type→post), so
250
250
  # give them room like the device template (40); read-only Q&A needs few.
251
- max_iters=40 if phone_enabled else 8,
251
+ # Connector WRITE tasks are equally many-step (e.g. "message all my recent
252
+ # LinkedIn connections" = 1 list + N sends, each its own reasoning+HITL
253
+ # round), so they need the same headroom — 8 hit the cap mid-task and
254
+ # forced _summarizing() on a half-finished tool batch.
255
+ max_iters=40 if (phone_enabled or connector_services) else 8,
252
256
  reliability=True,
253
257
  bounded_memory=True,
254
258
  )
@@ -256,15 +260,39 @@ def _build_agent():
256
260
  return agent
257
261
 
258
262
 
263
+ _HOOKS_REGISTERED = False
264
+
265
+
259
266
  def _register_stream_hooks(agent) -> None:
260
- """Emit delta / tool events live as the agent produces output (pre_print gives
261
- cumulative snapshots per message; we forward the new suffix as a delta)."""
267
+ """Emit delta / tool events live as the agent produces output.
268
+
269
+ Registers agentscope CLASS hooks on ReActAgent — NOT instance hooks on the
270
+ object make_agent returned. With reliability=True (and bounded_memory) that
271
+ object is a WRAPPER around the real ReActAgent, so an instance hook on it
272
+ never fires when the inner agent runs its acting / print steps: the FE then
273
+ only ever saw the `round` event ("thinking…") and never the tool / delta
274
+ stream. Class hooks fire for the inner agent regardless of wrapping — the
275
+ exact mechanism the pipeline event bus uses (shared.runtime.events
276
+ .wire_agentscope_hooks). There's one agent per host process, so a class hook
277
+ is effectively instance-scoped here; it keys output to the in-flight turn via
278
+ _stream and no-ops between turns (turnId == "").
279
+
280
+ pre_print gives cumulative snapshots per message; we forward the new suffix
281
+ as a delta. post_acting gives the tool-call batch; one `tool` event each.
282
+ """
283
+ global _HOOKS_REGISTERED
284
+ if _HOOKS_REGISTERED:
285
+ return
262
286
  try:
263
287
  from shared.runtime.events import _flatten_agent_text
264
288
  except Exception:
265
289
  return
290
+ try:
291
+ from agentscope.agent import ReActAgent
292
+ except Exception:
293
+ return
266
294
 
267
- def _pre_print(*_args, **kwargs) -> None:
295
+ def _pre_print_hook(_agent, **kwargs) -> None:
268
296
  try:
269
297
  tid = _stream.get("turnId")
270
298
  if not tid:
@@ -283,7 +311,7 @@ def _register_stream_hooks(agent) -> None:
283
311
  except Exception:
284
312
  pass
285
313
 
286
- def _post_acting(*_args, **kwargs) -> None:
314
+ def _post_acting_hook(_agent, **kwargs) -> None:
287
315
  try:
288
316
  tid = _stream.get("turnId")
289
317
  if not tid:
@@ -295,11 +323,30 @@ def _register_stream_hooks(agent) -> None:
295
323
  except Exception:
296
324
  pass
297
325
 
298
- for hook_type, fn in (("pre_print", _pre_print), ("post_acting", _post_acting)):
326
+ # Our agentscope's hook registration is 3-arg: (hook_type, hook_name, hook).
327
+ # The ORIGINAL code here called register_INSTANCE_hook(hook_type, fn) — 2 args
328
+ # against a 3-arg method AND on the reliability WRAPPER rather than the inner
329
+ # ReActAgent → TypeError, silently swallowed → the hooks were NEVER registered.
330
+ # That is why the FE only ever saw the `round` event ("thinking…") and none of
331
+ # the tool / delta stream. Register CLASS hooks with the correct arity (2-arg
332
+ # kept as a defensive fallback in case the signature ever changes).
333
+ def _reg(hook_type: str, name: str, fn) -> bool:
299
334
  try:
300
- agent.register_instance_hook(hook_type, fn)
335
+ ReActAgent.register_class_hook(hook_type, name, fn) # 3-arg (vendored)
336
+ return True
337
+ except TypeError:
338
+ try:
339
+ ReActAgent.register_class_hook(hook_type, fn) # 2-arg (pip build)
340
+ return True
341
+ except Exception:
342
+ return False
301
343
  except Exception:
302
- pass
344
+ return False
345
+
346
+ ok_a = _reg("pre_print", "mel_assistant_delta", _pre_print_hook)
347
+ ok_b = _reg("post_acting", "mel_assistant_tool", _post_acting_hook)
348
+ _HOOKS_REGISTERED = ok_a or ok_b
349
+ _log(f"stream hooks registered (delta={ok_a} tool={ok_b})")
303
350
 
304
351
 
305
352
  def _run_turn(agent, turn_id: str, message: str) -> None:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melaya/runner",
3
- "version": "1.0.88",
3
+ "version": "1.0.90",
4
4
  "description": "Run Melaya AI pipelines locally with your own LM Studio or Ollama models",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,