feat: priority system, batch tasks, action feedback, event daemon
- Priority system: GET /api/state/priorities, POST /api/action/priority_global, POST /api/action/priority_type - Batch system: POST /api/action/batch with per-action result tracking - Enhanced action feedback with error codes and AI suggestions: cell_occupied, cell_solid, cell_occupied_by_dupe, material_shortage, etc. - Event stream: GET /api/state/events?since=&limit= for incremental polling - Event daemon: scripts/event_daemon.py continuously polls events, classifies by severity, auto-triggers analysis on critical events - Games state now reports suffocating/starving/stressed counts - Cell data includes isDiggable and isSafeForDupe flags - Added 'events', 'queue', 'batch', 'priority_global', 'priority_type' CLI commands - Added sample batch plan file
This commit is contained in:
149
tools/oni_api.py
149
tools/oni_api.py
@ -353,6 +353,140 @@ def cmd_harvest(args):
|
||||
result = api_post('/api/action/harvest', {"x": int(args[0]), "y": int(args[1])})
|
||||
print(json.dumps(result, indent=2, ensure_ascii=False))
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Event / Queue / Batch / Priority
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def cmd_events(args):
|
||||
"""Poll game events. Usage: events [since] [limit]"""
|
||||
since = args[0] if len(args) > 0 else "0"
|
||||
limit = args[1] if len(args) > 1 else "50"
|
||||
data = api_get(f"/api/state/events?since={since}&limit={limit}")
|
||||
if 'error' in data:
|
||||
print(f"Error: {data['error']}")
|
||||
return
|
||||
events = data.get('events', [])
|
||||
next_seq = data.get('next_seq', 0)
|
||||
has_more = data.get('has_more', False)
|
||||
|
||||
if not events:
|
||||
print("No new events.")
|
||||
print(f"Next sequence: {next_seq}")
|
||||
return
|
||||
|
||||
print(f"Events ({len(events)} new, next_seq={next_seq}, has_more={has_more}):")
|
||||
print()
|
||||
for e in events:
|
||||
severity = e.get('severity', '?')
|
||||
sev_mark = {'critical': '!!!', 'warning': '!!', 'info': 'i'}.get(severity.lower(), '?')
|
||||
cat = e.get('category', '?')
|
||||
title = e.get('title', '?')
|
||||
msg = e.get('message', '')
|
||||
cycle = e.get('cycle', '?')
|
||||
entity = e.get('entity', '')
|
||||
cell = e.get('cell', '')
|
||||
print(f" [{sev_mark}] ({cycle}) {title}")
|
||||
if msg:
|
||||
print(f" {msg}")
|
||||
if entity:
|
||||
print(f" entity: {entity}")
|
||||
if isinstance(cell, int) and cell >= 0:
|
||||
print(f" cell index: {cell}")
|
||||
print()
|
||||
|
||||
def cmd_queue(args):
|
||||
"""View pending task queue. Usage: queue [batch_id]"""
|
||||
params = ""
|
||||
if args:
|
||||
params = f"?batch_id={args[0]}"
|
||||
data = api_get(f"/api/state/queue{params}")
|
||||
if 'error' in data:
|
||||
print(f"Error: {data['error']}")
|
||||
return
|
||||
print(f"Task Queue:")
|
||||
print(f" Length: {data.get('queue_length', '?')}")
|
||||
print(f" Batch ID: {data.get('batch_id', 'none')}")
|
||||
for t in data.get('tasks', []):
|
||||
print(f" - {t.get('type', '?')}: {t.get('value', '?')}")
|
||||
|
||||
def cmd_batch(args):
|
||||
"""Execute a batch of actions. Usage: batch <json_file>"""
|
||||
if not args:
|
||||
print("Usage: batch <json_file>")
|
||||
print(" JSON format: { \"actions\": [ { \"type\": \"build|dig|...\", ... } ] }")
|
||||
return
|
||||
try:
|
||||
with open(args[0]) as f:
|
||||
plan = json.load(f)
|
||||
except Exception as e:
|
||||
print(f"Error reading file: {e}")
|
||||
return
|
||||
|
||||
result = api_post('/api/action/batch', plan)
|
||||
if 'error' in result:
|
||||
print(f"Error: {result['error']}")
|
||||
return
|
||||
|
||||
print(f"Batch: {result.get('batchId', '?')}")
|
||||
print(f" Total: {result.get('total', 0)}")
|
||||
print(f" OK: {result.get('successCount', 0)}")
|
||||
print(f" Failed: {result.get('failCount', 0)}")
|
||||
print(f" Summary: {result.get('summary', '?')}")
|
||||
print()
|
||||
|
||||
for action in result.get('actions', []):
|
||||
status = 'OK' if action.get('success') else 'FAIL'
|
||||
result_type = action.get('result', '?')
|
||||
error = action.get('error', '')
|
||||
err_msg = action.get('errorMessage', '')
|
||||
suggestion = action.get('suggestion', '')
|
||||
|
||||
print(f" [{status}] {result_type}")
|
||||
if error:
|
||||
print(f" error: {error}")
|
||||
if err_msg:
|
||||
print(f" msg: {err_msg}")
|
||||
if suggestion:
|
||||
print(f" -> {suggestion}")
|
||||
print()
|
||||
|
||||
def cmd_priority_global(args):
|
||||
"""Set global priority. Usage: priority_global <target> <priority>"""
|
||||
if len(args) < 2:
|
||||
print("Usage: priority_global <target> <priority>")
|
||||
print(" target: 'dig', 'build', 'clear', or 'all'")
|
||||
print(" priority: 1 (lowest) to 9 (emergency)")
|
||||
return
|
||||
result = api_post('/api/action/priority_global', {
|
||||
"target": args[0],
|
||||
"priority": int(args[1])
|
||||
})
|
||||
_print_feedback(result)
|
||||
|
||||
def cmd_priority_type(args):
|
||||
"""Set priority for a building type. Usage: priority_type <buildingType> <priority>"""
|
||||
if len(args) < 2:
|
||||
print("Usage: priority_type <buildingType> <priority>")
|
||||
return
|
||||
result = api_post('/api/action/priority_type', {
|
||||
"buildingType": args[0],
|
||||
"priority": int(args[1])
|
||||
})
|
||||
_print_feedback(result)
|
||||
|
||||
def _print_feedback(result):
|
||||
"""Pretty-print action feedback."""
|
||||
if result.get('success'):
|
||||
print(f"OK: {result.get('result', 'done')}")
|
||||
for k, v in result.get('data', {}).items():
|
||||
print(f" {k}: {v}")
|
||||
else:
|
||||
print(f"FAIL: {result.get('error', 'unknown_error')}")
|
||||
print(f" {result.get('errorMessage', '')}")
|
||||
sug = result.get('suggestion')
|
||||
if sug:
|
||||
print(f" -> {sug}")
|
||||
|
||||
def cmd_explore(args):
|
||||
"""AI-friendly exploration: reads a region and returns structured text summary."""
|
||||
x = int(args[0]) if len(args) > 0 else 0
|
||||
@ -432,6 +566,8 @@ COMMANDS = {
|
||||
'critters': cmd_critters,
|
||||
'plants': cmd_plants,
|
||||
'rooms': cmd_rooms,
|
||||
'queue': cmd_queue,
|
||||
'events': cmd_events,
|
||||
'cell': cmd_cell,
|
||||
'cells': cmd_cells,
|
||||
'slice': cmd_cell_slice,
|
||||
@ -445,6 +581,9 @@ COMMANDS = {
|
||||
'mop': cmd_mop,
|
||||
'harvest': cmd_harvest,
|
||||
'explore': cmd_explore,
|
||||
'batch': cmd_batch,
|
||||
'priority_global': cmd_priority_global,
|
||||
'priority_type': cmd_priority_type,
|
||||
}
|
||||
|
||||
if __name__ == '__main__':
|
||||
@ -473,10 +612,15 @@ if __name__ == '__main__':
|
||||
print(" gas <x> <y> [r] Gas analysis in radius r")
|
||||
print(" explore <x> <y> <w> <h> AI-friendly region summary")
|
||||
print("")
|
||||
print("=== Event / Queue ===")
|
||||
print(" events [since] [limit] Poll new game events")
|
||||
print(" queue [batch_id] View pending task queue")
|
||||
print("")
|
||||
print("=== Registries (AI Reference) ===")
|
||||
print(" registry buildings [f] List all building IDs with metadata")
|
||||
print(" registry elements [f] List all element IDs with properties")
|
||||
print(" registry techs [f] List all tech IDs with unlocks")
|
||||
print(" registry priorities Show priority level meanings")
|
||||
print("")
|
||||
print("=== Actions ===")
|
||||
print(" dig <x> <y> <w> <h> Dig area")
|
||||
@ -486,5 +630,10 @@ if __name__ == '__main__':
|
||||
print(" research_select <id> Select tech to research")
|
||||
print(" mop <x> <y> Mop liquid")
|
||||
print(" harvest <x> <y> Harvest plant")
|
||||
print("")
|
||||
print("=== Batch / Priority (Advanced) ===")
|
||||
print(" batch <json_file> Execute batch plan")
|
||||
print(" priority_global <t> <p> Set global default priority")
|
||||
print(" priority_type <type> <p> Set per-building-type priority")
|
||||
else:
|
||||
COMMANDS[cmd](sys.argv[2:])
|
||||
|
||||
Reference in New Issue
Block a user