pygent 0.1.12__py3-none-any.whl → 0.1.14__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.
- pygent/__init__.py +2 -0
- pygent/agent.py +32 -5
- pygent/runtime.py +18 -0
- pygent/task_manager.py +125 -0
- pygent/tools.py +99 -2
- pygent-0.1.14.dist-info/METADATA +132 -0
- pygent-0.1.14.dist-info/RECORD +18 -0
- pygent-0.1.12.dist-info/METADATA +0 -20
- pygent-0.1.12.dist-info/RECORD +0 -17
- {pygent-0.1.12.dist-info → pygent-0.1.14.dist-info}/WHEEL +0 -0
- {pygent-0.1.12.dist-info → pygent-0.1.14.dist-info}/entry_points.txt +0 -0
- {pygent-0.1.12.dist-info → pygent-0.1.14.dist-info}/licenses/LICENSE +0 -0
- {pygent-0.1.12.dist-info → pygent-0.1.14.dist-info}/top_level.txt +0 -0
pygent/__init__.py
CHANGED
@@ -10,6 +10,7 @@ from .agent import Agent, run_interactive # noqa: E402,F401, must come after __
|
|
10
10
|
from .models import Model, OpenAIModel # noqa: E402,F401
|
11
11
|
from .errors import PygentError, APIError # noqa: E402,F401
|
12
12
|
from .tools import register_tool, tool # noqa: E402,F401
|
13
|
+
from .task_manager import TaskManager # noqa: E402,F401
|
13
14
|
|
14
15
|
__all__ = [
|
15
16
|
"Agent",
|
@@ -20,4 +21,5 @@ __all__ = [
|
|
20
21
|
"APIError",
|
21
22
|
"register_tool",
|
22
23
|
"tool",
|
24
|
+
"TaskManager",
|
23
25
|
]
|
pygent/agent.py
CHANGED
@@ -20,10 +20,10 @@ DEFAULT_MODEL = os.getenv("PYGENT_MODEL", "gpt-4.1-mini")
|
|
20
20
|
SYSTEM_MSG = (
|
21
21
|
"You are Pygent, a sandboxed coding assistant.\n"
|
22
22
|
"Respond with JSON when you need to use a tool."
|
23
|
-
"If you need to stop, call the `stop` tool.\n"
|
23
|
+
"If you need to stop or finished you task, call the `stop` tool.\n"
|
24
24
|
"You can use the following tools:\n"
|
25
25
|
f"{json.dumps(tools.TOOL_SCHEMAS, indent=2)}\n"
|
26
|
-
"You can also use the `continue` tool to continue the conversation.\n"
|
26
|
+
"You can also use the `continue` tool to request user input or continue the conversation.\n"
|
27
27
|
)
|
28
28
|
|
29
29
|
console = Console()
|
@@ -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
|
pygent/runtime.py
CHANGED
@@ -92,6 +92,24 @@ class Runtime:
|
|
92
92
|
p.write_text(content, encoding="utf-8")
|
93
93
|
return f"Wrote {p.relative_to(self.base_dir)}"
|
94
94
|
|
95
|
+
def read_file(self, path: Union[str, Path], binary: bool = False) -> str:
|
96
|
+
"""Return the contents of a file relative to the workspace."""
|
97
|
+
|
98
|
+
p = self.base_dir / path
|
99
|
+
if not p.exists():
|
100
|
+
return f"file {p.relative_to(self.base_dir)} not found"
|
101
|
+
data = p.read_bytes()
|
102
|
+
if binary:
|
103
|
+
import base64
|
104
|
+
|
105
|
+
return base64.b64encode(data).decode()
|
106
|
+
try:
|
107
|
+
return data.decode()
|
108
|
+
except UnicodeDecodeError:
|
109
|
+
import base64
|
110
|
+
|
111
|
+
return base64.b64encode(data).decode()
|
112
|
+
|
95
113
|
def cleanup(self) -> None:
|
96
114
|
if self._use_docker and self.container is not None:
|
97
115
|
try:
|
pygent/task_manager.py
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
"""Manage background tasks executed by sub-agents."""
|
4
|
+
|
5
|
+
import os
|
6
|
+
import shutil
|
7
|
+
import threading
|
8
|
+
import uuid
|
9
|
+
from dataclasses import dataclass, field
|
10
|
+
from typing import Callable, Dict, TYPE_CHECKING
|
11
|
+
|
12
|
+
from .runtime import Runtime
|
13
|
+
|
14
|
+
if TYPE_CHECKING: # pragma: no cover - for type hints only
|
15
|
+
from .agent import Agent
|
16
|
+
|
17
|
+
|
18
|
+
@dataclass
|
19
|
+
class Task:
|
20
|
+
"""Represents a delegated task."""
|
21
|
+
|
22
|
+
id: str
|
23
|
+
agent: "Agent"
|
24
|
+
thread: threading.Thread
|
25
|
+
status: str = field(default="running")
|
26
|
+
|
27
|
+
|
28
|
+
class TaskManager:
|
29
|
+
"""Launch agents asynchronously and track their progress."""
|
30
|
+
|
31
|
+
def __init__(
|
32
|
+
self,
|
33
|
+
agent_factory: Callable[[], "Agent"] | None = None,
|
34
|
+
max_tasks: int | None = None,
|
35
|
+
) -> None:
|
36
|
+
from .agent import Agent # local import to avoid circular dependency
|
37
|
+
|
38
|
+
env_max = os.getenv("PYGENT_MAX_TASKS")
|
39
|
+
self.max_tasks = max_tasks if max_tasks is not None else int(env_max or "3")
|
40
|
+
self.agent_factory = agent_factory or Agent
|
41
|
+
self.tasks: Dict[str, Task] = {}
|
42
|
+
self._lock = threading.Lock()
|
43
|
+
|
44
|
+
def start_task(
|
45
|
+
self,
|
46
|
+
prompt: str,
|
47
|
+
parent_rt: Runtime,
|
48
|
+
files: list[str] | None = None,
|
49
|
+
parent_depth: int = 0,
|
50
|
+
step_timeout: float | None = None,
|
51
|
+
task_timeout: float | None = None,
|
52
|
+
) -> str:
|
53
|
+
"""Create a new agent and run ``prompt`` asynchronously."""
|
54
|
+
|
55
|
+
if parent_depth >= 1:
|
56
|
+
raise RuntimeError("nested delegation is not allowed")
|
57
|
+
|
58
|
+
with self._lock:
|
59
|
+
active = sum(t.status == "running" for t in self.tasks.values())
|
60
|
+
if active >= self.max_tasks:
|
61
|
+
raise RuntimeError(f"max {self.max_tasks} tasks reached")
|
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
|
+
|
70
|
+
agent = self.agent_factory()
|
71
|
+
setattr(agent.runtime, "task_depth", parent_depth + 1)
|
72
|
+
if files:
|
73
|
+
for fp in files:
|
74
|
+
src = parent_rt.base_dir / fp
|
75
|
+
dest = agent.runtime.base_dir / fp
|
76
|
+
if src.is_dir():
|
77
|
+
shutil.copytree(src, dest, dirs_exist_ok=True)
|
78
|
+
elif src.exists():
|
79
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
80
|
+
shutil.copy(src, dest)
|
81
|
+
task_id = uuid.uuid4().hex[:8]
|
82
|
+
task = Task(id=task_id, agent=agent, thread=None) # type: ignore[arg-type]
|
83
|
+
|
84
|
+
def run() -> None:
|
85
|
+
try:
|
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"
|
95
|
+
except Exception as exc: # pragma: no cover - error propagation
|
96
|
+
task.status = f"error: {exc}"
|
97
|
+
|
98
|
+
t = threading.Thread(target=run, daemon=True)
|
99
|
+
task.thread = t
|
100
|
+
with self._lock:
|
101
|
+
self.tasks[task_id] = task
|
102
|
+
t.start()
|
103
|
+
return task_id
|
104
|
+
|
105
|
+
def status(self, task_id: str) -> str:
|
106
|
+
with self._lock:
|
107
|
+
task = self.tasks.get(task_id)
|
108
|
+
if not task:
|
109
|
+
return f"Task {task_id} not found"
|
110
|
+
return task.status
|
111
|
+
|
112
|
+
def collect_file(self, rt: Runtime, task_id: str, path: str) -> str:
|
113
|
+
"""Copy a file from a task workspace into ``rt``."""
|
114
|
+
|
115
|
+
with self._lock:
|
116
|
+
task = self.tasks.get(task_id)
|
117
|
+
if not task:
|
118
|
+
return f"Task {task_id} not found"
|
119
|
+
src = task.agent.runtime.base_dir / path
|
120
|
+
if not src.exists():
|
121
|
+
return f"file {path} not found"
|
122
|
+
dest = rt.base_dir / path
|
123
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
124
|
+
shutil.copy(src, dest)
|
125
|
+
return f"Retrieved {dest.relative_to(rt.base_dir)}"
|
pygent/tools.py
CHANGED
@@ -5,6 +5,16 @@ import json
|
|
5
5
|
from typing import Any, Callable, Dict, List
|
6
6
|
|
7
7
|
from .runtime import Runtime
|
8
|
+
from .task_manager import TaskManager
|
9
|
+
|
10
|
+
_task_manager: TaskManager | None = None
|
11
|
+
|
12
|
+
|
13
|
+
def _get_manager() -> TaskManager:
|
14
|
+
global _task_manager
|
15
|
+
if _task_manager is None:
|
16
|
+
_task_manager = TaskManager()
|
17
|
+
return _task_manager
|
8
18
|
|
9
19
|
|
10
20
|
# ---- registry ----
|
@@ -82,7 +92,7 @@ def _write_file(rt: Runtime, path: str, content: str) -> str:
|
|
82
92
|
|
83
93
|
@tool(
|
84
94
|
name="stop",
|
85
|
-
description="Stop the autonomous loop.",
|
95
|
+
description="Stop the autonomous loop. This is a side-effect free tool that does not return any output. Use when finished some task or when you want to stop the agent.",
|
86
96
|
parameters={"type": "object", "properties": {}},
|
87
97
|
)
|
88
98
|
def _stop(rt: Runtime) -> str: # pragma: no cover - side-effect free
|
@@ -91,9 +101,96 @@ def _stop(rt: Runtime) -> str: # pragma: no cover - side-effect free
|
|
91
101
|
|
92
102
|
@tool(
|
93
103
|
name="continue",
|
94
|
-
description="
|
104
|
+
description="Request user answer or input. If in your previous message you asked for user input, you can use this tool to continue the conversation.",
|
95
105
|
parameters={"type": "object", "properties": {}},
|
96
106
|
)
|
97
107
|
def _continue(rt: Runtime) -> str: # pragma: no cover - side-effect free
|
98
108
|
return "Continuing the conversation."
|
99
109
|
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
@tool(
|
114
|
+
name="delegate_task",
|
115
|
+
description="Create a background task using a new agent and return its ID.",
|
116
|
+
parameters={
|
117
|
+
"type": "object",
|
118
|
+
"properties": {
|
119
|
+
"prompt": {"type": "string", "description": "Instruction for the sub-agent"},
|
120
|
+
"files": {
|
121
|
+
"type": "array",
|
122
|
+
"items": {"type": "string"},
|
123
|
+
"description": "Files to copy to the sub-agent before starting",
|
124
|
+
},
|
125
|
+
"timeout": {"type": "number", "description": "Max seconds for the task"},
|
126
|
+
"step_timeout": {"type": "number", "description": "Time limit per step"},
|
127
|
+
},
|
128
|
+
"required": ["prompt"],
|
129
|
+
},
|
130
|
+
)
|
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:
|
138
|
+
if getattr(rt, "task_depth", 0) >= 1:
|
139
|
+
return "error: delegation not allowed in sub-tasks"
|
140
|
+
try:
|
141
|
+
tid = _get_manager().start_task(
|
142
|
+
prompt,
|
143
|
+
parent_rt=rt,
|
144
|
+
files=files,
|
145
|
+
parent_depth=getattr(rt, "task_depth", 0),
|
146
|
+
step_timeout=step_timeout,
|
147
|
+
task_timeout=timeout,
|
148
|
+
)
|
149
|
+
except RuntimeError as exc:
|
150
|
+
return str(exc)
|
151
|
+
return f"started {tid}"
|
152
|
+
|
153
|
+
|
154
|
+
@tool(
|
155
|
+
name="task_status",
|
156
|
+
description="Check the status of a delegated task.",
|
157
|
+
parameters={
|
158
|
+
"type": "object",
|
159
|
+
"properties": {"task_id": {"type": "string"}},
|
160
|
+
"required": ["task_id"],
|
161
|
+
},
|
162
|
+
)
|
163
|
+
def _task_status(rt: Runtime, task_id: str) -> str:
|
164
|
+
return _get_manager().status(task_id)
|
165
|
+
|
166
|
+
|
167
|
+
@tool(
|
168
|
+
name="collect_file",
|
169
|
+
description="Retrieve a file from a delegated task into the main workspace.",
|
170
|
+
parameters={
|
171
|
+
"type": "object",
|
172
|
+
"properties": {
|
173
|
+
"task_id": {"type": "string"},
|
174
|
+
"path": {"type": "string"},
|
175
|
+
},
|
176
|
+
"required": ["task_id", "path"],
|
177
|
+
},
|
178
|
+
)
|
179
|
+
def _collect_file(rt: Runtime, task_id: str, path: str) -> str:
|
180
|
+
return _get_manager().collect_file(rt, task_id, path)
|
181
|
+
|
182
|
+
|
183
|
+
@tool(
|
184
|
+
name="download_file",
|
185
|
+
description="Return the contents of a file from the workspace (base64 if binary)",
|
186
|
+
parameters={
|
187
|
+
"type": "object",
|
188
|
+
"properties": {
|
189
|
+
"path": {"type": "string"},
|
190
|
+
"binary": {"type": "boolean", "default": False},
|
191
|
+
},
|
192
|
+
"required": ["path"],
|
193
|
+
},
|
194
|
+
)
|
195
|
+
def _download_file(rt: Runtime, path: str, binary: bool = False) -> str:
|
196
|
+
return rt.read_file(path, binary=binary)
|
@@ -0,0 +1,132 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: pygent
|
3
|
+
Version: 0.1.14
|
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
|
+
Author-email: Mariano Chaves <mchaves.software@gmail.com>
|
6
|
+
Project-URL: Documentation, https://marianochaves.github.io/pygent
|
7
|
+
Project-URL: Repository, https://github.com/marianochaves/pygent
|
8
|
+
Requires-Python: >=3.9
|
9
|
+
Description-Content-Type: text/markdown
|
10
|
+
License-File: LICENSE
|
11
|
+
Requires-Dist: rich>=13.7.0
|
12
|
+
Requires-Dist: openai>=1.0.0
|
13
|
+
Provides-Extra: test
|
14
|
+
Requires-Dist: pytest; extra == "test"
|
15
|
+
Provides-Extra: docs
|
16
|
+
Requires-Dist: mkdocs; extra == "docs"
|
17
|
+
Provides-Extra: docker
|
18
|
+
Requires-Dist: docker>=7.0.0; extra == "docker"
|
19
|
+
Provides-Extra: ui
|
20
|
+
Requires-Dist: gradio; extra == "ui"
|
21
|
+
Dynamic: license-file
|
22
|
+
|
23
|
+
# Pygent
|
24
|
+
|
25
|
+
Pygent is a coding assistant that executes each request inside an isolated Docker container whenever possible. If Docker is unavailable (for instance on some Windows setups) the commands are executed locally instead. Full documentation is available in the `docs/` directory and at [marianochaves.github.io/pygent](https://marianochaves.github.io/pygent/).
|
26
|
+
|
27
|
+
## Features
|
28
|
+
|
29
|
+
* Runs commands in ephemeral containers (default image `python:3.12-slim`).
|
30
|
+
* Integrates with OpenAI-compatible models to orchestrate each step.
|
31
|
+
* Persists the conversation history during the session.
|
32
|
+
* Provides a small Python API for use in other projects.
|
33
|
+
* Optional web interface via `pygent-ui`.
|
34
|
+
* Register your own tools and customise the system prompt.
|
35
|
+
|
36
|
+
## Installation
|
37
|
+
|
38
|
+
Installing from source is recommended:
|
39
|
+
|
40
|
+
```bash
|
41
|
+
pip install -e .
|
42
|
+
```
|
43
|
+
|
44
|
+
Python ≥ 3.9 is required. The package now bundles the `openai` client for model access.
|
45
|
+
To run commands in Docker containers also install `pygent[docker]`.
|
46
|
+
|
47
|
+
## Configuration
|
48
|
+
|
49
|
+
Behaviour can be adjusted via environment variables (see `docs/configuration.md` for a complete list):
|
50
|
+
|
51
|
+
* `OPENAI_API_KEY` – key used to access the OpenAI API.
|
52
|
+
Set this to your API key or a key from any compatible provider.
|
53
|
+
* `OPENAI_BASE_URL` – base URL for OpenAI-compatible APIs
|
54
|
+
(defaults to ``https://api.openai.com/v1``).
|
55
|
+
* `PYGENT_MODEL` – model name used for requests (default `gpt-4.1-mini`).
|
56
|
+
* `PYGENT_IMAGE` – Docker image to create the container (default `python:3.12-slim`).
|
57
|
+
* `PYGENT_USE_DOCKER` – set to `0` to disable Docker and run locally.
|
58
|
+
* `PYGENT_MAX_TASKS` – maximum number of concurrent delegated tasks (default `3`).
|
59
|
+
|
60
|
+
## CLI usage
|
61
|
+
|
62
|
+
After installing run:
|
63
|
+
|
64
|
+
```bash
|
65
|
+
pygent
|
66
|
+
```
|
67
|
+
|
68
|
+
Use `--docker` to run commands inside a container (requires
|
69
|
+
`pygent[docker]`). Use `--no-docker` or set `PYGENT_USE_DOCKER=0`
|
70
|
+
to force local execution.
|
71
|
+
|
72
|
+
Type messages normally; use `/exit` to end the session. Each command is executed
|
73
|
+
in the container and the result shown in the terminal.
|
74
|
+
Interactive programs that expect input (e.g. running `python` without a script)
|
75
|
+
are not supported and will exit immediately.
|
76
|
+
For a minimal web interface run `pygent-ui` instead (requires `pygent[ui]`).
|
77
|
+
|
78
|
+
|
79
|
+
## API usage
|
80
|
+
|
81
|
+
You can also interact directly with the Python code:
|
82
|
+
|
83
|
+
```python
|
84
|
+
from pygent import Agent
|
85
|
+
|
86
|
+
ag = Agent()
|
87
|
+
ag.step("echo 'Hello World'")
|
88
|
+
# ... more steps
|
89
|
+
ag.runtime.cleanup()
|
90
|
+
```
|
91
|
+
|
92
|
+
See the [examples](https://github.com/marianochaves/pygent/tree/main/examples) folder for more complete scripts. Models can be swapped by
|
93
|
+
passing an object implementing the ``Model`` interface when creating the
|
94
|
+
``Agent``. The default uses an OpenAI-compatible API, but custom models are
|
95
|
+
easy to plug in.
|
96
|
+
|
97
|
+
### Using OpenAI and other providers
|
98
|
+
|
99
|
+
Set your OpenAI key:
|
100
|
+
|
101
|
+
```bash
|
102
|
+
export OPENAI_API_KEY="sk-..."
|
103
|
+
```
|
104
|
+
|
105
|
+
To use a different provider, set `OPENAI_BASE_URL` to the provider
|
106
|
+
endpoint and keep `OPENAI_API_KEY` pointing to the correct key:
|
107
|
+
|
108
|
+
```bash
|
109
|
+
export OPENAI_BASE_URL="https://openrouter.ai/api/v1"
|
110
|
+
export OPENAI_API_KEY="your-provider-key"
|
111
|
+
```
|
112
|
+
|
113
|
+
## Development
|
114
|
+
|
115
|
+
1. Install the test dependencies:
|
116
|
+
|
117
|
+
```bash
|
118
|
+
pip install -e .[test]
|
119
|
+
```
|
120
|
+
|
121
|
+
2. Run the test suite:
|
122
|
+
|
123
|
+
```bash
|
124
|
+
pytest
|
125
|
+
```
|
126
|
+
|
127
|
+
Use `mkdocs serve` to build the documentation locally.
|
128
|
+
|
129
|
+
## License
|
130
|
+
|
131
|
+
This project is released under the MIT license. See the `LICENSE` file for details.
|
132
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
pygent/__init__.py,sha256=8TB-wzDeQV0YANON-q7sUkzlIyAmTN6gyz4R-axmoYU,724
|
2
|
+
pygent/__main__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
|
3
|
+
pygent/agent.py,sha256=5aY5HRlnLNwZzU_JD4bdEd9P9JLK3mtV4NJl7go9igY,4077
|
4
|
+
pygent/cli.py,sha256=Hz2FZeNMVhxoT5DjCqphXla3TisGJtPEz921LEcpxrA,527
|
5
|
+
pygent/errors.py,sha256=s5FBg_v94coSgMh7cfkP4hVXafViGYgCY8QiT698-c4,155
|
6
|
+
pygent/models.py,sha256=j3670gjUtvQRGZ5wqGDcQ7ZJVTdT5WiwL7nWTokeYzg,1141
|
7
|
+
pygent/openai_compat.py,sha256=cyWFtXt6sDfOlsZd3FuRxbcZMm3WU-DLPBQpbmcuiW8,2617
|
8
|
+
pygent/py.typed,sha256=0Wh72UpGSn4lSGW-u3xMV9kxcBHMdwE15IGUqiJTwqo,52
|
9
|
+
pygent/runtime.py,sha256=KckSdTSBIooz181ef8krXbSgqTxIaYDMdCy0ryOi7KQ,4386
|
10
|
+
pygent/task_manager.py,sha256=kQ2wwBkhPtpluPzKe9T9Hiv1NoxUA3-sEvuIiPqxq90,4167
|
11
|
+
pygent/tools.py,sha256=xHpUpG2QcBEvwTilpw8BDlYWY3KG9mItSt0FoKNkohA,5585
|
12
|
+
pygent/ui.py,sha256=xqPAvweghPOBBvoD72HzhN6zlXew_3inb8AN7Ck2zpQ,1328
|
13
|
+
pygent-0.1.14.dist-info/licenses/LICENSE,sha256=rIktBU2VR4kHzsWul64cbom2zHIgGqYmABoZwSur6T8,1071
|
14
|
+
pygent-0.1.14.dist-info/METADATA,sha256=Et3MB9nI0I9Wb9eWEAmKUrd52rS6H9TluAarCzQsiOk,4278
|
15
|
+
pygent-0.1.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
+
pygent-0.1.14.dist-info/entry_points.txt,sha256=b9j216E5UpuMrQWRZrwyEmacNEAYvw1tCKkZqdIVIOc,70
|
17
|
+
pygent-0.1.14.dist-info/top_level.txt,sha256=P26IYsb-ThK5IkGP_bRuGJQ0Q_Y8JCcbYqVpvULdxDw,7
|
18
|
+
pygent-0.1.14.dist-info/RECORD,,
|
pygent-0.1.12.dist-info/METADATA
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: pygent
|
3
|
-
Version: 0.1.12
|
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
|
-
Author-email: Mariano Chaves <mchaves.software@gmail.com>
|
6
|
-
Project-URL: Documentation, https://marianochaves.github.io/pygent
|
7
|
-
Project-URL: Repository, https://github.com/marianochaves/pygent
|
8
|
-
Requires-Python: >=3.9
|
9
|
-
License-File: LICENSE
|
10
|
-
Requires-Dist: rich>=13.7.0
|
11
|
-
Requires-Dist: openai>=1.0.0
|
12
|
-
Provides-Extra: test
|
13
|
-
Requires-Dist: pytest; extra == "test"
|
14
|
-
Provides-Extra: docs
|
15
|
-
Requires-Dist: mkdocs; extra == "docs"
|
16
|
-
Provides-Extra: docker
|
17
|
-
Requires-Dist: docker>=7.0.0; extra == "docker"
|
18
|
-
Provides-Extra: ui
|
19
|
-
Requires-Dist: gradio; extra == "ui"
|
20
|
-
Dynamic: license-file
|
pygent-0.1.12.dist-info/RECORD
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
pygent/__init__.py,sha256=L4IRxHYfzucHUjSMvYHG-1uoTe6XaYJkaHLXuGs4CI8,648
|
2
|
-
pygent/__main__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
|
3
|
-
pygent/agent.py,sha256=ZyY9dEvB6bnM1ZFLh4XKQJ68v8xpRlP3HM2RRm6Y6Q0,3030
|
4
|
-
pygent/cli.py,sha256=Hz2FZeNMVhxoT5DjCqphXla3TisGJtPEz921LEcpxrA,527
|
5
|
-
pygent/errors.py,sha256=s5FBg_v94coSgMh7cfkP4hVXafViGYgCY8QiT698-c4,155
|
6
|
-
pygent/models.py,sha256=j3670gjUtvQRGZ5wqGDcQ7ZJVTdT5WiwL7nWTokeYzg,1141
|
7
|
-
pygent/openai_compat.py,sha256=cyWFtXt6sDfOlsZd3FuRxbcZMm3WU-DLPBQpbmcuiW8,2617
|
8
|
-
pygent/py.typed,sha256=0Wh72UpGSn4lSGW-u3xMV9kxcBHMdwE15IGUqiJTwqo,52
|
9
|
-
pygent/runtime.py,sha256=xD77DPFUfmbAwsIA5SjlEmj_TimFtN3j-6h53aUVdF0,3821
|
10
|
-
pygent/tools.py,sha256=H2oice1Dyl-rw6Rq9hgWxpGSlxDD3ylCpxha8-4dkZQ,2568
|
11
|
-
pygent/ui.py,sha256=xqPAvweghPOBBvoD72HzhN6zlXew_3inb8AN7Ck2zpQ,1328
|
12
|
-
pygent-0.1.12.dist-info/licenses/LICENSE,sha256=rIktBU2VR4kHzsWul64cbom2zHIgGqYmABoZwSur6T8,1071
|
13
|
-
pygent-0.1.12.dist-info/METADATA,sha256=896zkz6xObtzwzVoM77ts8BYMgx-lNQzuUCe8YkBv74,878
|
14
|
-
pygent-0.1.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
15
|
-
pygent-0.1.12.dist-info/entry_points.txt,sha256=b9j216E5UpuMrQWRZrwyEmacNEAYvw1tCKkZqdIVIOc,70
|
16
|
-
pygent-0.1.12.dist-info/top_level.txt,sha256=P26IYsb-ThK5IkGP_bRuGJQ0Q_Y8JCcbYqVpvULdxDw,7
|
17
|
-
pygent-0.1.12.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|