Implement governed auto-claim loop on task_plane:
- SchedulabilityProof model (5-segment persisted diagnostic snapshot) + ProofBuilder
- authoritative_claim_recheck (A23: cross-tenant/task/generation/lease/capacity)
- SchedulingService wiring TaskScheduler to HTTP long_poll/poll/schedule
- governed_claim single-transaction (proof→recheck→claim→receipt→event)
- HttpRunnerTransport (real transport, renew with claim_id self-resolution)
- AgentPullRunner discover_once handles idle/no-task (REQ-03c)
- receipt/readback endpoints (/proofs, /receipts, /tasks/{id}/receipts)
Pure stdlib, no new deps; 25 tests pass (22 R2 + 2 heartbeat + 1 idle). Base: 3c320ae.
56 lines
2.4 KiB
Python
56 lines
2.4 KiB
Python
"""Small operational CLI for the Agent Pull Runner contract.
|
|
|
|
Default mode talks to a live governed TaskPlane HTTP API via HttpRunnerTransport
|
|
(--base-url / --token). --self-test keeps an in-process stub transport for
|
|
offline smoke checks.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
|
|
from agent_pull_runner import AgentPullRunner, RunnerConfig
|
|
from task_plane.http_transport import HttpRunnerTransport
|
|
|
|
|
|
class _NoopTransport:
|
|
def register_worker(self, worker_id, capabilities): return {"status": "registered", "worker_id": worker_id, "capabilities": list(capabilities)}
|
|
def heartbeat(self, worker_id): return {"status": "alive", "worker_id": worker_id}
|
|
def long_poll(self, worker_id, timeout_seconds): return None
|
|
def poll(self, worker_id): return None
|
|
def claim(self, worker_id, task): return task
|
|
def renew(self, worker_id, task_id): return {"status": "renewed", "task_id": task_id}
|
|
def report_progress(self, worker_id, task_id, payload): return {"status": "progress_recorded", "task_id": task_id}
|
|
def report_result(self, worker_id, task_id, payload): return {"status": "result_recorded", "task_id": task_id}
|
|
def report_evidence(self, worker_id, task_id, payload): return {"status": "evidence_recorded", "task_id": task_id}
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description="AIOS Agent Pull Runner")
|
|
parser.add_argument("--worker-id", default="self-test-worker")
|
|
parser.add_argument("--base-url", default="http://127.0.0.1:8000")
|
|
parser.add_argument("--token", default="")
|
|
parser.add_argument("--actor-identity", default="")
|
|
parser.add_argument("--self-test", action="store_true")
|
|
args = parser.parse_args()
|
|
if args.self_test:
|
|
transport = _NoopTransport()
|
|
else:
|
|
transport = HttpRunnerTransport(
|
|
args.base_url,
|
|
token=args.token,
|
|
actor_identity=args.actor_identity or None,
|
|
)
|
|
runner = AgentPullRunner(
|
|
RunnerConfig(worker_id=args.worker_id, fallback_seconds=60), transport
|
|
)
|
|
if args.self_test:
|
|
print(json.dumps({"status": "PASS", "registration": runner.register(), "fallback_seconds": runner.config.fallback_seconds}, sort_keys=True))
|
|
return 0
|
|
print(json.dumps({"status": "READY", "worker_id": args.worker_id, "base_url": args.base_url}, sort_keys=True))
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|