Buckets:
| #!/usr/bin/env python3 | |
| """ | |
| SSH-friendly CLI for the Causation Research Assistant backend. | |
| This talks to the running Flask backend on the same box, so you can use the | |
| CRA and core monitoring endpoints without opening the browser UI. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import os | |
| import subprocess | |
| import sys | |
| import tempfile | |
| import zipfile | |
| from pathlib import Path | |
| from typing import Any, Dict, List, Optional | |
| from urllib import error, parse, request | |
| DEFAULT_BASE_URL = "http://127.0.0.1:5000" | |
| NOTE_TYPES = [ | |
| "note", | |
| "observation", | |
| "hypothesis", | |
| "causation", | |
| "analysis", | |
| "conclusion", | |
| "question", | |
| "todo", | |
| "cra", | |
| ] | |
| class CRAClient: | |
| def __init__( | |
| self, | |
| base_url: str, | |
| timeout: float = 60.0, | |
| cra_key: Optional[str] = None, | |
| hf_auth_token: Optional[str] = None, | |
| ): | |
| self.base_url = base_url.rstrip("/") | |
| self.timeout = timeout | |
| self.cra_key = cra_key | |
| self.hf_auth_token = hf_auth_token | |
| def request_json( | |
| self, | |
| method: str, | |
| path: str, | |
| payload: Optional[Dict[str, Any]] = None, | |
| query: Optional[Dict[str, Any]] = None, | |
| ) -> Dict[str, Any]: | |
| url = self._build_url(path, query=query) | |
| body = None | |
| headers = {"Accept": "application/json"} | |
| if self.hf_auth_token: | |
| headers["Authorization"] = f"Bearer {self.hf_auth_token}" | |
| if self.cra_key: | |
| headers["X-CRA-Key"] = self.cra_key | |
| if payload is not None: | |
| body = json.dumps(payload).encode("utf-8") | |
| headers["Content-Type"] = "application/json" | |
| req = request.Request(url, data=body, method=method.upper(), headers=headers) | |
| try: | |
| with request.urlopen(req, timeout=self.timeout) as resp: | |
| raw = resp.read().decode("utf-8") | |
| if not raw.strip(): | |
| return {} | |
| return json.loads(raw) | |
| except error.HTTPError as exc: | |
| detail = exc.read().decode("utf-8", errors="replace") | |
| raise RuntimeError(f"HTTP {exc.code} for {path}: {detail}") from exc | |
| except error.URLError as exc: | |
| raise RuntimeError( | |
| f"Could not reach CRA backend at {self.base_url}. " | |
| f"Is unified_entry.py or causation_web_ui.py running?" | |
| ) from exc | |
| def download(self, path: str, destination: Path) -> int: | |
| url = self._build_url(path) | |
| headers = {"Accept": "*/*"} | |
| if self.hf_auth_token: | |
| headers["Authorization"] = f"Bearer {self.hf_auth_token}" | |
| if self.cra_key: | |
| headers["X-CRA-Key"] = self.cra_key | |
| req = request.Request(url, headers=headers) | |
| try: | |
| with request.urlopen(req, timeout=self.timeout) as resp: | |
| data = resp.read() | |
| except error.HTTPError as exc: | |
| detail = exc.read().decode("utf-8", errors="replace") | |
| raise RuntimeError(f"HTTP {exc.code} while downloading {path}: {detail}") from exc | |
| except error.URLError as exc: | |
| raise RuntimeError( | |
| f"Could not reach CRA backend at {self.base_url}. " | |
| f"Is unified_entry.py or causation_web_ui.py running?" | |
| ) from exc | |
| destination.parent.mkdir(parents=True, exist_ok=True) | |
| destination.write_bytes(data) | |
| return len(data) | |
| def _build_url(self, path: str, query: Optional[Dict[str, Any]] = None) -> str: | |
| normalized_path = path if path.startswith("/") else f"/{path}" | |
| url = f"{self.base_url}{normalized_path}" | |
| if query: | |
| filtered = {k: v for k, v in query.items() if v is not None} | |
| if filtered: | |
| url = f"{url}?{parse.urlencode(filtered, doseq=True)}" | |
| return url | |
| def parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser( | |
| description="CLI for the Convergence Research Assistant backend." | |
| ) | |
| parser.add_argument( | |
| "--base-url", | |
| default=DEFAULT_BASE_URL, | |
| help=f"CRA backend base URL (default: {DEFAULT_BASE_URL})", | |
| ) | |
| parser.add_argument( | |
| "--timeout", | |
| type=float, | |
| default=60.0, | |
| help="HTTP timeout in seconds (default: 60)", | |
| ) | |
| parser.add_argument( | |
| "--cra-key", | |
| default=os.environ.get("CRA_INTERNAL_KEY"), | |
| help="Internal CRA key for private Space env-token fallback (default: CRA_INTERNAL_KEY env var).", | |
| ) | |
| parser.add_argument( | |
| "--hf-auth-token", | |
| default=os.environ.get("HF_SPACE_TOKEN"), | |
| help="Bearer token for private Hugging Face Space access (default: HF_SPACE_TOKEN env var).", | |
| ) | |
| parser.add_argument( | |
| "--json", | |
| action="store_true", | |
| help="Print raw JSON for the selected command.", | |
| ) | |
| subparsers = parser.add_subparsers(dest="command", required=True) | |
| subparsers.add_parser("status", help="Show CRA custodian status.") | |
| subparsers.add_parser("sitrep", help="Show combined operational summary.") | |
| subparsers.add_parser("health", help="Run CRA health check.") | |
| subparsers.add_parser("system", help="Show current system state snapshot.") | |
| subparsers.add_parser("data", help="Show full CRA data package.") | |
| subparsers.add_parser("models", help="List locally configured text/vision models.") | |
| subparsers.add_parser("sim-status", help="Show simulation running state.") | |
| subparsers.add_parser("sim-start", help="Send simulation start signal.") | |
| subparsers.add_parser("sim-stop", help="Send simulation stop signal.") | |
| subparsers.add_parser("guardian-on", help="Enable CRA guardian mode.") | |
| subparsers.add_parser("capsules", help="List saved organism capsules.") | |
| subparsers.add_parser("checkpoint-status", help="Show checkpoint health/status.") | |
| subparsers.add_parser("checkpoint-list", help="List available neural checkpoints.") | |
| subparsers.add_parser("training-status", help="Show training/checkpoint/log summary.") | |
| subparsers.add_parser("exporter-status", help="Show exporter pipeline readiness summary.") | |
| subparsers.add_parser("security-contracts", help="List action contracts and markings.") | |
| security_receipts_parser = subparsers.add_parser( | |
| "security-receipts", | |
| help="Show recent action/security receipts.", | |
| ) | |
| security_receipts_parser.add_argument("--limit", type=int, default=20, help="Max receipts to show.") | |
| security_receipts_parser.add_argument("--action", help="Filter by action name.") | |
| events_parser = subparsers.add_parser("events", help="Show recent CRA events.") | |
| events_parser.add_argument("--limit", type=int, default=10, help="Max events to print.") | |
| logs_parser = subparsers.add_parser("logs", help="Show CRA log tails.") | |
| logs_parser.add_argument( | |
| "--log", | |
| help="Specific log file name to print, e.g. system.log or reality_sim.log", | |
| ) | |
| logs_parser.add_argument( | |
| "--tail", | |
| type=int, | |
| default=20, | |
| help="Lines to show per log (default: 20)", | |
| ) | |
| config_parser = subparsers.add_parser("config", help="Inspect CRA/runtime config data.") | |
| config_parser.add_argument( | |
| "--current", | |
| action="store_true", | |
| help="Use /api/config/current instead of /api/cra/config.", | |
| ) | |
| config_parser.add_argument( | |
| "--history", | |
| action="store_true", | |
| help="Use /api/config/history.", | |
| ) | |
| config_parser.add_argument( | |
| "--actions", | |
| action="store_true", | |
| help="Use /api/config/actions.", | |
| ) | |
| config_parser.add_argument( | |
| "--limit", | |
| type=int, | |
| default=10, | |
| help="Max config history/action entries to print.", | |
| ) | |
| config_set_parser = subparsers.add_parser( | |
| "config-set", | |
| help="Apply a guarded runtime config patch through CRA config update.", | |
| ) | |
| config_set_parser.add_argument("path", help="JSON pointer path, e.g. /simulation/max_steps") | |
| config_set_parser.add_argument("value", help="New value. JSON is accepted.") | |
| config_set_parser.add_argument( | |
| "--op", | |
| default="replace", | |
| choices=["replace", "add", "remove"], | |
| help="Patch operation (default: replace)", | |
| ) | |
| config_set_parser.add_argument( | |
| "--reason", | |
| default="cra_cli_config_set", | |
| help="Reason recorded with the config action.", | |
| ) | |
| config_rollback_parser = subparsers.add_parser( | |
| "config-rollback", | |
| help="Rollback recent config changes.", | |
| ) | |
| config_rollback_parser.add_argument( | |
| "--steps", | |
| type=int, | |
| default=1, | |
| help="Number of history steps to roll back (default: 1)", | |
| ) | |
| config_rollback_parser.add_argument( | |
| "--reason", | |
| default="cra_cli_config_rollback", | |
| help="Reason recorded with the rollback action.", | |
| ) | |
| org_parser = subparsers.add_parser("organisms", help="List top organisms.") | |
| org_parser.add_argument("--limit", type=int, default=10, help="Max organisms to print.") | |
| alliance_parser = subparsers.add_parser("alliances", help="List alliances.") | |
| alliance_parser.add_argument("--limit", type=int, default=10, help="Max alliances to print.") | |
| chat_parser = subparsers.add_parser("chat", help="Send a single message to the CRA.") | |
| chat_parser.add_argument("message", nargs="*", help="Message text. Reads stdin if omitted.") | |
| chat_parser.add_argument("--model", default="meta-llama/Llama-3.3-70B-Instruct", help="CRA Hugging Face text model name.") | |
| chat_parser.add_argument("--vision-model", help="Optional CRA Hugging Face vision model name.") | |
| chat_parser.add_argument("--api-key", help="Optional per-request API key override.") | |
| chat_parser.add_argument("--selected-event", help="Optional selected event id.") | |
| chat_parser.add_argument( | |
| "--view-state-file", | |
| help="Path to JSON file containing the frontend-style view_state object.", | |
| ) | |
| butterfly_chat_parser = subparsers.add_parser( | |
| "butterfly-chat", | |
| help="Chat directly with the organism swarm through Butterfly Chat.", | |
| ) | |
| butterfly_chat_parser.add_argument("message", nargs="*", help="Message text. Reads stdin if omitted.") | |
| butterfly_chat_parser.add_argument( | |
| "--routing-strategy", | |
| default="all", | |
| help="Router strategy passed to /api/butterfly/chat (default: all).", | |
| ) | |
| butterfly_chat_parser.add_argument( | |
| "--max-organisms", | |
| type=int, | |
| default=10, | |
| help="Maximum organisms to query (default: 10).", | |
| ) | |
| butterfly_chat_parser.add_argument( | |
| "--min-mastery-level", | |
| type=int, | |
| default=0, | |
| help="Only include organisms at or above this mastery level (default: 0).", | |
| ) | |
| standin_chat_parser = subparsers.add_parser( | |
| "standin-chat", | |
| help="Provider-free CRA stand-in: chat directly with Butterfly Chat without a model provider.", | |
| ) | |
| standin_chat_parser.add_argument("message", nargs="*", help="Message text. Reads stdin if omitted.") | |
| standin_chat_parser.add_argument( | |
| "--routing-strategy", | |
| default="all", | |
| help="Router strategy passed to /api/butterfly/chat (default: all).", | |
| ) | |
| standin_chat_parser.add_argument( | |
| "--max-organisms", | |
| type=int, | |
| default=10, | |
| help="Maximum organisms to query (default: 10).", | |
| ) | |
| standin_chat_parser.add_argument( | |
| "--min-mastery-level", | |
| type=int, | |
| default=0, | |
| help="Only include organisms at or above this mastery level (default: 0).", | |
| ) | |
| organism_chat_parser = subparsers.add_parser( | |
| "organism-chat", | |
| help="Chat directly with one organism by id.", | |
| ) | |
| organism_chat_parser.add_argument("organism_id", help="Target organism id.") | |
| organism_chat_parser.add_argument("message", nargs="*", help="Message text. Reads stdin if omitted.") | |
| subparsers.add_parser( | |
| "swarm-stats", | |
| help="Show Butterfly Chat language-learning and training stats.", | |
| ) | |
| notepad_parser = subparsers.add_parser( | |
| "notepad", | |
| help="Read/search the CRA Research Notepad scientific journal.", | |
| ) | |
| notepad_parser.add_argument("--type", choices=NOTE_TYPES, help="Filter by note type.") | |
| notepad_parser.add_argument("--query", help="Search content, tags, and linked events.") | |
| notepad_parser.add_argument("--limit", type=int, default=20, help="Max entries to show.") | |
| notepad_parser.add_argument("--summary", action="store_true", help="Show summary only.") | |
| notepad_add_parser = subparsers.add_parser( | |
| "notepad-add", | |
| help="Append an entry to the CRA Research Notepad.", | |
| ) | |
| notepad_add_parser.add_argument("type", choices=NOTE_TYPES, help="Entry type.") | |
| notepad_add_parser.add_argument("message", nargs="*", help="Entry content. Reads stdin if omitted.") | |
| notepad_add_parser.add_argument("--event", action="append", default=[], help="Linked event id. Repeat as needed.") | |
| notepad_add_parser.add_argument("--confidence", choices=["low", "medium", "high"], help="Hypothesis confidence.") | |
| notepad_add_parser.add_argument("--cause", help="Cause event id for causation notes.") | |
| notepad_add_parser.add_argument("--effect", help="Effect event id for causation notes.") | |
| notepad_add_parser.add_argument("--source", default="cra_cli", help="Source metadata label.") | |
| cocoon_validate_parser = subparsers.add_parser( | |
| "cocoon-validate", | |
| help="Validate a Cocoon ZIP or extracted package without starting the main system.", | |
| ) | |
| cocoon_validate_parser.add_argument("path", help="Path to Cocoon ZIP or extracted directory.") | |
| cocoon_validate_parser.add_argument( | |
| "--run-info", | |
| action="store_true", | |
| help="Run cocoon.py --mode info --max-organisms 1 after extraction/directory check.", | |
| ) | |
| cocoon_validate_parser.add_argument( | |
| "--python", | |
| default=sys.executable, | |
| help="Python executable for --run-info (default: current interpreter).", | |
| ) | |
| receipt_parser = subparsers.add_parser( | |
| "scientific-receipt", | |
| help="Capture a CRA scientific run receipt into the Research Notepad.", | |
| ) | |
| receipt_parser.add_argument( | |
| "--title", | |
| default="Scientific run receipt", | |
| help="Receipt title/content prefix.", | |
| ) | |
| receipt_parser.add_argument( | |
| "--tag", | |
| default="#scientific_receipt", | |
| help="Hashtag to include in the notepad entry.", | |
| ) | |
| receipt_parser.add_argument( | |
| "--event-limit", | |
| type=int, | |
| default=5, | |
| help="Recent event count to include.", | |
| ) | |
| repl_parser = subparsers.add_parser( | |
| "repl", | |
| help="Interactive CRA shell over SSH. Type /help for local commands.", | |
| ) | |
| repl_parser.add_argument("--model", default="meta-llama/Llama-3.3-70B-Instruct", help="CRA Hugging Face text model name.") | |
| repl_parser.add_argument("--vision-model", help="Optional CRA Hugging Face vision model name.") | |
| repl_parser.add_argument("--api-key", help="Optional per-request API key override.") | |
| compile_org_parser = subparsers.add_parser( | |
| "compile-organism", | |
| help="Compile a single organism to an export archive and save it locally.", | |
| ) | |
| compile_org_parser.add_argument("organism_id", help="Organism id to compile.") | |
| compile_org_parser.add_argument( | |
| "--format", | |
| default="onnx", | |
| choices=["onnx", "torchscript"], | |
| help="Export format (default: onnx)", | |
| ) | |
| compile_org_parser.add_argument( | |
| "--outdir", | |
| default="agent_downloads", | |
| help="Directory to save downloaded artifacts.", | |
| ) | |
| compile_ensemble_parser = subparsers.add_parser( | |
| "compile-ensemble", | |
| help="Compile multiple organisms into a single ensemble archive.", | |
| ) | |
| compile_ensemble_parser.add_argument( | |
| "organism_ids", | |
| nargs="+", | |
| help="One or more organism ids.", | |
| ) | |
| compile_ensemble_parser.add_argument( | |
| "--format", | |
| default="onnx", | |
| choices=["onnx", "torchscript"], | |
| help="Export format (default: onnx)", | |
| ) | |
| compile_ensemble_parser.add_argument( | |
| "--outdir", | |
| default="agent_downloads", | |
| help="Directory to save downloaded artifacts.", | |
| ) | |
| compile_learning_parser = subparsers.add_parser( | |
| "compile-learning", | |
| help="Compile a trainable learning capsule archive.", | |
| ) | |
| compile_learning_parser.add_argument( | |
| "--organism-id", | |
| dest="organism_ids", | |
| action="append", | |
| default=[], | |
| help="Organism id to include. Repeat for multiple organisms.", | |
| ) | |
| compile_learning_parser.add_argument( | |
| "--training-config-file", | |
| help="Path to JSON file with training_config overrides.", | |
| ) | |
| compile_learning_parser.add_argument( | |
| "--outdir", | |
| default="agent_downloads", | |
| help="Directory to save downloaded artifacts.", | |
| ) | |
| compile_cocoon_parser = subparsers.add_parser( | |
| "compile-cocoon", | |
| help="Compile a cocoon/package export and save it locally.", | |
| ) | |
| compile_cocoon_parser.add_argument( | |
| "--organism-id", | |
| dest="organism_ids", | |
| action="append", | |
| default=[], | |
| help="Organism id to include. Repeat for multiple organisms.", | |
| ) | |
| compile_cocoon_parser.add_argument( | |
| "--top-n", | |
| type=int, | |
| default=1, | |
| help="Use top N organisms if no --organism-id values are provided.", | |
| ) | |
| compile_cocoon_parser.add_argument( | |
| "--alliance-id", | |
| dest="alliance_ids", | |
| action="append", | |
| default=[], | |
| help="Alliance id to include in a curated Cocoon. Repeat for 2-3 alliances.", | |
| ) | |
| compile_cocoon_parser.add_argument( | |
| "--alliance", | |
| dest="alliance_names", | |
| action="append", | |
| default=[], | |
| help="Alliance name or id to include in a curated Cocoon.", | |
| ) | |
| compile_cocoon_parser.add_argument( | |
| "--include-unallied", | |
| action="store_true", | |
| help="Include organisms with no alliance mapping. Default excludes them.", | |
| ) | |
| compile_cocoon_parser.add_argument( | |
| "--format", | |
| default="cocoon", | |
| choices=["cocoon", "onnx", "torchscript", "package"], | |
| help="Export format (default: cocoon)", | |
| ) | |
| compile_cocoon_parser.add_argument( | |
| "--no-gym", | |
| action="store_true", | |
| help="Disable gym adapter in export.", | |
| ) | |
| compile_cocoon_parser.add_argument( | |
| "--no-http", | |
| action="store_true", | |
| help="Disable HTTP server in export.", | |
| ) | |
| compile_cocoon_parser.add_argument( | |
| "--no-compress", | |
| action="store_true", | |
| help="Disable export compression.", | |
| ) | |
| compile_cocoon_parser.add_argument( | |
| "--outdir", | |
| default="agent_downloads", | |
| help="Directory to save downloaded artifacts.", | |
| ) | |
| compile_cocoon_parser.add_argument( | |
| "--reason", | |
| default="cra_cli_compile_cocoon", | |
| help="Reason recorded with the cocoon compile receipt.", | |
| ) | |
| checkpoint_save_parser = subparsers.add_parser( | |
| "checkpoint-save", | |
| help="Trigger an immediate neural checkpoint save.", | |
| ) | |
| checkpoint_save_parser.add_argument( | |
| "--reason", | |
| default="cra_cli_manual_save", | |
| help="Reason recorded in the checkpoint signal.", | |
| ) | |
| checkpoint_restore_parser = subparsers.add_parser( | |
| "checkpoint-restore", | |
| help="Signal restore from a checkpoint (applies on next start/restart).", | |
| ) | |
| checkpoint_restore_parser.add_argument( | |
| "--name", | |
| help="Checkpoint directory name. Defaults to latest if omitted.", | |
| ) | |
| checkpoint_restore_parser.add_argument( | |
| "--reason", | |
| default="cra_cli_checkpoint_restore", | |
| help="Reason recorded with the restore receipt.", | |
| ) | |
| api_parser = subparsers.add_parser( | |
| "api", | |
| help="Call any CRA/web API route directly.", | |
| ) | |
| api_parser.add_argument("path", help="API path, e.g. /api/cra/status") | |
| api_parser.add_argument( | |
| "--method", | |
| default="GET", | |
| choices=["GET", "POST"], | |
| help="HTTP method (default: GET)", | |
| ) | |
| api_parser.add_argument( | |
| "--data", | |
| help="JSON body for POST requests.", | |
| ) | |
| api_parser.add_argument( | |
| "--query", | |
| action="append", | |
| default=[], | |
| help="Query pair in key=value form. Repeat as needed.", | |
| ) | |
| return parser.parse_args() | |
| def read_message(args: argparse.Namespace) -> str: | |
| if args.message: | |
| return " ".join(args.message).strip() | |
| if not sys.stdin.isatty(): | |
| return sys.stdin.read().strip() | |
| raise SystemExit("Message is required. Pass it as arguments or pipe it on stdin.") | |
| def read_view_state(path: Optional[str]) -> Dict[str, Any]: | |
| if not path: | |
| return {} | |
| with open(path, "r", encoding="utf-8") as fh: | |
| return json.load(fh) | |
| def read_json_file(path: Optional[str]) -> Dict[str, Any]: | |
| if not path: | |
| return {} | |
| with open(path, "r", encoding="utf-8") as fh: | |
| return json.load(fh) | |
| def print_json(data: Any) -> None: | |
| print(json.dumps(data, indent=2, sort_keys=False)) | |
| def print_heading(title: str) -> None: | |
| print(f"\n== {title} ==") | |
| def format_timestamp(value: Any) -> str: | |
| return str(value) if value is not None else "-" | |
| def summarize_status(data: Dict[str, Any]) -> None: | |
| custodian = data.get("custodian", {}) | |
| monitoring = custodian.get("monitoring", {}) | |
| print(f"Role: {custodian.get('role', '-')}") | |
| print(f"Status: {custodian.get('status', '-')}") | |
| print(f"Protection: {custodian.get('protection_status', '-')}") | |
| print(f"Event streaming: {monitoring.get('event_streaming', False)}") | |
| print(f"WebSocket support: {monitoring.get('websocket_support', False)}") | |
| capabilities = custodian.get("capabilities", []) | |
| if capabilities: | |
| print("Capabilities:") | |
| for item in capabilities: | |
| print(f" - {item}") | |
| def summarize_health(data: Dict[str, Any]) -> None: | |
| print(f"Overall health: {data.get('overall_health', '-')}") | |
| for key in ("critical_issues", "warnings", "recommendations"): | |
| items = data.get(key, []) | |
| if items: | |
| print(f"{key.replace('_', ' ').title()}:") | |
| for item in items: | |
| print(f" - {item}") | |
| def summarize_sitrep( | |
| status_data: Dict[str, Any], | |
| health_data: Dict[str, Any], | |
| system_data: Dict[str, Any], | |
| checkpoint_data: Dict[str, Any], | |
| ) -> None: | |
| print_heading("CRA") | |
| summarize_status(status_data) | |
| print_heading("Health") | |
| summarize_health(health_data) | |
| print_heading("System") | |
| summarize_system(system_data) | |
| print_heading("Training") | |
| summarize_checkpoints(checkpoint_data) | |
| def summarize_system(data: Dict[str, Any]) -> None: | |
| state = data.get("state", {}) | |
| sim = state.get("simulation", {}) | |
| pc = state.get("pc_resources", {}) | |
| memory = pc.get("memory", {}) | |
| cpu = pc.get("cpu", {}) | |
| butterfly = state.get("butterfly_system", {}) | |
| print(f"Simulation running: {sim.get('running', False)}") | |
| print(f"Paused: {sim.get('paused', True)}") | |
| print(f"Frame: {sim.get('frame', 0)}") | |
| print(f"FPS: {sim.get('fps', 0.0)}") | |
| print(f"CPU total: {cpu.get('total_percent', 0):.1f}%") | |
| print(f"Memory used: {memory.get('used_gb', 0):.2f} / {memory.get('total_gb', 0):.2f} GB") | |
| print(f"Process RSS: {memory.get('process_mb', 0):.1f} MB") | |
| print(f"Nodes: {butterfly.get('total_nodes', 0)}") | |
| print(f"Links: {butterfly.get('total_links', 0)}") | |
| warnings = state.get("warnings", []) | |
| if warnings: | |
| print("Warnings:") | |
| for item in warnings: | |
| print(f" - {item}") | |
| def summarize_models(data: Dict[str, Any]) -> None: | |
| text_models = data.get("text_models") or data.get("models") or [] | |
| vision_models = data.get("vision_models") or [] | |
| print("Text models:") | |
| for item in text_models: | |
| print(f" - {item}") | |
| if vision_models: | |
| print("Vision models:") | |
| for item in vision_models: | |
| print(f" - {item}") | |
| def summarize_sim_status(data: Dict[str, Any]) -> None: | |
| print(f"Running: {data.get('running', False)}") | |
| print(f"Paused: {data.get('paused', True)}") | |
| if "message" in data: | |
| print(data["message"]) | |
| def summarize_events(data: Dict[str, Any], limit: int) -> None: | |
| events = data.get("events", [])[:limit] | |
| print(f"Events shown: {len(events)}") | |
| for idx, event in enumerate(events, start=1): | |
| etype = event.get("type") or event.get("event_type") or "unknown" | |
| timestamp = format_timestamp(event.get("timestamp")) | |
| print(f"{idx}. {etype} @ {timestamp}") | |
| summary = event.get("data") or event.get("message") or event.get("payload") | |
| if summary: | |
| if isinstance(summary, dict): | |
| summary = json.dumps(summary, ensure_ascii=True) | |
| print(f" {str(summary)[:220]}") | |
| def summarize_logs(data: Dict[str, Any], log_name: Optional[str], tail: int) -> None: | |
| logs = data.get("logs", {}) | |
| if log_name: | |
| selected = logs.get(log_name) | |
| if not selected: | |
| raise SystemExit(f"Log {log_name!r} not found. Available: {', '.join(sorted(logs))}") | |
| content = selected.get("content", []) | |
| for line in content[-tail:]: | |
| print(line) | |
| return | |
| for name in sorted(logs): | |
| payload = logs[name] | |
| print_heading(name) | |
| print(f"Entries loaded: {payload.get('entries', 0)}") | |
| for line in payload.get("content", [])[-tail:]: | |
| print(line) | |
| def summarize_config(data: Dict[str, Any], limit: int) -> None: | |
| if "history" in data: | |
| entries = data.get("history", [])[-limit:] | |
| print(f"History entries shown: {len(entries)}") | |
| for idx, entry in enumerate(entries, start=1): | |
| print( | |
| f"{idx}. version={entry.get('version', '-')} " | |
| f"timestamp={format_timestamp(entry.get('timestamp'))}" | |
| ) | |
| elif "actions" in data: | |
| entries = data.get("actions", [])[-limit:] | |
| print(f"Actions shown: {len(entries)}") | |
| for idx, entry in enumerate(entries, start=1): | |
| print( | |
| f"{idx}. {entry.get('action', '-')} path={entry.get('path', '-')} " | |
| f"actor={entry.get('actor', '-')} status={entry.get('status', '-')}" | |
| ) | |
| elif "config" in data and isinstance(data["config"], dict): | |
| keys = ", ".join(sorted(data["config"].keys())) | |
| print(f"Config payload keys: {keys}") | |
| print_json(data["config"]) | |
| else: | |
| print_json(data) | |
| def summarize_organisms(data: List[Dict[str, Any]], limit: int) -> None: | |
| shown = data[:limit] | |
| print(f"Organisms shown: {len(shown)}") | |
| for idx, org in enumerate(shown, start=1): | |
| print( | |
| f"{idx}. id={org.get('id', '-')[:12]} " | |
| f"fitness={org.get('fitness', 0):.4f} " | |
| f"words={org.get('words_learned', 0)} " | |
| f"personality={org.get('personality_type', '-')}" | |
| ) | |
| def summarize_alliances(data: List[Dict[str, Any]], limit: int) -> None: | |
| shown = data[:limit] | |
| print(f"Alliances shown: {len(shown)}") | |
| for idx, alliance in enumerate(shown, start=1): | |
| print( | |
| f"{idx}. {alliance.get('name', alliance.get('alliance_id', '-'))} " | |
| f"members={alliance.get('member_count', len(alliance.get('members', [])))} " | |
| f"fitness={alliance.get('collective_fitness', alliance.get('average_fitness', 0))}" | |
| ) | |
| def summarize_capsules(data: Dict[str, Any]) -> None: | |
| capsules = data.get("capsules", []) | |
| print(f"Capsules: {len(capsules)}") | |
| for idx, capsule in enumerate(capsules[:20], start=1): | |
| print( | |
| f"{idx}. organism={capsule.get('organism_id', '-')[:12]} " | |
| f"capsule={capsule.get('capsule_id', '-')[:12]} " | |
| f"fitness={capsule.get('fitness', 0)} " | |
| f"captured={format_timestamp(capsule.get('capture_time'))}" | |
| ) | |
| def summarize_checkpoints(data: Dict[str, Any]) -> None: | |
| if "checkpoint_status" in data: | |
| status = data.get("checkpoint_status", {}) | |
| health = status.get("health", {}) | |
| print(f"Enabled: {status.get('enabled', False)}") | |
| print(f"Count: {status.get('checkpoints_count', 0)}") | |
| print(f"Total size MB: {status.get('total_size_mb', 0)}") | |
| latest = status.get("latest_checkpoint") or {} | |
| if latest: | |
| print( | |
| f"Latest: {latest.get('name', '-')} " | |
| f"gen={latest.get('generation', '-')} " | |
| f"timestamp={format_timestamp(latest.get('timestamp'))}" | |
| ) | |
| if health.get("recommendation"): | |
| print(f"Recommendation: {health['recommendation']}") | |
| return | |
| checkpoints = data.get("checkpoints", []) | |
| print(f"Checkpoints: {len(checkpoints)}") | |
| for idx, checkpoint in enumerate(checkpoints[:20], start=1): | |
| print( | |
| f"{idx}. {checkpoint.get('name', '-')} " | |
| f"gen={checkpoint.get('generation', '-')} " | |
| f"size={checkpoint.get('size_mb', 0)}MB " | |
| f"timestamp={format_timestamp(checkpoint.get('timestamp'))}" | |
| ) | |
| def summarize_training_status( | |
| system_data: Dict[str, Any], | |
| checkpoint_data: Dict[str, Any], | |
| logs_data: Dict[str, Any], | |
| ) -> None: | |
| summarize_system(system_data) | |
| print_heading("Checkpointing") | |
| summarize_checkpoints(checkpoint_data) | |
| print_heading("Neural Log") | |
| neural_log = logs_data.get("logs", {}).get("neural.log", {}) | |
| for line in neural_log.get("content", [])[-15:]: | |
| print(line) | |
| def summarize_exporter_status( | |
| organisms_data: List[Dict[str, Any]], | |
| capsules_data: Dict[str, Any], | |
| checkpoint_data: Dict[str, Any], | |
| ) -> None: | |
| print(f"Live/saved organisms visible to exporter: {len(organisms_data)}") | |
| if organisms_data: | |
| print("Top organisms:") | |
| for idx, org in enumerate(organisms_data[:5], start=1): | |
| print( | |
| f" {idx}. id={org.get('id', '-')[:12]} " | |
| f"fitness={org.get('fitness', 0):.4f} " | |
| f"source={org.get('source', '-')}" | |
| ) | |
| capsules = capsules_data.get("capsules", []) | |
| print(f"Saved capsules: {len(capsules)}") | |
| latest_capsules = sorted( | |
| capsules, | |
| key=lambda item: str(item.get("capture_time") or ""), | |
| reverse=True, | |
| )[:5] | |
| if latest_capsules: | |
| print("Recent capsules:") | |
| for idx, capsule in enumerate(latest_capsules, start=1): | |
| print( | |
| f" {idx}. organism={str(capsule.get('organism_id', '-'))[:12]} " | |
| f"captured={format_timestamp(capsule.get('capture_time'))} " | |
| f"reason={capsule.get('reason', '-')}" | |
| ) | |
| print_heading("Checkpointing") | |
| summarize_checkpoints(checkpoint_data) | |
| def save_downloads(client: CRAClient, data: Dict[str, Any], outdir: str) -> List[Path]: | |
| saved: List[Path] = [] | |
| target_dir = Path(outdir) | |
| filename = data.get("filename") | |
| download_url = data.get("download_url") | |
| if filename and download_url: | |
| destination = target_dir / filename | |
| client.download(download_url, destination) | |
| saved.append(destination) | |
| for extra in data.get("additional_files", []) or []: | |
| extra_name = extra.get("filename") | |
| extra_url = extra.get("download_url") | |
| if extra_name and extra_url: | |
| destination = target_dir / extra_name | |
| client.download(extra_url, destination) | |
| saved.append(destination) | |
| return saved | |
| def summarize_export_result(data: Dict[str, Any], saved_paths: List[Path]) -> None: | |
| print(f"Success: {data.get('success', False)}") | |
| if data.get("capsule_type"): | |
| print(f"Capsule type: {data.get('capsule_type')}") | |
| if data.get("export_format"): | |
| print(f"Format: {data.get('export_format')}") | |
| if data.get("mode"): | |
| print(f"Mode: {data.get('mode')}") | |
| if data.get("organism_count") is not None: | |
| print(f"Organisms: {data.get('organism_count')}") | |
| if data.get("size") is not None: | |
| print(f"Size: {data.get('size')} bytes") | |
| if data.get("usage_hint"): | |
| print(f"Usage: {data.get('usage_hint')}") | |
| if saved_paths: | |
| print("Saved:") | |
| for path in saved_paths: | |
| print(f" - {path}") | |
| def parse_jsonish_value(raw: str) -> Any: | |
| text = raw.strip() | |
| try: | |
| return json.loads(text) | |
| except json.JSONDecodeError: | |
| lowered = text.lower() | |
| if lowered == "true": | |
| return True | |
| if lowered == "false": | |
| return False | |
| if lowered == "null": | |
| return None | |
| return raw | |
| def do_chat( | |
| client: CRAClient, | |
| message: str, | |
| model: str, | |
| vision_model: Optional[str] = None, | |
| api_key: Optional[str] = None, | |
| selected_event: Optional[str] = None, | |
| view_state: Optional[Dict[str, Any]] = None, | |
| ) -> Dict[str, Any]: | |
| payload: Dict[str, Any] = { | |
| "message": message, | |
| "model": model, | |
| "view_state": view_state or {}, | |
| } | |
| if vision_model: | |
| payload["vision_model"] = vision_model | |
| if api_key: | |
| payload["api_key"] = api_key | |
| if selected_event: | |
| payload["selected_event"] = selected_event | |
| return client.request_json("POST", "/api/cra/chat", payload=payload) | |
| def summarize_chat(data: Dict[str, Any]) -> None: | |
| response = data.get("response") or data.get("message") or "" | |
| if response: | |
| print(response.strip()) | |
| if not response: | |
| print_json(data) | |
| return | |
| timing = data.get("timing_breakdown") or data.get("timing") or {} | |
| if timing: | |
| print_heading("Timing") | |
| print_json(timing) | |
| if data.get("vision_analysis"): | |
| print_heading("Vision") | |
| print(data["vision_analysis"]) | |
| def butterfly_chat_failed(data: Dict[str, Any]) -> bool: | |
| routing = data.get("routing_info") or {} | |
| responded = routing.get("organisms_responded", data.get("organism_count", 0)) | |
| try: | |
| organisms_responded = int(responded or 0) | |
| except (TypeError, ValueError): | |
| organisms_responded = 0 | |
| response = str(data.get("response") or "").strip() | |
| if response == "<no response>": | |
| response = "" | |
| return ( | |
| data.get("success") is False | |
| or data.get("status") == "error" | |
| or organisms_responded == 0 | |
| or not response | |
| ) | |
| def summarize_butterfly_chat(data: Dict[str, Any]) -> None: | |
| response = data.get("response") or "" | |
| failed = butterfly_chat_failed(data) | |
| printed_response = False | |
| if failed: | |
| print_heading("Butterfly Chat Failed") | |
| reason = data.get("failure_reason") or data.get("status") or "unknown_failure" | |
| print(f"Reason: {reason}") | |
| routing = data.get("routing_info") or {} | |
| if routing: | |
| print(f"Organisms queried: {routing.get('organisms_queried', 0)}") | |
| print(f"Organisms responded: {routing.get('organisms_responded', 0)}") | |
| if response.strip(): | |
| print(response.strip()) | |
| printed_response = True | |
| if response: | |
| if not printed_response: | |
| print(response.strip()) | |
| else: | |
| print_json(data) | |
| return | |
| print_heading("Swarm") | |
| print(f"Organisms: {data.get('organism_count', 0)}") | |
| print(f"Confidence: {data.get('confidence', 0):.3f}") | |
| print(f"Strategy: {data.get('routing_strategy', '-')}") | |
| routing = data.get("routing_info") or {} | |
| if routing: | |
| selected = routing.get("selected_organisms") or routing.get("organisms") or [] | |
| if selected: | |
| print(f"Selected: {len(selected)}") | |
| responses = data.get("organism_responses") or [] | |
| if responses: | |
| print_heading("Organism Responses") | |
| for idx, item in enumerate(responses[:8], start=1): | |
| oid = str(item.get("organism_id") or item.get("id") or item.get("species_id") or "-") | |
| confidence = item.get("confidence", 0) | |
| text = item.get("response") or item.get("message") or "" | |
| print(f"{idx}. {oid[:12]} confidence={confidence:.3f}") | |
| if text: | |
| print(f" {text[:220]}") | |
| errors = data.get("errors") or [] | |
| if errors: | |
| print_heading("Errors") | |
| for item in errors[:5]: | |
| print(f" - {item}") | |
| def summarize_organism_chat(data: Dict[str, Any]) -> None: | |
| if not data.get("success", False) and "response" not in data: | |
| print_json(data) | |
| return | |
| print(f"Organism: {data.get('organism_id', '-')}") | |
| info = data.get("organism_info") or {} | |
| if info: | |
| print( | |
| f"Generation: {info.get('generation', 0)} " | |
| f"Fitness: {info.get('fitness', 0)} " | |
| f"Words: {info.get('vocabulary_size', 0)} " | |
| f"Personality: {info.get('personality', '-')}" | |
| ) | |
| response = data.get("response") or "" | |
| if response: | |
| print_heading("Response") | |
| print(response.strip()) | |
| print(f"Confidence: {data.get('confidence', 0):.3f}") | |
| debug = data.get("debug") or {} | |
| if debug: | |
| print_heading("Learning") | |
| print(f"Experience buffer: {debug.get('organism_experience_count', '-')}") | |
| print(f"Personal vocab: {debug.get('organism_personal_vocab_size', '-')}") | |
| print(f"Mastery atoms used: {debug.get('atoms_found_for_response', '-')}") | |
| atom_details = debug.get("atom_formation_details") or [] | |
| for atom in atom_details[:8]: | |
| print( | |
| f" - {atom.get('word', '-')} " | |
| f"strength={atom.get('strength', '-')} " | |
| f"uses={atom.get('usage_count', '-')} " | |
| f"source={atom.get('source', '-')}" | |
| ) | |
| trail = data.get("causation_trail") or [] | |
| if trail: | |
| print_heading("Causation Trail") | |
| for item in trail[:8]: | |
| print(f" - {item}") | |
| def summarize_swarm_stats(data: Dict[str, Any]) -> None: | |
| payload = data.get("agent_swarm") or data | |
| stats = payload.get("stats") or payload | |
| if not isinstance(stats, dict): | |
| print_json(data) | |
| return | |
| population = stats.get("population_stats") or {} | |
| semantic = stats.get("semantic_reward_stats") or {} | |
| transfer = stats.get("knowledge_transfer_stats") or {} | |
| vocab = stats.get("creative_vocab_stats") or {} | |
| derived = payload.get("derived_metrics") or data.get("derived_metrics") or {} | |
| print_heading("Population") | |
| print(f"Organisms: {population.get('total_organisms', 0)}") | |
| print(f"With language: {population.get('organisms_with_language', 0)}") | |
| print(f"Chat experiences: {population.get('total_chat_experiences', 0)}") | |
| print(f"Chat training triggered: {population.get('chat_training_triggered', 0)}") | |
| if derived: | |
| print(f"Training ratio: {derived.get('training_ratio', 0):.3f}") | |
| print(f"Learning health: {derived.get('learning_health_score', 0):.3f}") | |
| print_heading("Semantic Reward") | |
| print(f"Calculations: {semantic.get('total_calculations', 0)}") | |
| print(f"Average reward: {semantic.get('avg_total_reward', 0):.3f}") | |
| print(f"Average coherence: {semantic.get('avg_coherence', 0):.3f}") | |
| print_heading("Knowledge Transfer") | |
| print(f"Broadcasts: {transfer.get('total_broadcasts', 0)}") | |
| print(f"Recipients: {transfer.get('total_recipients', 0)}") | |
| print(f"Reward transferred: {transfer.get('total_reward_transferred', 0):.3f}") | |
| if vocab: | |
| print_heading("Vocabulary") | |
| print(f"Expansions: {vocab.get('total_expansions', 0)}") | |
| print(f"Phrases: {vocab.get('phrases_generated', 0)}") | |
| print(f"Compounds: {vocab.get('compounds_created', 0)}") | |
| print(f"Neologisms: {vocab.get('neologisms_minted', 0)}") | |
| def summarize_notepad(data: Dict[str, Any], summary_only: bool = False) -> None: | |
| if not data.get("success", True): | |
| print_json(data) | |
| return | |
| summary = data.get("summary") or {} | |
| if "summary" in summary: | |
| summary = summary["summary"] | |
| entries = data.get("entries") or [] | |
| print_heading("Research Notepad") | |
| print(f"Session: {data.get('sessionId', '-')}") | |
| print(f"Last saved: {data.get('lastSaved', '-')}") | |
| print(f"Total: {summary.get('total', data.get('totalEntries', len(entries)))}") | |
| print(f"Returned: {data.get('returned', len(entries))}") | |
| print(f"Open hypotheses: {summary.get('openHypotheses', 0)}") | |
| print(f"Pending todos: {summary.get('pendingTodos', 0)}") | |
| by_type = summary.get("byType") or {} | |
| if by_type: | |
| compact = ", ".join(f"{k}={v}" for k, v in sorted(by_type.items()) if v) | |
| if compact: | |
| print(f"By type: {compact}") | |
| if summary_only: | |
| return | |
| for entry in entries: | |
| timestamp = entry.get("timestamp", "-") | |
| note_type = entry.get("type", "note") | |
| content = (entry.get("content") or "").strip() | |
| print_heading(f"{note_type} {entry.get('id', '-')}") | |
| print(f"Time: {timestamp}") | |
| if entry.get("linkedEvents"): | |
| print(f"Events: {', '.join(str(e) for e in entry.get('linkedEvents', []))}") | |
| metadata = entry.get("metadata") or {} | |
| if metadata: | |
| useful = {k: v for k, v in metadata.items() if v not in (None, "", [])} | |
| if useful: | |
| print(f"Metadata: {json.dumps(useful, ensure_ascii=False)}") | |
| print(content) | |
| def _read_zip_json(zf: zipfile.ZipFile, name: str) -> Optional[Dict[str, Any]]: | |
| try: | |
| with zf.open(name) as fh: | |
| data = json.loads(fh.read().decode("utf-8", errors="replace")) | |
| return data if isinstance(data, dict) else None | |
| except Exception: | |
| return None | |
| def _vocab_word_count(vocab: Optional[Dict[str, Any]]) -> int: | |
| if not isinstance(vocab, dict): | |
| return 0 | |
| word_to_id = vocab.get("word_to_id") | |
| return len(word_to_id) if isinstance(word_to_id, dict) else len(vocab) | |
| def validate_cocoon_package(path: Path, run_info: bool = False, python_executable: str = sys.executable) -> Dict[str, Any]: | |
| """Static validation for Cocoon ZIPs/directories used by Council adapters.""" | |
| connector_words = {"a", "and", "to", "of", "in", "it", "is", "but", "then", "cocoon"} | |
| curriculum_files = { | |
| "curriculum/connector_words.json", | |
| "curriculum/dialogue_frames.json", | |
| "curriculum/role_transform_tasks.json", | |
| "curriculum/game_language_tasks.json", | |
| "curriculum/reward_rubric.json", | |
| "training_logs/schema.json", | |
| } | |
| result: Dict[str, Any] = { | |
| "path": str(path), | |
| "exists": path.exists(), | |
| "kind": "missing", | |
| "ok": False, | |
| "errors": [], | |
| "warnings": [], | |
| "files": {}, | |
| } | |
| if not path.exists(): | |
| result["errors"].append("Path does not exist.") | |
| return result | |
| extracted_dir: Optional[Path] = None | |
| temp_dir: Optional[tempfile.TemporaryDirectory[str]] = None | |
| try: | |
| if path.is_file() and path.suffix.lower() == ".zip": | |
| result["kind"] = "zip" | |
| with zipfile.ZipFile(path) as zf: | |
| names = [item.filename for item in zf.infolist()] | |
| duplicates = sorted({name for name in names if names.count(name) > 1}) | |
| result["duplicates"] = duplicates | |
| if duplicates: | |
| result["warnings"].append(f"Duplicate ZIP entries: {', '.join(duplicates)}") | |
| required = ["cocoon.py", "metadata.json", "vocabulary.json", "README.md"] | |
| result["files"] = {name: name in names for name in required} | |
| for name, present in result["files"].items(): | |
| if not present: | |
| result["errors"].append(f"Missing {name}") | |
| metadata = _read_zip_json(zf, "metadata.json") | |
| vocab = _read_zip_json(zf, "vocabulary.json") | |
| readme = "" | |
| try: | |
| readme = zf.read("README.md").decode("utf-8", errors="replace") | |
| except Exception: | |
| pass | |
| result["metadata_package_version"] = metadata.get("package_version") if metadata else None | |
| result["metadata_vocab_size"] = metadata.get("vocab_size") if metadata else None | |
| result["vocabulary_count"] = _vocab_word_count(vocab) | |
| result["connector_words"] = { | |
| word: bool(isinstance(vocab, dict) and word in (vocab.get("word_to_id") or {})) | |
| for word in sorted(connector_words) | |
| } | |
| missing_connectors = [w for w, present in result["connector_words"].items() if not present] | |
| if missing_connectors: | |
| result["warnings"].append(f"Missing connector words: {', '.join(missing_connectors)}") | |
| if "brain_ensemble.onnx" in readme and "brain_ensemble.onnx" not in names: | |
| result["warnings"].append("README references brain_ensemble.onnx but package does not include it.") | |
| if "game_contracts.json" not in names: | |
| result["warnings"].append("Missing game_contracts.json Council contract.") | |
| result["curriculum_files"] = { | |
| name: name in names | |
| for name in sorted(curriculum_files) | |
| } | |
| missing_curriculum = [name for name, present in result["curriculum_files"].items() if not present] | |
| if missing_curriculum: | |
| result["warnings"].append(f"Missing language curriculum files: {', '.join(missing_curriculum)}") | |
| result["has_torchscript"] = "brain_ensemble.pt" in names | |
| result["has_onnx"] = "brain_ensemble.onnx" in names | |
| if run_info: | |
| temp_parent = Path(os.environ.get("TEMP", tempfile.gettempdir())) | |
| if Path("D:/temp").exists(): | |
| temp_parent = Path("D:/temp") | |
| temp_dir = tempfile.TemporaryDirectory(prefix="cocoon_validate_", dir=str(temp_parent)) | |
| zf.extractall(temp_dir.name) | |
| extracted_dir = Path(temp_dir.name) | |
| elif path.is_dir(): | |
| result["kind"] = "directory" | |
| names = {str(p.relative_to(path)).replace("\\", "/") for p in path.rglob("*") if p.is_file()} | |
| required = ["cocoon.py", "metadata.json", "vocabulary.json", "README.md"] | |
| result["files"] = {name: name in names for name in required} | |
| for name, present in result["files"].items(): | |
| if not present: | |
| result["errors"].append(f"Missing {name}") | |
| metadata = read_json_file(str(path / "metadata.json")) if (path / "metadata.json").exists() else None | |
| vocab = read_json_file(str(path / "vocabulary.json")) if (path / "vocabulary.json").exists() else None | |
| result["metadata_package_version"] = metadata.get("package_version") if metadata else None | |
| result["metadata_vocab_size"] = metadata.get("vocab_size") if metadata else None | |
| result["vocabulary_count"] = _vocab_word_count(vocab) | |
| result["connector_words"] = { | |
| word: bool(isinstance(vocab, dict) and word in (vocab.get("word_to_id") or {})) | |
| for word in sorted(connector_words) | |
| } | |
| missing_connectors = [w for w, present in result["connector_words"].items() if not present] | |
| if missing_connectors: | |
| result["warnings"].append(f"Missing connector words: {', '.join(missing_connectors)}") | |
| if "game_contracts.json" not in names: | |
| result["warnings"].append("Missing game_contracts.json Council contract.") | |
| result["curriculum_files"] = { | |
| name: name in names | |
| for name in sorted(curriculum_files) | |
| } | |
| missing_curriculum = [name for name, present in result["curriculum_files"].items() if not present] | |
| if missing_curriculum: | |
| result["warnings"].append(f"Missing language curriculum files: {', '.join(missing_curriculum)}") | |
| result["has_torchscript"] = "brain_ensemble.pt" in names | |
| result["has_onnx"] = "brain_ensemble.onnx" in names | |
| extracted_dir = path | |
| else: | |
| result["errors"].append("Path must be a Cocoon ZIP or extracted directory.") | |
| if run_info and extracted_dir: | |
| cocoon_py = extracted_dir / "cocoon.py" | |
| if cocoon_py.exists(): | |
| proc = subprocess.run( | |
| [python_executable, str(cocoon_py), "--mode", "info", "--max-organisms", "1"], | |
| cwd=str(extracted_dir), | |
| capture_output=True, | |
| text=True, | |
| timeout=90, | |
| env={**os.environ, "PYTHONIOENCODING": "utf-8"}, | |
| ) | |
| result["runtime_info"] = { | |
| "returncode": proc.returncode, | |
| "stdout_tail": proc.stdout[-4000:], | |
| "stderr_tail": proc.stderr[-2000:], | |
| } | |
| if proc.returncode != 0: | |
| result["warnings"].append("cocoon.py --mode info returned nonzero.") | |
| else: | |
| result["warnings"].append("Cannot run info: cocoon.py missing.") | |
| finally: | |
| if temp_dir is not None: | |
| temp_dir.cleanup() | |
| result["ok"] = not result["errors"] | |
| return result | |
| def summarize_cocoon_validation(data: Dict[str, Any]) -> None: | |
| print_heading("Cocoon Validation") | |
| print(f"Path: {data.get('path')}") | |
| print(f"Kind: {data.get('kind')}") | |
| print(f"OK: {data.get('ok')}") | |
| print(f"Vocab count: {data.get('vocabulary_count', 0)}") | |
| print(f"Metadata vocab: {data.get('metadata_vocab_size', '-')}") | |
| print(f"TorchScript: {data.get('has_torchscript', False)}") | |
| print(f"ONNX: {data.get('has_onnx', False)}") | |
| connectors = data.get("connector_words") or {} | |
| if connectors: | |
| missing = [word for word, present in connectors.items() if not present] | |
| print(f"Connectors missing: {', '.join(missing) if missing else 'none'}") | |
| curriculum = data.get("curriculum_files") or {} | |
| if curriculum: | |
| missing = [name for name, present in curriculum.items() if not present] | |
| print(f"Curriculum files missing: {', '.join(missing) if missing else 'none'}") | |
| for key in ("errors", "warnings"): | |
| items = data.get(key) or [] | |
| if items: | |
| print_heading(key.title()) | |
| for item in items: | |
| print(f"- {item}") | |
| runtime_info = data.get("runtime_info") or {} | |
| if runtime_info: | |
| print_heading("Runtime Info") | |
| print(f"Return code: {runtime_info.get('returncode')}") | |
| stdout = runtime_info.get("stdout_tail") or "" | |
| if stdout: | |
| print(stdout.strip()) | |
| def build_scientific_receipt(client: CRAClient, title: str, tag: str, event_limit: int) -> Dict[str, Any]: | |
| """Collect a compact run receipt and write it to the Research Notepad.""" | |
| sections: Dict[str, Any] = {} | |
| for name, method, path in [ | |
| ("status", "GET", "/api/cra/status"), | |
| ("system", "GET", "/api/cra/system/state"), | |
| ("swarm", "GET", "/api/cra/diagnostics/agent_swarm"), | |
| ("exporter", "GET", "/api/cra/diagnostics/checkpoint_status"), | |
| ("notepad", "GET", "/api/research-notepad/summary"), | |
| ]: | |
| try: | |
| sections[name] = client.request_json(method, path) | |
| except Exception as exc: | |
| sections[name] = {"error": str(exc)} | |
| try: | |
| sections["events"] = client.request_json("GET", "/api/cra/events/recent") | |
| except Exception as exc: | |
| sections["events"] = {"error": str(exc)} | |
| status = sections.get("status", {}) | |
| system = sections.get("system", {}) | |
| swarm = sections.get("swarm", {}) | |
| notepad = sections.get("notepad", {}) | |
| content_lines = [ | |
| f"{title} {tag}".strip(), | |
| "", | |
| f"Status keys: {', '.join(status.keys()) if isinstance(status, dict) else 'unavailable'}", | |
| f"System keys: {', '.join(system.keys()) if isinstance(system, dict) else 'unavailable'}", | |
| f"Swarm available: {'error' not in swarm if isinstance(swarm, dict) else False}", | |
| f"Notepad total: {((notepad.get('summary') or {}).get('total') if isinstance(notepad, dict) else 'unavailable')}", | |
| f"Recent event limit requested: {event_limit}", | |
| "", | |
| "Receipt JSON:", | |
| json.dumps(sections, indent=2, default=str)[:12000], | |
| ] | |
| note = client.request_json( | |
| "POST", | |
| "/api/research-notepad", | |
| payload={ | |
| "type": "analysis", | |
| "content": "\n".join(content_lines), | |
| "metadata": {"source": "cra_cli", "kind": "scientific_receipt"}, | |
| }, | |
| ) | |
| return {"receipt": sections, "notepad": note} | |
| def parse_query_pairs(items: List[str]) -> Dict[str, str]: | |
| query: Dict[str, str] = {} | |
| for item in items: | |
| if "=" not in item: | |
| raise SystemExit(f"Invalid --query value {item!r}; expected key=value") | |
| key, value = item.split("=", 1) | |
| query[key] = value | |
| return query | |
| def run_repl(client: CRAClient, args: argparse.Namespace) -> int: | |
| print("CRA SSH shell. Type /help for commands, /exit to quit.") | |
| while True: | |
| try: | |
| line = input("cra> ").strip() | |
| except (EOFError, KeyboardInterrupt): | |
| print() | |
| return 0 | |
| if not line: | |
| continue | |
| if line in {"/exit", "/quit"}: | |
| return 0 | |
| if line == "/help": | |
| print( | |
| "Local commands:\n" | |
| " /status\n" | |
| " /health\n" | |
| " /system\n" | |
| " /models\n" | |
| " /events\n" | |
| " /logs [name]\n" | |
| " /sim status|start|stop\n" | |
| " /butterfly <message>\n" | |
| " /organism <organism_id> <message>\n" | |
| " /swarm\n" | |
| " /exit\n" | |
| "Anything else is sent to the CRA chat model." | |
| ) | |
| continue | |
| try: | |
| if line == "/status": | |
| summarize_status(client.request_json("GET", "/api/cra/status")) | |
| elif line == "/health": | |
| summarize_health(client.request_json("GET", "/api/cra/health/check")) | |
| elif line == "/system": | |
| summarize_system(client.request_json("GET", "/api/cra/system/state")) | |
| elif line == "/models": | |
| summarize_models(client.request_json("GET", "/api/ollama/models")) | |
| elif line == "/events": | |
| summarize_events(client.request_json("GET", "/api/cra/events/recent"), limit=10) | |
| elif line.startswith("/logs"): | |
| parts = line.split(maxsplit=1) | |
| log_name = parts[1].strip() if len(parts) > 1 else None | |
| summarize_logs(client.request_json("GET", "/api/cra/logs"), log_name=log_name, tail=20) | |
| elif line.startswith("/sim"): | |
| parts = line.split() | |
| action = parts[1] if len(parts) > 1 else "status" | |
| if action == "status": | |
| summarize_sim_status(client.request_json("GET", "/api/simulation/status")) | |
| elif action == "start": | |
| summarize_sim_status(client.request_json("POST", "/api/simulation/start", payload={})) | |
| elif action == "stop": | |
| summarize_sim_status(client.request_json("POST", "/api/simulation/stop", payload={})) | |
| else: | |
| print("Unknown /sim action. Use status, start, or stop.") | |
| elif line.startswith("/butterfly "): | |
| message = line.split(maxsplit=1)[1].strip() | |
| data = client.request_json("POST", "/api/butterfly/chat", payload={ | |
| "message": message, | |
| "routing_strategy": "all", | |
| "max_organisms": 10, | |
| "min_mastery_level": 0, | |
| }) | |
| summarize_butterfly_chat(data) | |
| elif line.startswith("/organism "): | |
| parts = line.split(maxsplit=2) | |
| if len(parts) < 3: | |
| print("Usage: /organism <organism_id> <message>") | |
| continue | |
| data = client.request_json( | |
| "POST", | |
| f"/api/organism/{parse.quote(parts[1])}/chat", | |
| payload={"message": parts[2]}, | |
| ) | |
| summarize_organism_chat(data) | |
| elif line == "/swarm": | |
| summarize_swarm_stats(client.request_json("GET", "/api/cra/diagnostics/agent_swarm")) | |
| else: | |
| reply = do_chat( | |
| client, | |
| message=line, | |
| model=args.model, | |
| vision_model=args.vision_model, | |
| api_key=args.api_key, | |
| ) | |
| summarize_chat(reply) | |
| except Exception as exc: | |
| print(f"Error: {exc}", file=sys.stderr) | |
| def main() -> int: | |
| args = parse_args() | |
| client = CRAClient( | |
| base_url=args.base_url, | |
| timeout=args.timeout, | |
| cra_key=args.cra_key, | |
| hf_auth_token=args.hf_auth_token, | |
| ) | |
| try: | |
| if args.command == "status": | |
| data = client.request_json("GET", "/api/cra/status") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_status(data) | |
| return 0 | |
| if args.command == "sitrep": | |
| status_data = client.request_json("GET", "/api/cra/status") | |
| health_data = client.request_json("GET", "/api/cra/health/check") | |
| system_data = client.request_json("GET", "/api/cra/system/state") | |
| checkpoint_data = client.request_json("GET", "/api/cra/diagnostics/checkpoint_status") | |
| if args.json: | |
| print_json( | |
| { | |
| "status": status_data, | |
| "health": health_data, | |
| "system": system_data, | |
| "checkpoint": checkpoint_data, | |
| } | |
| ) | |
| else: | |
| summarize_sitrep(status_data, health_data, system_data, checkpoint_data) | |
| return 0 | |
| if args.command == "health": | |
| data = client.request_json("GET", "/api/cra/health/check") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_health(data) | |
| return 0 | |
| if args.command == "system": | |
| data = client.request_json("GET", "/api/cra/system/state") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_system(data) | |
| return 0 | |
| if args.command == "data": | |
| data = client.request_json("GET", "/api/cra/data") | |
| print_json(data if args.json else data.get("data", data)) | |
| return 0 | |
| if args.command == "models": | |
| data = client.request_json("GET", "/api/ollama/models") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_models(data) | |
| return 0 | |
| if args.command == "sim-status": | |
| data = client.request_json("GET", "/api/simulation/status") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_sim_status(data) | |
| return 0 | |
| if args.command == "sim-start": | |
| data = client.request_json("POST", "/api/simulation/start", payload={}) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_sim_status(data) | |
| return 0 | |
| if args.command == "sim-stop": | |
| data = client.request_json("POST", "/api/simulation/stop", payload={}) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_sim_status(data) | |
| return 0 | |
| if args.command == "guardian-on": | |
| data = client.request_json( | |
| "POST", | |
| "/api/cra/guardian/mode", | |
| payload={"mode": "enable"}, | |
| ) | |
| print_json(data) | |
| return 0 | |
| if args.command == "events": | |
| data = client.request_json("GET", "/api/cra/events/recent") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_events(data, limit=args.limit) | |
| return 0 | |
| if args.command == "logs": | |
| data = client.request_json("GET", "/api/cra/logs") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_logs(data, log_name=args.log, tail=args.tail) | |
| return 0 | |
| if args.command == "training-status": | |
| system_data = client.request_json("GET", "/api/cra/system/state") | |
| checkpoint_data = client.request_json("GET", "/api/cra/diagnostics/checkpoint_status") | |
| logs_data = client.request_json("GET", "/api/cra/logs") | |
| if args.json: | |
| print_json( | |
| { | |
| "system": system_data, | |
| "checkpoint": checkpoint_data, | |
| "logs": logs_data, | |
| } | |
| ) | |
| else: | |
| summarize_training_status(system_data, checkpoint_data, logs_data) | |
| return 0 | |
| if args.command == "exporter-status": | |
| organisms_data = client.request_json("GET", "/api/organisms") | |
| capsules_data = client.request_json("GET", "/api/capsules") | |
| checkpoint_data = client.request_json("GET", "/api/cra/diagnostics/checkpoint_status") | |
| if args.json: | |
| print_json( | |
| { | |
| "organisms": organisms_data, | |
| "capsules": capsules_data, | |
| "checkpoint": checkpoint_data, | |
| } | |
| ) | |
| else: | |
| summarize_exporter_status(organisms_data, capsules_data, checkpoint_data) | |
| return 0 | |
| if args.command == "security-contracts": | |
| data = client.request_json("GET", "/api/security/contracts") | |
| print_json(data) | |
| return 0 | |
| if args.command == "security-receipts": | |
| data = client.request_json( | |
| "GET", | |
| "/api/security/receipts", | |
| query={"limit": args.limit, "action": args.action}, | |
| ) | |
| print_json(data) | |
| return 0 | |
| if args.command == "config": | |
| if args.history: | |
| data = client.request_json( | |
| "GET", | |
| "/api/config/history", | |
| query={"include_config": "false"}, | |
| ) | |
| elif args.actions: | |
| data = client.request_json( | |
| "GET", | |
| "/api/config/actions", | |
| query={"limit": args.limit}, | |
| ) | |
| elif args.current: | |
| data = client.request_json("GET", "/api/config/current") | |
| else: | |
| data = client.request_json("GET", "/api/cra/config") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_config(data, limit=args.limit) | |
| return 0 | |
| if args.command == "config-set": | |
| patch: List[Dict[str, Any]] = [{"op": args.op, "path": args.path}] | |
| if args.op != "remove": | |
| patch[0]["value"] = parse_jsonish_value(args.value) | |
| data = client.request_json( | |
| "POST", | |
| "/api/config/update", | |
| payload={ | |
| "patch": patch, | |
| "actor": "CRA_CLI", | |
| "reason": args.reason, | |
| }, | |
| ) | |
| print_json(data if args.json else data) | |
| return 0 | |
| if args.command == "config-rollback": | |
| data = client.request_json( | |
| "POST", | |
| "/api/config/rollback", | |
| payload={ | |
| "steps": args.steps, | |
| "actor": "CRA_CLI", | |
| "reason": args.reason, | |
| }, | |
| ) | |
| print_json(data if args.json else data) | |
| return 0 | |
| if args.command == "organisms": | |
| data = client.request_json("GET", "/api/organisms") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_organisms(data, limit=args.limit) | |
| return 0 | |
| if args.command == "alliances": | |
| data = client.request_json("GET", "/api/alliances") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_alliances(data, limit=args.limit) | |
| return 0 | |
| if args.command == "capsules": | |
| data = client.request_json("GET", "/api/capsules") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_capsules(data) | |
| return 0 | |
| if args.command == "checkpoint-status": | |
| data = client.request_json("GET", "/api/cra/diagnostics/checkpoint_status") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_checkpoints(data) | |
| return 0 | |
| if args.command == "checkpoint-list": | |
| data = client.request_json("GET", "/api/checkpoint/list") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_checkpoints(data) | |
| return 0 | |
| if args.command == "checkpoint-save": | |
| data = client.request_json( | |
| "POST", | |
| "/api/checkpoint/save", | |
| payload={"reason": args.reason, "actor": "CRA_CLI"}, | |
| ) | |
| print_json(data if args.json else data) | |
| return 0 | |
| if args.command == "checkpoint-restore": | |
| payload: Dict[str, Any] = { | |
| "actor": "CRA_CLI", | |
| "reason": args.reason, | |
| } | |
| if args.name: | |
| payload["checkpoint_name"] = args.name | |
| data = client.request_json("POST", "/api/checkpoint/restore", payload=payload) | |
| print_json(data if args.json else data) | |
| return 0 | |
| if args.command == "chat": | |
| message = read_message(args) | |
| data = do_chat( | |
| client, | |
| message=message, | |
| model=args.model, | |
| vision_model=args.vision_model, | |
| api_key=args.api_key, | |
| selected_event=args.selected_event, | |
| view_state=read_view_state(args.view_state_file), | |
| ) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_chat(data) | |
| return 0 | |
| if args.command in ("butterfly-chat", "standin-chat"): | |
| message = read_message(args) | |
| actor = "CRA_STANDIN" if args.command == "standin-chat" else "CRA_CLI" | |
| data = client.request_json("POST", "/api/butterfly/chat", payload={ | |
| "message": message, | |
| "routing_strategy": args.routing_strategy, | |
| "max_organisms": args.max_organisms, | |
| "min_mastery_level": args.min_mastery_level, | |
| "actor": actor, | |
| "interaction_context": { | |
| "source": args.command, | |
| "inside_boundary": "inside_game_only", | |
| "consent_condition": "operator_requested", | |
| }, | |
| }) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_butterfly_chat(data) | |
| return 1 if butterfly_chat_failed(data) else 0 | |
| if args.command == "organism-chat": | |
| message = read_message(args) | |
| data = client.request_json( | |
| "POST", | |
| f"/api/organism/{parse.quote(args.organism_id)}/chat", | |
| payload={"message": message, "actor": "CRA_CLI"}, | |
| ) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_organism_chat(data) | |
| return 0 | |
| if args.command == "swarm-stats": | |
| data = client.request_json("GET", "/api/cra/diagnostics/agent_swarm") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_swarm_stats(data) | |
| return 0 | |
| if args.command == "notepad": | |
| if args.summary: | |
| data = client.request_json("GET", "/api/research-notepad/summary") | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_notepad(data, summary_only=True) | |
| return 0 | |
| data = client.request_json( | |
| "GET", | |
| "/api/research-notepad", | |
| query={ | |
| "type": args.type, | |
| "query": args.query, | |
| "limit": args.limit, | |
| }, | |
| ) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_notepad(data) | |
| return 0 | |
| if args.command == "notepad-add": | |
| content = read_message(args) | |
| metadata: Dict[str, Any] = {"source": args.source} | |
| if args.confidence: | |
| metadata["confidence"] = args.confidence | |
| if args.cause: | |
| metadata["causeEventId"] = args.cause | |
| if args.effect: | |
| metadata["effectEventId"] = args.effect | |
| payload = { | |
| "type": args.type, | |
| "content": content, | |
| "metadata": metadata, | |
| "linkedEvents": args.event, | |
| "actor": "CRA_CLI", | |
| } | |
| data = client.request_json("POST", "/api/research-notepad", payload=payload) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| entry = data.get("entry", {}) | |
| print(f"Added {entry.get('type', args.type)} note: {entry.get('id', '-')}") | |
| return 0 | |
| if args.command == "cocoon-validate": | |
| data = validate_cocoon_package( | |
| Path(args.path), | |
| run_info=args.run_info, | |
| python_executable=args.python, | |
| ) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_cocoon_validation(data) | |
| return 0 | |
| if args.command == "scientific-receipt": | |
| data = build_scientific_receipt( | |
| client, | |
| title=args.title, | |
| tag=args.tag, | |
| event_limit=args.event_limit, | |
| ) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| entry = (data.get("notepad") or {}).get("entry", {}) | |
| print(f"Scientific receipt saved to Research Notepad: {entry.get('id', '-')}") | |
| return 0 | |
| if args.command == "repl": | |
| return run_repl(client, args) | |
| if args.command == "compile-organism": | |
| data = client.request_json( | |
| "POST", | |
| f"/api/capsule/{args.organism_id}/compile", | |
| payload={"format": args.format}, | |
| ) | |
| saved_paths = save_downloads(client, data, args.outdir) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_export_result(data, saved_paths) | |
| return 0 | |
| if args.command == "compile-ensemble": | |
| data = client.request_json( | |
| "POST", | |
| "/api/capsules/compile-ensemble", | |
| payload={"organism_ids": args.organism_ids, "format": args.format}, | |
| ) | |
| saved_paths = save_downloads(client, data, args.outdir) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_export_result(data, saved_paths) | |
| return 0 | |
| if args.command == "compile-learning": | |
| payload = { | |
| "organism_ids": args.organism_ids, | |
| "training_config": read_json_file(args.training_config_file), | |
| } | |
| data = client.request_json("POST", "/api/capsules/compile-learning", payload=payload) | |
| saved_paths = save_downloads(client, data, args.outdir) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_export_result(data, saved_paths) | |
| return 0 | |
| if args.command == "compile-cocoon": | |
| selected_alliances = list(args.alliance_ids or []) + list(args.alliance_names or []) | |
| payload = { | |
| "organism_ids": args.organism_ids, | |
| "top_n": args.top_n, | |
| "include_gym": not args.no_gym, | |
| "include_http": not args.no_http, | |
| "compress": not args.no_compress, | |
| "format": args.format, | |
| "actor": "CRA_CLI", | |
| "reason": args.reason, | |
| } | |
| if selected_alliances: | |
| payload["selected_alliances"] = selected_alliances | |
| if args.include_unallied: | |
| payload["include_unallied"] = True | |
| data = client.request_json("POST", "/api/capsules/compile-cocoon", payload=payload) | |
| saved_paths = save_downloads(client, data, args.outdir) | |
| if args.json: | |
| print_json(data) | |
| else: | |
| summarize_export_result(data, saved_paths) | |
| return 0 | |
| if args.command == "api": | |
| payload = json.loads(args.data) if args.data else None | |
| query = parse_query_pairs(args.query) | |
| data = client.request_json(args.method, args.path, payload=payload, query=query) | |
| print_json(data) | |
| return 0 | |
| raise SystemExit(f"Unknown command: {args.command}") | |
| except Exception as exc: | |
| print(f"Error: {exc}", file=sys.stderr) | |
| return 1 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |
Xet Storage Details
- Size:
- 76.7 kB
- Xet hash:
- f87389e9d4ccd2805b86ec69f85dead3f71462233d2ab4985167196240eb1041
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.