the-grid-cc 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,242 @@
1
+ """
2
+ I/O Tower - Human checkpoints where Users connect to The Grid.
3
+
4
+ "The I/O Tower is sacred. It's where we commune with the Users."
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from datetime import datetime
9
+ from typing import Optional, Any, Callable
10
+ from enum import Enum
11
+ import uuid
12
+
13
+
14
+ class CheckpointReason(Enum):
15
+ """Reason for I/O Tower checkpoint."""
16
+ FISSION_DEPTH = "fission_depth"
17
+ BEFORE_COMMIT = "before_commit"
18
+ ERROR_OCCURRED = "error_occurred"
19
+ LOW_ENERGY = "low_energy"
20
+ RECOGNIZER_FAILED = "recognizer_failed"
21
+ USER_REQUESTED = "user_requested"
22
+ DECISION_REQUIRED = "decision_required"
23
+ REVIEW_REQUIRED = "review_required"
24
+
25
+
26
+ class UserDecision(Enum):
27
+ """User decision at checkpoint."""
28
+ AUTHORIZE = "authorize" # Allow action to proceed
29
+ DENY = "deny" # Block action
30
+ MODIFY = "modify" # Modify before proceeding
31
+ MERGE = "merge" # Merge operations (for fission)
32
+ ABORT = "abort" # Abort entire operation
33
+ DEFER = "defer" # Defer decision
34
+
35
+
36
+ @dataclass
37
+ class CheckpointOption:
38
+ """An option presented at a checkpoint."""
39
+ key: str
40
+ label: str
41
+ description: str
42
+ decision: UserDecision
43
+
44
+
45
+ @dataclass
46
+ class CheckpointContext:
47
+ """Context for an I/O Tower checkpoint."""
48
+ reason: CheckpointReason
49
+ program_id: str
50
+ program_name: str
51
+ depth: int
52
+ energy_remaining: int
53
+ energy_allocated: int
54
+ pending_actions: list[str] = field(default_factory=list)
55
+ details: dict = field(default_factory=dict)
56
+
57
+
58
+ @dataclass
59
+ class CheckpointResult:
60
+ """Result of a checkpoint interaction."""
61
+ decision: UserDecision
62
+ timestamp: datetime
63
+ user_input: Optional[str] = None
64
+ modifications: dict = field(default_factory=dict)
65
+
66
+
67
+ class IOTower:
68
+ """
69
+ I/O Tower - Human checkpoint interface.
70
+
71
+ Provides human checkpoints at critical moments:
72
+ - Fission depth >= configured threshold
73
+ - Before commits
74
+ - On errors
75
+ - Energy running low
76
+ - Recognizer flags issues
77
+ """
78
+
79
+ # Default options for common checkpoint types
80
+ DEFAULT_OPTIONS = {
81
+ CheckpointReason.FISSION_DEPTH: [
82
+ CheckpointOption("A", "Authorize", "Allow fission to continue", UserDecision.AUTHORIZE),
83
+ CheckpointOption("M", "Merge", "Combine into single Program (saves Energy)", UserDecision.MERGE),
84
+ CheckpointOption("D", "Deny", "Block spawning, continue with current Program", UserDecision.DENY),
85
+ CheckpointOption("V", "View Disc", "See full context before deciding", UserDecision.DEFER),
86
+ ],
87
+ CheckpointReason.BEFORE_COMMIT: [
88
+ CheckpointOption("C", "Commit", "Proceed with commit", UserDecision.AUTHORIZE),
89
+ CheckpointOption("R", "Review", "Review changes first", UserDecision.DEFER),
90
+ CheckpointOption("M", "Modify", "Modify commit message/contents", UserDecision.MODIFY),
91
+ CheckpointOption("A", "Abort", "Cancel commit", UserDecision.ABORT),
92
+ ],
93
+ CheckpointReason.ERROR_OCCURRED: [
94
+ CheckpointOption("R", "Retry", "Retry the operation", UserDecision.AUTHORIZE),
95
+ CheckpointOption("S", "Skip", "Skip this operation", UserDecision.DENY),
96
+ CheckpointOption("A", "Abort", "Abort the entire process", UserDecision.ABORT),
97
+ CheckpointOption("D", "Debug", "View debug information", UserDecision.DEFER),
98
+ ],
99
+ CheckpointReason.LOW_ENERGY: [
100
+ CheckpointOption("C", "Continue", "Continue with remaining energy", UserDecision.AUTHORIZE),
101
+ CheckpointOption("A", "Allocate", "Allocate more energy", UserDecision.MODIFY),
102
+ CheckpointOption("P", "Pause", "Pause and save state", UserDecision.DEFER),
103
+ CheckpointOption("S", "Stop", "Stop execution", UserDecision.ABORT),
104
+ ],
105
+ CheckpointReason.RECOGNIZER_FAILED: [
106
+ CheckpointOption("F", "Fix", "Fix issues and retry", UserDecision.MODIFY),
107
+ CheckpointOption("O", "Override", "Override and continue", UserDecision.AUTHORIZE),
108
+ CheckpointOption("R", "Review", "Review issues in detail", UserDecision.DEFER),
109
+ CheckpointOption("A", "Abort", "Abort due to validation failure", UserDecision.ABORT),
110
+ ],
111
+ }
112
+
113
+ def __init__(
114
+ self,
115
+ require_at_depth: int = 3,
116
+ require_before_commit: bool = True,
117
+ require_on_error: bool = True,
118
+ require_on_low_energy: bool = True,
119
+ timeout_seconds: int = 300,
120
+ ):
121
+ self.require_at_depth = require_at_depth
122
+ self.require_before_commit = require_before_commit
123
+ self.require_on_error = require_on_error
124
+ self.require_on_low_energy = require_on_low_energy
125
+ self.timeout_seconds = timeout_seconds
126
+
127
+ # Checkpoint history
128
+ self.checkpoints: list[tuple[CheckpointContext, CheckpointResult]] = []
129
+
130
+ # Callback for user input (to be set by CLI)
131
+ self.input_handler: Optional[Callable[[CheckpointContext, list[CheckpointOption]], CheckpointResult]] = None
132
+
133
+ def should_checkpoint(
134
+ self,
135
+ reason: CheckpointReason,
136
+ depth: int = 0,
137
+ energy_percentage: float = 100.0,
138
+ ) -> bool:
139
+ """Determine if a checkpoint is required."""
140
+ if reason == CheckpointReason.FISSION_DEPTH:
141
+ return depth >= self.require_at_depth
142
+ elif reason == CheckpointReason.BEFORE_COMMIT:
143
+ return self.require_before_commit
144
+ elif reason == CheckpointReason.ERROR_OCCURRED:
145
+ return self.require_on_error
146
+ elif reason == CheckpointReason.LOW_ENERGY:
147
+ return self.require_on_low_energy and energy_percentage < 10
148
+ elif reason == CheckpointReason.RECOGNIZER_FAILED:
149
+ return True # Always checkpoint on validation failure
150
+ elif reason == CheckpointReason.USER_REQUESTED:
151
+ return True
152
+ return False
153
+
154
+ def checkpoint(
155
+ self,
156
+ context: CheckpointContext,
157
+ options: list[CheckpointOption] = None,
158
+ ) -> CheckpointResult:
159
+ """
160
+ Trigger a checkpoint and await user decision.
161
+
162
+ In actual use, this would pause execution and present
163
+ options to the user through the CLI.
164
+ """
165
+ if options is None:
166
+ options = self.DEFAULT_OPTIONS.get(context.reason, [])
167
+
168
+ # If we have an input handler, use it
169
+ if self.input_handler:
170
+ result = self.input_handler(context, options)
171
+ else:
172
+ # Default: authorize (for testing/non-interactive)
173
+ result = CheckpointResult(
174
+ decision=UserDecision.AUTHORIZE,
175
+ timestamp=datetime.now(),
176
+ )
177
+
178
+ self.checkpoints.append((context, result))
179
+ return result
180
+
181
+ def render_checkpoint(
182
+ self,
183
+ context: CheckpointContext,
184
+ options: list[CheckpointOption],
185
+ ) -> str:
186
+ """Render checkpoint display."""
187
+ lines = [
188
+ "╔" + "═" * 77 + "╗",
189
+ "║ ⛯ I/O TOWER - Human Input Required" + " " * 40 + "║",
190
+ "╠" + "═" * 77 + "╣",
191
+ "║" + " " * 77 + "║",
192
+ f"║ REASON: {context.reason.value:<65}║",
193
+ "║" + " " * 77 + "║",
194
+ "║ CONTEXT:" + " " * 67 + "║",
195
+ ]
196
+
197
+ # Program info
198
+ lines.append(f"║ Program \"{context.program_name}\" (depth: {context.depth})" + " " * (48 - len(context.program_name)) + "║")
199
+ lines.append(f"║ Energy: {context.energy_remaining}/{context.energy_allocated}" + " " * 55 + "║")
200
+
201
+ # Pending actions
202
+ if context.pending_actions:
203
+ lines.append("║" + " " * 77 + "║")
204
+ lines.append("║ Pending actions:" + " " * 59 + "║")
205
+ for action in context.pending_actions[:5]: # Limit display
206
+ lines.append(f"║ • {action:<71}║")
207
+
208
+ # Details
209
+ if context.details:
210
+ lines.append("║" + " " * 77 + "║")
211
+ for key, value in list(context.details.items())[:5]:
212
+ lines.append(f"║ {key}: {str(value):<69}║")
213
+
214
+ # Options
215
+ lines.append("║" + " " * 77 + "║")
216
+ lines.append("║ ┌" + "─" * 73 + "┐ ║")
217
+ for opt in options:
218
+ lines.append(f"║ │ [{opt.key}] {opt.label} - {opt.description:<55}│ ║")
219
+ lines.append("║ └" + "─" * 73 + "┘ ║")
220
+ lines.append("║" + " " * 77 + "║")
221
+ lines.append("╚" + "═" * 77 + "╝")
222
+
223
+ return "\n".join(lines)
224
+
225
+ def get_history(self) -> list[dict]:
226
+ """Get checkpoint history."""
227
+ return [
228
+ {
229
+ "context": {
230
+ "reason": ctx.reason.value,
231
+ "program_id": ctx.program_id,
232
+ "program_name": ctx.program_name,
233
+ "depth": ctx.depth,
234
+ },
235
+ "result": {
236
+ "decision": res.decision.value,
237
+ "timestamp": res.timestamp.isoformat(),
238
+ "user_input": res.user_input,
239
+ },
240
+ }
241
+ for ctx, res in self.checkpoints
242
+ ]
@@ -0,0 +1,268 @@
1
+ """
2
+ Program - Autonomous executor on The Grid.
3
+
4
+ "Programs are living entities on The Grid. They execute, they adapt, they spawn."
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from datetime import datetime
9
+ from typing import Optional, Callable, Any
10
+ from enum import Enum
11
+ import uuid
12
+
13
+ from .disc import IdentityDisc
14
+
15
+
16
+ class ProgramStatus(Enum):
17
+ """Status of a Program."""
18
+ INITIALIZING = "initializing"
19
+ RUNNING = "running"
20
+ SPAWNING = "spawning"
21
+ WAITING = "waiting"
22
+ COMPLETED = "completed"
23
+ FAILED = "failed"
24
+ DEREZZED = "derezzed"
25
+
26
+
27
+ class ProgramType(Enum):
28
+ """Type of Program."""
29
+ STANDARD = "standard"
30
+ RECOGNIZER = "recognizer"
31
+ LIGHT_CYCLE = "light_cycle" # Fast execution path
32
+
33
+
34
+ @dataclass
35
+ class SpawnRequest:
36
+ """Request to spawn a child Program."""
37
+ name: str
38
+ purpose: str
39
+ energy_budget: int
40
+ constraints: list[str] = field(default_factory=list)
41
+ approved: bool = False
42
+
43
+
44
+ class Program:
45
+ """
46
+ Program - Autonomous executor (subagent) on The Grid.
47
+
48
+ Programs can:
49
+ - Execute tasks autonomously
50
+ - Spawn child Programs (fission)
51
+ - Carry context via Identity Disc
52
+ - Consume energy from their budget
53
+ """
54
+
55
+ def __init__(
56
+ self,
57
+ name: str,
58
+ purpose: str,
59
+ parent: Optional["Program"] = None,
60
+ energy_budget: int = 100,
61
+ program_type: ProgramType = ProgramType.STANDARD,
62
+ ):
63
+ self.id = str(uuid.uuid4())[:8]
64
+ self.name = name
65
+ self.purpose = purpose
66
+ self.program_type = program_type
67
+
68
+ self.status = ProgramStatus.INITIALIZING
69
+ self.created_at = datetime.now()
70
+ self.started_at: Optional[datetime] = None
71
+ self.completed_at: Optional[datetime] = None
72
+
73
+ # Fission lineage
74
+ self.parent = parent
75
+ self.children: list["Program"] = []
76
+ self.depth = 0 if parent is None else parent.depth + 1
77
+
78
+ # Identity Disc (context carrier)
79
+ parent_disc = parent.disc if parent else None
80
+ self.disc = IdentityDisc(
81
+ program_id=f"program:{self.id}",
82
+ purpose=purpose,
83
+ parent_disc=parent_disc,
84
+ )
85
+ self.disc.energy_allocated = energy_budget
86
+
87
+ # Execution state
88
+ self.current_action = "Initializing"
89
+ self.output: Any = None
90
+ self.error: Optional[str] = None
91
+
92
+ # Spawn requests (pending fission)
93
+ self.spawn_requests: list[SpawnRequest] = []
94
+
95
+ def start(self) -> None:
96
+ """Start Program execution."""
97
+ self.status = ProgramStatus.RUNNING
98
+ self.started_at = datetime.now()
99
+ self.current_action = "Running"
100
+
101
+ def update_action(self, action: str) -> None:
102
+ """Update current action."""
103
+ self.current_action = action
104
+
105
+ def request_spawn(
106
+ self,
107
+ name: str,
108
+ purpose: str,
109
+ energy_budget: int,
110
+ constraints: list[str] = None,
111
+ ) -> SpawnRequest:
112
+ """Request to spawn a child Program."""
113
+ request = SpawnRequest(
114
+ name=name,
115
+ purpose=purpose,
116
+ energy_budget=energy_budget,
117
+ constraints=constraints or [],
118
+ )
119
+ self.spawn_requests.append(request)
120
+ self.status = ProgramStatus.SPAWNING
121
+ return request
122
+
123
+ def spawn(self, request: SpawnRequest) -> Optional["Program"]:
124
+ """Spawn a child Program from approved request."""
125
+ if not request.approved:
126
+ return None
127
+
128
+ # Deduct energy for spawn
129
+ if not self.disc.consume_energy(request.energy_budget):
130
+ return None
131
+
132
+ child = Program(
133
+ name=request.name,
134
+ purpose=request.purpose,
135
+ parent=self,
136
+ energy_budget=request.energy_budget,
137
+ )
138
+ for constraint in request.constraints:
139
+ child.disc.add_constraint(constraint)
140
+
141
+ self.children.append(child)
142
+ return child
143
+
144
+ def consume_energy(self, amount: int, description: str = "") -> bool:
145
+ """Consume energy for an operation."""
146
+ success = self.disc.consume_energy(amount)
147
+ if success:
148
+ self.disc.record_discovery(
149
+ finding=f"Energy consumed: {amount}",
150
+ source="energy_system",
151
+ relevance="low",
152
+ )
153
+ return success
154
+
155
+ def complete(self, output: Any = None) -> None:
156
+ """Mark Program as completed."""
157
+ self.status = ProgramStatus.COMPLETED
158
+ self.completed_at = datetime.now()
159
+ self.output = output
160
+ self.current_action = "Completed"
161
+
162
+ # Return unused energy to parent
163
+ if self.parent:
164
+ unused = self.disc.energy_remaining()
165
+ if unused > 0:
166
+ self.parent.disc.energy_allocated += unused
167
+
168
+ def fail(self, error: str) -> None:
169
+ """Mark Program as failed."""
170
+ self.status = ProgramStatus.FAILED
171
+ self.completed_at = datetime.now()
172
+ self.error = error
173
+ self.current_action = f"Failed: {error}"
174
+
175
+ def derez(self) -> None:
176
+ """Derez (terminate) this Program and all children."""
177
+ self.status = ProgramStatus.DEREZZED
178
+ self.disc.derez()
179
+ for child in self.children:
180
+ child.derez()
181
+
182
+ def wait_for_children(self) -> None:
183
+ """Set status to waiting for children to complete."""
184
+ self.status = ProgramStatus.WAITING
185
+ self.current_action = "Waiting for child Programs"
186
+
187
+ def all_children_completed(self) -> bool:
188
+ """Check if all child Programs are completed."""
189
+ return all(
190
+ c.status in (ProgramStatus.COMPLETED, ProgramStatus.DEREZZED)
191
+ for c in self.children
192
+ )
193
+
194
+ def any_child_failed(self) -> bool:
195
+ """Check if any child Program failed."""
196
+ return any(
197
+ c.status == ProgramStatus.FAILED
198
+ for c in self.children
199
+ )
200
+
201
+ def get_lineage(self) -> list[str]:
202
+ """Get the lineage chain of Program names."""
203
+ return self.disc.get_lineage()
204
+
205
+ def depth_display(self) -> str:
206
+ """Get depth indicator for display."""
207
+ return " " * self.depth
208
+
209
+ def status_icon(self) -> str:
210
+ """Get status icon for display."""
211
+ icons = {
212
+ ProgramStatus.INITIALIZING: "○",
213
+ ProgramStatus.RUNNING: "◐",
214
+ ProgramStatus.SPAWNING: "◎",
215
+ ProgramStatus.WAITING: "◑",
216
+ ProgramStatus.COMPLETED: "●",
217
+ ProgramStatus.FAILED: "✗",
218
+ ProgramStatus.DEREZZED: "◯",
219
+ }
220
+ return icons.get(self.status, "?")
221
+
222
+ def duration(self) -> Optional[float]:
223
+ """Get execution duration in seconds."""
224
+ if not self.started_at:
225
+ return None
226
+ end = self.completed_at or datetime.now()
227
+ return (end - self.started_at).total_seconds()
228
+
229
+ def energy_percentage(self) -> float:
230
+ """Get energy as percentage."""
231
+ return self.disc.energy_percentage()
232
+
233
+ def summary(self) -> str:
234
+ """Get Program summary."""
235
+ lines = [
236
+ f"Program: {self.name} [{self.id}]",
237
+ f" Purpose: {self.purpose}",
238
+ f" Status: {self.status.value}",
239
+ f" Depth: {self.depth}",
240
+ f" Energy: {self.disc.energy_remaining()}/{self.disc.energy_allocated}",
241
+ f" Children: {len(self.children)}",
242
+ f" Action: {self.current_action}",
243
+ ]
244
+ return "\n".join(lines)
245
+
246
+ def to_dict(self) -> dict:
247
+ """Serialize Program to dictionary."""
248
+ return {
249
+ "id": self.id,
250
+ "name": self.name,
251
+ "purpose": self.purpose,
252
+ "type": self.program_type.value,
253
+ "status": self.status.value,
254
+ "depth": self.depth,
255
+ "current_action": self.current_action,
256
+ "energy_remaining": self.disc.energy_remaining(),
257
+ "energy_allocated": self.disc.energy_allocated,
258
+ "children": [c.to_dict() for c in self.children],
259
+ "lineage": self.get_lineage(),
260
+ "output": str(self.output) if self.output else None,
261
+ "error": self.error,
262
+ "created_at": self.created_at.isoformat(),
263
+ "started_at": self.started_at.isoformat() if self.started_at else None,
264
+ "completed_at": self.completed_at.isoformat() if self.completed_at else None,
265
+ }
266
+
267
+ def __repr__(self) -> str:
268
+ return f"Program(id={self.id}, name={self.name}, depth={self.depth})"