Back to home page

EIC code displayed by LXR

 
 

    


Warning, /swf-monitor/docs/WRANGLER_AGENT.md is written in an unsupported language. File is not indexed.

0001 # Wrangler Agent
0002 
0003 The wrangler agent is the platform's always-on executor for bounded work that
0004 is neither a privileged production action nor an interactive dialog: LLM
0005 judgments over production state, and the scripts that prepare and record them.
0006 It is built on `BaseAgent` from swf-common-lib, so it has the identity,
0007 liveness, and monitor visibility of every other agent, and on
0008 [wrangle-ai](https://github.com/BNLNPPS/wrangle-ai), whose `Wrangler` is its
0009 work loop: a durable work queue, a wake signal in place of polling, bounded
0010 concurrency, dedup of in-flight work, and recovery of work a dead process left
0011 behind. Its first handler is the alarm responder specified in
0012 [ALARM_QUEUE.md](ALARM_QUEUE.md).
0013 
0014 ## Role beside the production ops agent
0015 
0016 The production ops agent
0017 ([EPICPROD_OPS_AGENT.md](https://github.com/BNLNPPS/swf-epicprod/blob/main/docs/EPICPROD_OPS_AGENT.md))
0018 is the credentialed executor: it holds the PanDA token and the Rucio proxy, and
0019 every privileged action passes through it. wrangle-ai is that agent's pattern
0020 rebuilt as a generic core, and the wrangler agent is its first use in the
0021 platform. The two agents divide by the nature of the work, not by trigger:
0022 
0023 | | Production ops agent | Wrangler agent |
0024 |---|---|---|
0025 | Work | Deterministic doers under production credentials | LLM doers and their deterministic preparation and recording |
0026 | Queue | Bus messages, consumed once; the action stream is the record | Durable worker rows in the bullpen, claimed, retried, and reclaimed; the action stream is the record |
0027 | Wake | Bus delivery | Postgres `NOTIFY` from any producer, in any process or OS account |
0028 | Privileged actions | Executes and verifies them | Requests them from the ops agent through the task-operation queue |
0029 
0030 The ops agent is not extended with LLM work. An LLM doer is the class of
0031 work most able to exhaust a host in time and memory, and it belongs in a
0032 process whose loss costs a diagnosis rather than a submission. No migration of
0033 ops-agent handlers onto the wrangler is planned; the pattern for one, should a
0034 handler come to need durable rows or scheduled execution, is the migration
0035 section of wrangle-ai's `docs/scheduler.md`.
0036 
0037 ## Construction
0038 
0039 - **BaseAgent.** The agent runs under a fixed namespace with the standard
0040   control messages (`health_ping`, `shutdown`) on its own queue, so it appears
0041   in the agent list, answers the cleaner-killer's liveness ping, and stops
0042   deliberately with the same exit convention as the ops agent. Work does not
0043   arrive on the bus.
0044 - **Bullpen.** `PgBullpen` from `wrangle_ai.postgres` over a `wrangle_workers`
0045   table in the monitor database. The table is created by a Django migration
0046   whose DDL is a frozen copy of the package schema, and read by an unmanaged
0047   model for the UI. A subclass hooks `mark_failed` to record an action-stream
0048   incident (`wrangler_worker_failed`, level ERROR, with the worker type, id,
0049   and error) so every failure surfaces uniformly, and `mark_done` to record
0050   `wrangler_worker_done` with the measured duration. The agent does not boot
0051   Django; the bullpen is psycopg, and the records go through the REST twin of
0052   `log_epicprod_action`, as the ops agent's do.
0053 - **Bell.** `PgBell` on the monitor database. A producer inserts a worker row
0054   and rings with `pg_notify`; the web tier does this through its ordinary
0055   Django connection. A monitor-side helper, `enqueue_worker(type, payload)`,
0056   is the single producer entry point.
0057 - **Claim restriction.** The agent claims only the worker types it has
0058   registered, so a second agent with a different handler set can share the
0059   table.
0060 - **Pulse.** Once per loop pass the agent writes `wrangler_heartbeat` to
0061   SysConfig with the in-flight count. The loop never executes work, so a
0062   stale pulse means a stopped process, and the System page reads it as such.
0063 
0064 ## Handlers and doers
0065 
0066 A handler is registered with a worker type, a timeout, and a dedup key
0067 function. It runs a doer, a subprocess with a hard timeout, and records the
0068 outcome; the handler is deterministic and the doer is the only place an LLM
0069 runs. The LLM doer is `claude -p` under subscription authentication with the
0070 API key removed from its environment, per the platform rule that unattended
0071 LLM operations never use metered access, and with the MCP configuration of the
0072 production checkout, which carries the swf-monitor MCP server. The doer
0073 returns a structured result; the handler parses it and writes the record. The
0074 model writes nothing to production state.
0075 
0076 ### `alarm_respond`
0077 
0078 The first handler. The notice router's `alarm-responder` push plugin enqueues
0079 one worker per matching `alarm_raised` or `alarm_renotified` incident whose
0080 event carries no response transition, with the event id, alarm name, and
0081 transition id as payload and `alarm:<event id>` as the dedup key, so a
0082 renotify while an analysis is in flight is a recorded skip. The doer reads the
0083 event, its transitions, and the evidence the alarm class names (the action
0084 stream, PanDA, Rucio) through MCP, and returns a diagnosis, a proposed action
0085 from the alarm class's allowed set, and its reasoning. The handler posts a
0086 `response_proposed` transition. In `act` mode, for reversible actions only, the
0087 handler additionally queues the action through the existing task-operation
0088 path under source `alarm-responder`, subject to the per-class hourly cap in
0089 SysConfig, and enqueues a follow-up worker that waits for the operation's
0090 verified outcome and posts `response_taken` and `verified`. Modes, caps, and
0091 the transition vocabulary are specified in ALARM_QUEUE.md.
0092 
0093 ## Trust boundary
0094 
0095 The agent runs as the operating account, the same account as the ops agent, so
0096 the boundary between them is not an OS boundary: an LLM doer under that
0097 account can read what the account can read. The effective boundary is the
0098 tool surface the doer is given and the rule that a production action is a
0099 request to the ops agent, recorded as a task operation with a verified
0100 outcome, never a direct call. A dedicated service account for the wrangler,
0101 with its own subscription login, would add an OS boundary and is a deployment
0102 choice, not a design requirement.
0103 
0104 ## Data
0105 
0106 - `wrangle_workers` (frozen migration, unmanaged model): worker id, type,
0107   payload, status, result, error, attempts, claiming agent and process, doer
0108   process, and timestamps, as defined by `wrangle_ai.postgres`.
0109 - SysConfig: `wrangler_heartbeat`; the responder caps per alarm class.
0110 - Action stream: `wrangler_worker_done`, `wrangler_worker_failed`, declared in
0111   `ACTION_DEFAULTS`.
0112 
0113 ## Operation
0114 
0115 The agent is a systemd unit, `swf-wrangler-agent.service`, modeled on the ops
0116 agent's: the operating account, `Restart=always` with a burst cap, and the
0117 deliberate-stop exit code that systemd does not restart. The deploy script
0118 restarts it with the ops agent and the canary agent, so a deploy picks up new
0119 handler code; in-flight doers survive a restart when they follow the detached
0120 self-completing convention, and the bullpen's liveness-checked reclaim leaves
0121 them alone. wrangle-ai enters the swf-monitor requirements as a floor. Worker
0122 rows are listed on a monitor page with status, type, timing, and error, the
0123 work history the action stream does not carry.
0124 
0125 ## Delivery sequence
0126 
0127 1. The package, the migration, and the agent with its control messages, pulse,
0128    unit, and deploy restart; a no-op handler proves the loop end to end.
0129 2. `alarm_respond` in `advise` mode, with the router plugin as producer
0130    (ALARM_QUEUE.md step 4).
0131 3. `act` mode and the verification follow-up (ALARM_QUEUE.md step 5).
0132 4. Scheduled work through wrangle-ai's Foreman and Roster when a first
0133    scheduled candidate exists.
0134 
0135 ## Status
0136 
0137 Design. Nothing in this document is implemented.