monoco-toolkit 0.3.11__py3-none-any.whl → 0.3.12__py3-none-any.whl
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.
- monoco/core/automation/__init__.py +51 -0
- monoco/core/automation/config.py +338 -0
- monoco/core/automation/field_watcher.py +296 -0
- monoco/core/automation/handlers.py +723 -0
- monoco/core/config.py +1 -1
- monoco/core/executor/__init__.py +38 -0
- monoco/core/executor/agent_action.py +254 -0
- monoco/core/executor/git_action.py +303 -0
- monoco/core/executor/im_action.py +309 -0
- monoco/core/executor/pytest_action.py +218 -0
- monoco/core/git.py +15 -0
- monoco/core/hooks/context.py +74 -13
- monoco/core/router/__init__.py +55 -0
- monoco/core/router/action.py +341 -0
- monoco/core/router/router.py +392 -0
- monoco/core/scheduler/__init__.py +63 -0
- monoco/core/scheduler/base.py +152 -0
- monoco/core/scheduler/engines.py +175 -0
- monoco/core/scheduler/events.py +171 -0
- monoco/core/scheduler/local.py +377 -0
- monoco/core/watcher/__init__.py +57 -0
- monoco/core/watcher/base.py +365 -0
- monoco/core/watcher/dropzone.py +152 -0
- monoco/core/watcher/issue.py +303 -0
- monoco/core/watcher/memo.py +200 -0
- monoco/core/watcher/task.py +238 -0
- monoco/daemon/events.py +34 -0
- monoco/daemon/scheduler.py +172 -201
- monoco/daemon/services.py +27 -243
- monoco/features/agent/__init__.py +25 -7
- monoco/features/agent/cli.py +91 -57
- monoco/features/agent/engines.py +31 -170
- monoco/features/agent/worker.py +1 -1
- monoco/features/issue/commands.py +90 -32
- monoco/features/issue/core.py +249 -4
- monoco/features/spike/commands.py +5 -3
- {monoco_toolkit-0.3.11.dist-info → monoco_toolkit-0.3.12.dist-info}/METADATA +1 -1
- {monoco_toolkit-0.3.11.dist-info → monoco_toolkit-0.3.12.dist-info}/RECORD +41 -20
- monoco/features/agent/apoptosis.py +0 -44
- monoco/features/agent/manager.py +0 -127
- monoco/features/agent/session.py +0 -169
- {monoco_toolkit-0.3.11.dist-info → monoco_toolkit-0.3.12.dist-info}/WHEEL +0 -0
- {monoco_toolkit-0.3.11.dist-info → monoco_toolkit-0.3.12.dist-info}/entry_points.txt +0 -0
- {monoco_toolkit-0.3.11.dist-info → monoco_toolkit-0.3.12.dist-info}/licenses/LICENSE +0 -0
monoco/features/agent/session.py
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from typing import Optional
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from pydantic import BaseModel, Field, ConfigDict
|
|
5
|
-
|
|
6
|
-
from .worker import Worker
|
|
7
|
-
from monoco.core.hooks import HookContext, HookRegistry, get_registry
|
|
8
|
-
from monoco.core.config import find_monoco_root
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class Session(BaseModel):
|
|
12
|
-
"""
|
|
13
|
-
Represents a runtime session of a worker.
|
|
14
|
-
Persisted state of the session.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
18
|
-
|
|
19
|
-
id: str = Field(..., description="Unique session ID (likely UUID)")
|
|
20
|
-
issue_id: str = Field(..., description="The Issue ID this session is working on")
|
|
21
|
-
role_name: str = Field(..., description="Name of the role employed")
|
|
22
|
-
status: str = Field(
|
|
23
|
-
default="pending", description="pending, running, suspended, terminated"
|
|
24
|
-
)
|
|
25
|
-
branch_name: str = Field(
|
|
26
|
-
..., description="Git branch name associated with this session"
|
|
27
|
-
)
|
|
28
|
-
pid: Optional[int] = Field(default=None, description="Process ID of the worker")
|
|
29
|
-
created_at: datetime = Field(default_factory=datetime.now)
|
|
30
|
-
updated_at: datetime = Field(default_factory=datetime.now)
|
|
31
|
-
# History could be a list of logs or pointers to git commits
|
|
32
|
-
# For now, let's keep it simple. The git log IS the history.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class RuntimeSession:
|
|
36
|
-
"""
|
|
37
|
-
The in-memory wrapper around the Session model and the active Worker.
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
def __init__(
|
|
41
|
-
self,
|
|
42
|
-
session_model: Session,
|
|
43
|
-
worker: Optional[Worker],
|
|
44
|
-
hook_registry: Optional[HookRegistry] = None,
|
|
45
|
-
project_root: Optional[Path] = None,
|
|
46
|
-
save_callback: Optional[callable] = None,
|
|
47
|
-
):
|
|
48
|
-
self.model = session_model
|
|
49
|
-
self.worker = worker
|
|
50
|
-
self.hook_registry = hook_registry or get_registry()
|
|
51
|
-
self.project_root = project_root or find_monoco_root()
|
|
52
|
-
self.save_callback = save_callback
|
|
53
|
-
|
|
54
|
-
def _save(self):
|
|
55
|
-
if self.save_callback:
|
|
56
|
-
self.save_callback(self.model)
|
|
57
|
-
|
|
58
|
-
def _create_hook_context(self) -> HookContext:
|
|
59
|
-
"""Create a HookContext from the current session state."""
|
|
60
|
-
return HookContext.from_runtime_session(self, self.project_root)
|
|
61
|
-
|
|
62
|
-
def start(self, context: Optional[dict] = None):
|
|
63
|
-
if not self.worker:
|
|
64
|
-
raise RuntimeError(
|
|
65
|
-
"Cannot start session in observer mode (no worker attached)"
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
print(
|
|
69
|
-
f"Session {self.model.id}: Starting worker on branch {self.model.branch_name}"
|
|
70
|
-
)
|
|
71
|
-
# In real impl, checking out branch happening here
|
|
72
|
-
self.model.status = "running"
|
|
73
|
-
self.model.updated_at = datetime.now()
|
|
74
|
-
|
|
75
|
-
try:
|
|
76
|
-
# Execute on_session_start hooks
|
|
77
|
-
hook_context = self._create_hook_context()
|
|
78
|
-
self.hook_registry.execute_on_session_start(hook_context)
|
|
79
|
-
|
|
80
|
-
self.worker.start(context)
|
|
81
|
-
# Async mode: we assume it started running.
|
|
82
|
-
# Use poll or refresh_status to check later.
|
|
83
|
-
self.model.status = "running"
|
|
84
|
-
self.model.pid = self.worker.process_id
|
|
85
|
-
except Exception:
|
|
86
|
-
self.model.status = "failed"
|
|
87
|
-
raise
|
|
88
|
-
finally:
|
|
89
|
-
self.model.updated_at = datetime.now()
|
|
90
|
-
self._save()
|
|
91
|
-
|
|
92
|
-
def refresh_status(self) -> str:
|
|
93
|
-
"""
|
|
94
|
-
Polls the worker and updates the session model status.
|
|
95
|
-
"""
|
|
96
|
-
if self.worker:
|
|
97
|
-
worker_status = self.worker.poll()
|
|
98
|
-
self.model.status = worker_status
|
|
99
|
-
else:
|
|
100
|
-
# Observer mode
|
|
101
|
-
if self.model.pid:
|
|
102
|
-
try:
|
|
103
|
-
import os
|
|
104
|
-
|
|
105
|
-
# Check if process exists.
|
|
106
|
-
# kill(pid, 0) does not send a signal but raises OSError if pid missing
|
|
107
|
-
os.kill(self.model.pid, 0)
|
|
108
|
-
# If we are here, process exists. We assume running if it was running.
|
|
109
|
-
# We can't detect "suspended" easily without psutil.
|
|
110
|
-
if self.model.status == "terminated":
|
|
111
|
-
# If we thought it was terminated but it's alive, maybe update?
|
|
112
|
-
# Or keep as terminated? Let's assume running if found.
|
|
113
|
-
pass
|
|
114
|
-
except OSError:
|
|
115
|
-
self.model.status = "terminated"
|
|
116
|
-
else:
|
|
117
|
-
self.model.status = "terminated"
|
|
118
|
-
|
|
119
|
-
self.model.updated_at = datetime.now()
|
|
120
|
-
self._save()
|
|
121
|
-
return self.model.status
|
|
122
|
-
|
|
123
|
-
def suspend(self):
|
|
124
|
-
if not self.worker:
|
|
125
|
-
raise RuntimeError("Cannot suspend session in observer mode")
|
|
126
|
-
|
|
127
|
-
print(f"Session {self.model.id}: Suspending worker")
|
|
128
|
-
self.worker.stop()
|
|
129
|
-
self.model.status = "suspended"
|
|
130
|
-
self.model.updated_at = datetime.now()
|
|
131
|
-
self._save()
|
|
132
|
-
# In real impl, ensure git commit of current state?
|
|
133
|
-
|
|
134
|
-
def resume(self):
|
|
135
|
-
if not self.worker:
|
|
136
|
-
raise RuntimeError("Cannot resume session in observer mode")
|
|
137
|
-
|
|
138
|
-
print(f"Session {self.model.id}: Resuming worker")
|
|
139
|
-
self.worker.start() # In real impl, might need to re-init process
|
|
140
|
-
|
|
141
|
-
# Async mode: assume running
|
|
142
|
-
self.model.status = "running"
|
|
143
|
-
self.model.pid = self.worker.process_id
|
|
144
|
-
self.model.updated_at = datetime.now()
|
|
145
|
-
self._save()
|
|
146
|
-
|
|
147
|
-
def terminate(self):
|
|
148
|
-
print(f"Session {self.model.id}: Terminating")
|
|
149
|
-
|
|
150
|
-
# Execute on_session_end hooks before stopping worker
|
|
151
|
-
# This allows hooks to perform cleanup while session context is still valid
|
|
152
|
-
try:
|
|
153
|
-
hook_context = self._create_hook_context()
|
|
154
|
-
results = self.hook_registry.execute_on_session_end(hook_context)
|
|
155
|
-
|
|
156
|
-
# Log hook results
|
|
157
|
-
for result in results:
|
|
158
|
-
if result.status == "failure":
|
|
159
|
-
print(f" Hook warning: {result.message}")
|
|
160
|
-
except Exception as e:
|
|
161
|
-
# Don't let hook errors prevent session termination
|
|
162
|
-
print(f" Hook execution error: {e}")
|
|
163
|
-
|
|
164
|
-
if self.worker:
|
|
165
|
-
self.worker.stop()
|
|
166
|
-
|
|
167
|
-
self.model.status = "terminated"
|
|
168
|
-
self.model.updated_at = datetime.now()
|
|
169
|
-
self._save()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|