feat(agent): add monitor supervisor for long-running processes - #774
feat(agent): add monitor supervisor for long-running processes#774lu-zero wants to merge 8 commits into
Conversation
6c237be to
cd63cae
Compare
|
@tontinton this is a bit bigger than the minimal proof of concept I built initially but after using it all day I ended up with a richer tool. It seems working well enough, if you prefer I can try to slice it in smaller commits. |
|
Super cool, but any reason for the plugin to not remain yours, outside the repo? |
|
The plugin layer doesn't have all the hooks needed, if you prefer I can send a PR to expand the plugin surface, but I'd consider this kind of feature useful enough to be in the standard set. |
|
Yeah we should add the needed lua APIs instead, what's missing? |
|
Few hooks to cleanup and some uniformity across the frontends, I'll prepare something later. Shall we consider making somehow easier to find and install lua plugins though? |
3567390 to
f79c88d
Compare
54f00ba to
df0a069
Compare
SessionReset is TUI-only (`/new`). Plugins that need to clean up when a session goes away on tab delete, load, ACP replace, or headless completion had no hook. EventHandle::end_session fires SessionEnd with the session being left behind. Wired on TUI reset/load/delete/shutdown, ACP session replace/EOF, and headless completion.
Plugins can start jobs but could not inspect them: no pid, no command, no trailing output unless they kept their own buffers. jobinfo snapshots a job this plugin can see. joblist lists live ones. jobstart tail=N keeps a ring of stdout/stderr lines for that snapshot (default 20). Task and plugin jobs still disappear on exit, so this is a live view. After-exit peek and session filters can grow on top.
Plugin jobs die on /reload, so a monitor implemented only in Lua cannot outlive its own code. owner = "session" keeps the process until that session ends; the starting plugin can still inspect and stop it after a reload. notify posts a mailbox observation from the host, so exit notify does not depend on a Lua on_exit callback. SessionEnd fires first so handlers can inspect or stop those jobs, then the host reaps them. Folds the first review round: kill_job skips already-exited pids, jobwait reports truncated=true for the captured tail, elapsed_secs freezes at exit, and joblist includes exited session jobs.
A Lua monitor needs to grow a log from job and autocmd callbacks. Those callbacks used to resume inline, so the first maki.fs await died with a yield-across-C-call error. Callbacks now run in their own coroutine under a detached task scope, so they can suspend. SessionEnd wait is bounded on process-exit paths so a suspending handler cannot hang quit. maki.fs.append grows a file without replacing it, through smol::unblock so writes stay ordered. A failing job callback no longer aborts jobwait: the wait still collects the exit code, matching the detached dispatch pump. Also folds later review: jobforget, joblist without cloned tails, imported MakiId, and the per-callback / delivery-scope pinning.
ui_roundtrip waited forever if the event loop had already stopped draining, so a SessionEnd handler that touched winsaveview on quit deadlocked the Lua thread against teardown. It now times out. ACP called the blocking end_session wait on the smol executor, which paused stdin for the whole grace period. Session replace and EOF now poll end_session_async instead. The maki.fn module example passed the job id to on_exit as if it were the exit code.
The previous monitor was a native supervisor (maki-agent::monitor) with
its own registry, log-writing threads, and reap calls hand-wired into
every session-teardown path. feat/plugin-session-jobs built exactly the
host hooks that made the native version unnecessary: owner = "session"
jobs that survive plugin reload, a generic SessionEnd fired on every
teardown path already, and jobinfo/joblist/jobwait/jobstop that see
exited session jobs.
plugins/monitor/init.lua rebuilds the same five tools (monitor,
monitor_stop, monitor_list, monitor_peek, monitor_wait) entirely on
maki.fn.jobstart/jobinfo/joblist/jobwait/jobstop plus maki.fs.append,
writing the same logs_dir()/{session}/monitor-{id}/{stdout,stderr,meta}
layout the native version used. A SessionEnd autocmd removes the
session's log directory; process teardown is already handled by the
host's kill_session after SessionEnd dispatches.
Registered as a bundled plugin (maki-config, maki-lua/loader), added to
the generated tool docs (maki-docgen), and ported the long-running
commands concept page.
…t UI --allowed-tools validated against DEFAULT_BUILTINS plus edit sub-tools, so monitor_stop/list/peek/wait were rejected at CLI parse time. In headless mode, parse_session fell back to maki.session.current(), a UI roundtrip nobody drains outside the TUI; tool calls then failed with 'ui request timed out'. Both now use the paths designed for this: the sub-tool name list mirrors EDIT_SUB_TOOLS, and handlers take ctx:session_id() which carries the calling session on every frontend.
The SessionEnd autocmd wiped the whole per-session logs dir, so headless callers could never collect stdout/stderr/meta after --print returned, and /new erased failure logs of finished runs in the TUI. Jobs still get reaped by the host; the files stay.
f79c88d to
c76416c
Compare
|
Restacked on current #799 (the five-commit session-jobs series on latest The native supervisor is gone. What remains on top of #799:
|
Follow-up to #799. Tony asked whether monitor can live as a standalone Lua plugin. It can, once those host hooks land:
owner = "session"jobs,SessionEndon every teardown path, andjobinfo/joblist/jobwait/jobstopthat see exited session jobs.This PR sits on #799 and replaces the native
maki-agent::monitorsupervisor withplugins/monitor/init.lua.Contract
Do not
sleepor poll.notify_on_successdefaults on; set it false to hear only about failures.Commits on top of #799
monitor,monitor_stop,monitor_list,monitor_peek,monitor_wait) onmaki.fn.jobstart/jobinfo/joblist/jobwait/jobstopplusmaki.fs.append. Same log layout as the native supervisor:logs_dir()/{session}/monitor-{id}/{stdout,stderr,meta}.--allowed-toolsacceptsmonitor_stop/list/peek/wait. Handlers takectx:session_id()so headless calls do not round-trip through the UI.--printand/newcan still collect stdout/stderr/meta.Test plan
cargo fmt --all -- --checkand stylua onplugins/monitor/cargo clippyonmaki-lua,maki-config,maki-agent(-D warnings)cargo nextest run -p maki-lua -p maki-config -p maki-agentjust gen-docs-check