pygent 0.1.13__tar.gz → 0.1.14__tar.gz
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.
- {pygent-0.1.13 → pygent-0.1.14}/PKG-INFO +1 -1
- {pygent-0.1.13 → pygent-0.1.14}/pygent/agent.py +30 -3
- {pygent-0.1.13 → pygent-0.1.14}/pygent/task_manager.py +18 -2
- {pygent-0.1.13 → pygent-0.1.14}/pygent/tools.py +11 -1
- {pygent-0.1.13 → pygent-0.1.14}/pygent.egg-info/PKG-INFO +1 -1
- {pygent-0.1.13 → pygent-0.1.14}/pyproject.toml +1 -1
- {pygent-0.1.13 → pygent-0.1.14}/tests/test_tasks.py +17 -1
- {pygent-0.1.13 → pygent-0.1.14}/LICENSE +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/README.md +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent/__init__.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent/__main__.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent/cli.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent/errors.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent/models.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent/openai_compat.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent/py.typed +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent/runtime.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent/ui.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent.egg-info/SOURCES.txt +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent.egg-info/dependency_links.txt +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent.egg-info/entry_points.txt +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent.egg-info/requires.txt +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/pygent.egg-info/top_level.txt +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/setup.cfg +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/tests/test_autorun.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/tests/test_custom_model.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/tests/test_error_handling.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/tests/test_runtime.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/tests/test_tools.py +0 -0
- {pygent-0.1.13 → pygent-0.1.14}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pygent
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.14
|
4
4
|
Summary: Pygent is a minimalist coding assistant that runs commands in a Docker container when available and falls back to local execution. See https://marianochaves.github.io/pygent for documentation and https://github.com/marianochaves/pygent for the source code.
|
5
5
|
Author-email: Mariano Chaves <mchaves.software@gmail.com>
|
6
6
|
Project-URL: Documentation, https://marianochaves.github.io/pygent
|
@@ -44,7 +44,10 @@ class Agent:
|
|
44
44
|
self.history.append({"role": "system", "content": self.system_msg})
|
45
45
|
|
46
46
|
def step(self, user_msg: str):
|
47
|
+
"""Execute one round of interaction with the model."""
|
48
|
+
|
47
49
|
self.history.append({"role": "user", "content": user_msg})
|
50
|
+
|
48
51
|
assistant_msg = self.model.chat(
|
49
52
|
self.history, self.model_name, tools.TOOL_SCHEMAS
|
50
53
|
)
|
@@ -60,12 +63,36 @@ class Agent:
|
|
60
63
|
console.print(Panel(markdown_response, title="Resposta do Agente", title_align="left", border_style="cyan"))
|
61
64
|
return assistant_msg
|
62
65
|
|
63
|
-
def run_until_stop(
|
64
|
-
|
65
|
-
|
66
|
+
def run_until_stop(
|
67
|
+
self,
|
68
|
+
user_msg: str,
|
69
|
+
max_steps: int = 20,
|
70
|
+
step_timeout: float | None = None,
|
71
|
+
max_time: float | None = None,
|
72
|
+
) -> None:
|
73
|
+
"""Run steps until ``stop`` is called or limits are reached."""
|
74
|
+
|
75
|
+
if step_timeout is None:
|
76
|
+
env = os.getenv("PYGENT_STEP_TIMEOUT")
|
77
|
+
step_timeout = float(env) if env else None
|
78
|
+
if max_time is None:
|
79
|
+
env = os.getenv("PYGENT_TASK_TIMEOUT")
|
80
|
+
max_time = float(env) if env else None
|
81
|
+
|
66
82
|
msg = user_msg
|
83
|
+
start = time.monotonic()
|
84
|
+
self._timed_out = False
|
67
85
|
for _ in range(max_steps):
|
86
|
+
if max_time is not None and time.monotonic() - start > max_time:
|
87
|
+
self.history.append({"role": "system", "content": f"[timeout after {max_time}s]"})
|
88
|
+
self._timed_out = True
|
89
|
+
break
|
90
|
+
step_start = time.monotonic()
|
68
91
|
assistant_msg = self.step(msg)
|
92
|
+
if step_timeout is not None and time.monotonic() - step_start > step_timeout:
|
93
|
+
self.history.append({"role": "system", "content": f"[timeout after {step_timeout}s]"})
|
94
|
+
self._timed_out = True
|
95
|
+
break
|
69
96
|
calls = assistant_msg.tool_calls or []
|
70
97
|
if any(c.function.name in ("stop", "continue") for c in calls):
|
71
98
|
break
|
@@ -47,6 +47,8 @@ class TaskManager:
|
|
47
47
|
parent_rt: Runtime,
|
48
48
|
files: list[str] | None = None,
|
49
49
|
parent_depth: int = 0,
|
50
|
+
step_timeout: float | None = None,
|
51
|
+
task_timeout: float | None = None,
|
50
52
|
) -> str:
|
51
53
|
"""Create a new agent and run ``prompt`` asynchronously."""
|
52
54
|
|
@@ -58,6 +60,13 @@ class TaskManager:
|
|
58
60
|
if active >= self.max_tasks:
|
59
61
|
raise RuntimeError(f"max {self.max_tasks} tasks reached")
|
60
62
|
|
63
|
+
if step_timeout is None:
|
64
|
+
env = os.getenv("PYGENT_STEP_TIMEOUT")
|
65
|
+
step_timeout = float(env) if env else 60*5 # default 5 minutes
|
66
|
+
if task_timeout is None:
|
67
|
+
env = os.getenv("PYGENT_TASK_TIMEOUT")
|
68
|
+
task_timeout = float(env) if env else 60*20 # default 20 minutes
|
69
|
+
|
61
70
|
agent = self.agent_factory()
|
62
71
|
setattr(agent.runtime, "task_depth", parent_depth + 1)
|
63
72
|
if files:
|
@@ -74,8 +83,15 @@ class TaskManager:
|
|
74
83
|
|
75
84
|
def run() -> None:
|
76
85
|
try:
|
77
|
-
agent.run_until_stop(
|
78
|
-
|
86
|
+
agent.run_until_stop(
|
87
|
+
prompt,
|
88
|
+
step_timeout=step_timeout,
|
89
|
+
max_time=task_timeout,
|
90
|
+
)
|
91
|
+
if getattr(agent, "_timed_out", False):
|
92
|
+
task.status = f"timeout after {task_timeout}s"
|
93
|
+
else:
|
94
|
+
task.status = "finished"
|
79
95
|
except Exception as exc: # pragma: no cover - error propagation
|
80
96
|
task.status = f"error: {exc}"
|
81
97
|
|
@@ -122,11 +122,19 @@ def _continue(rt: Runtime) -> str: # pragma: no cover - side-effect free
|
|
122
122
|
"items": {"type": "string"},
|
123
123
|
"description": "Files to copy to the sub-agent before starting",
|
124
124
|
},
|
125
|
+
"timeout": {"type": "number", "description": "Max seconds for the task"},
|
126
|
+
"step_timeout": {"type": "number", "description": "Time limit per step"},
|
125
127
|
},
|
126
128
|
"required": ["prompt"],
|
127
129
|
},
|
128
130
|
)
|
129
|
-
def _delegate_task(
|
131
|
+
def _delegate_task(
|
132
|
+
rt: Runtime,
|
133
|
+
prompt: str,
|
134
|
+
files: list[str] | None = None,
|
135
|
+
timeout: float | None = None,
|
136
|
+
step_timeout: float | None = None,
|
137
|
+
) -> str:
|
130
138
|
if getattr(rt, "task_depth", 0) >= 1:
|
131
139
|
return "error: delegation not allowed in sub-tasks"
|
132
140
|
try:
|
@@ -135,6 +143,8 @@ def _delegate_task(rt: Runtime, prompt: str, files: list[str] | None = None) ->
|
|
135
143
|
parent_rt=rt,
|
136
144
|
files=files,
|
137
145
|
parent_depth=getattr(rt, "task_depth", 0),
|
146
|
+
step_timeout=step_timeout,
|
147
|
+
task_timeout=timeout,
|
138
148
|
)
|
139
149
|
except RuntimeError as exc:
|
140
150
|
return str(exc)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pygent
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.14
|
4
4
|
Summary: Pygent is a minimalist coding assistant that runs commands in a Docker container when available and falls back to local execution. See https://marianochaves.github.io/pygent for documentation and https://github.com/marianochaves/pygent for the source code.
|
5
5
|
Author-email: Mariano Chaves <mchaves.software@gmail.com>
|
6
6
|
Project-URL: Documentation, https://marianochaves.github.io/pygent
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "pygent"
|
3
|
-
version = "0.1.
|
3
|
+
version = "0.1.14"
|
4
4
|
description = "Pygent is a minimalist coding assistant that runs commands in a Docker container when available and falls back to local execution. See https://marianochaves.github.io/pygent for documentation and https://github.com/marianochaves/pygent for the source code."
|
5
5
|
readme = "README.md"
|
6
6
|
authors = [ { name = "Mariano Chaves", email = "mchaves.software@gmail.com" } ]
|
@@ -184,4 +184,20 @@ def test_task_limit():
|
|
184
184
|
second = tools._delegate_task(Runtime(use_docker=False), prompt='run')
|
185
185
|
assert 'max' in second
|
186
186
|
|
187
|
-
tm.tasks[tid].thread.join()
|
187
|
+
tm.tasks[tid].thread.join()
|
188
|
+
|
189
|
+
|
190
|
+
def test_step_timeout():
|
191
|
+
ag = make_slow_agent()
|
192
|
+
ag.run_until_stop('run', step_timeout=0.05, max_steps=1)
|
193
|
+
assert 'timeout' in ag.history[-1]["content"]
|
194
|
+
|
195
|
+
|
196
|
+
def test_task_timeout():
|
197
|
+
tm = TaskManager(agent_factory=make_slow_agent, max_tasks=1)
|
198
|
+
tools._task_manager = tm
|
199
|
+
rt = Runtime(use_docker=False)
|
200
|
+
tid = tm.start_task('run', rt, task_timeout=0.05, step_timeout=0.01)
|
201
|
+
tm.tasks[tid].thread.join()
|
202
|
+
assert 'timeout' in tm.status(tid)
|
203
|
+
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|