Coverage for src / osiris_cli / neural_tools.py: 0%
65 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-31 05:01 +0200
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-31 05:01 +0200
1#!/usr/bin/env python3
2"""
3Neural & Cognitive Tools for Osiris CLI
4Handles scratchpad management, model state dumping, and behavioral cloning.
5"""
7import os
8import json
9import time
10from pathlib import Path
11from typing import Dict, Any, Optional, List
12from datetime import datetime
14class NeuralTools:
15 """Specialized tools for neural state management and behavioral alignment."""
17 def __init__(self, project_root: Optional[Path] = None):
18 self.root = project_root or Path.cwd()
19 self.scratchpad_path = self.root / "SCRATCHPAD.md"
20 self.state_dir = self.root / ".osiris" / "neural_state"
21 self.state_dir.mkdir(parents=True, exist_ok=True)
22 self.cloning_dir = self.root / ".osiris" / "behavioral_cloning"
23 self.cloning_dir.mkdir(parents=True, exist_ok=True)
25 def scratchpad(self, action: str, content: Optional[str] = None) -> str:
26 """
27 Manage a persistent project-level scratchpad for planning and temporary notes.
29 Args:
30 action: "read", "write", or "append"
31 content: Content to write or append
32 """
33 if action == "read":
34 if not self.scratchpad_path.exists():
35 return "Scratchpad is empty. Use 'write' to initialize it."
36 return self.scratchpad_path.read_text(encoding='utf-8')
38 elif action == "write":
39 self.scratchpad_path.write_text(content or "", encoding='utf-8')
40 return f"Scratchpad updated at {datetime.now().strftime('%H:%M:%S')}"
42 elif action == "append":
43 with open(self.scratchpad_path, "a", encoding='utf-8') as f:
44 f.write(f"\n\n--- Added {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ---\n{content}")
45 return "Content appended to scratchpad."
47 return "Invalid action. Use 'read', 'write', or 'append'."
49 def dump_state(self, state_obj: Dict[str, Any], label: str = "latest") -> str:
50 """
51 Persist neural model state (optimized for Flax/JAX structures).
53 Args:
54 state_obj: The state dictionary to persist
55 label: Unique label for this state dump
56 """
57 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
58 filename = f"state_{label}_{timestamp}.json"
59 target_path = self.state_dir / filename
61 try:
62 # Handle JAX/Flax specific types if present (simplified for now)
63 # In a real JAX env, we would use orbax or msgpack
64 serializable_state = self._make_serializable(state_obj)
66 with open(target_path, "w", encoding='utf-8') as f:
67 json.dump(serializable_state, f, indent=2)
69 return f"Neural state dumped to {target_path}"
70 except Exception as e:
71 return f"Failed to dump state: {str(e)}"
73 def behavioral_cloning(self, mission_id: str, success: bool = True) -> str:
74 """
75 Export the current interaction sequence for behavioral cloning and alignment.
77 Args:
78 mission_id: Identifier for the current task/mission
79 success: Whether the mission was accomplished successfully
80 """
81 from .session import session
83 history = session.messages
85 payload = {
86 "mission_id": mission_id,
87 "timestamp": datetime.now().isoformat(),
88 "status": "success" if success else "failed",
89 "interactions": history,
90 "environment": {
91 "cwd": str(self.root),
92 "os": os.name
93 }
94 }
96 filename = f"clone_{mission_id}_{datetime.now().strftime('%H%M%S')}.json"
97 target_path = self.cloning_dir / filename
99 with open(target_path, "w", encoding='utf-8') as f:
100 json.dump(payload, f, indent=2)
102 return f"Behavioral trace archived for alignment: {target_path}"
104 def pad_outputs(self, outputs: List[Any], max_length: int, pad_value: Any = 0) -> List[Any]:
105 """
106 Standardized padding for neural sequence outputs (tensors or token lists).
108 Args:
109 outputs: List of sequences to pad
110 max_length: Target length for all sequences
111 pad_value: Value to use for padding
112 """
113 padded = []
114 for seq in outputs:
115 if len(seq) > max_length:
116 padded.append(seq[:max_length])
117 else:
118 padded.append(list(seq) + [pad_value] * (max_length - len(seq)))
119 return padded
121 def _make_serializable(self, obj: Any) -> Any:
122 """Recursively convert objects to JSON-serializable formats."""
123 if isinstance(obj, (str, int, float, bool, type(None))):
124 return obj
125 elif isinstance(obj, dict):
126 return {k: self._make_serializable(v) for k, v in obj.items()}
127 elif isinstance(obj, (list, tuple)):
128 return [self._make_serializable(item) for item in obj]
129 elif hasattr(obj, "tolist"): # Numpy/JAX arrays
130 return obj.tolist()
131 else:
132 return str(obj)
134# Singleton instance
135neural_tools = NeuralTools()