pygent 0.1.0__py3-none-any.whl → 0.1.1__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/agent.py +2 -2
- pygent/cli.py +8 -1
- pygent/runtime.py +60 -27
- pygent-0.1.1.dist-info/METADATA +18 -0
- pygent-0.1.1.dist-info/RECORD +12 -0
- pygent-0.1.0.dist-info/METADATA +0 -15
- pygent-0.1.0.dist-info/RECORD +0 -12
- {pygent-0.1.0.dist-info → pygent-0.1.1.dist-info}/WHEEL +0 -0
- {pygent-0.1.0.dist-info → pygent-0.1.1.dist-info}/entry_points.txt +0 -0
- {pygent-0.1.0.dist-info → pygent-0.1.1.dist-info}/licenses/LICENSE +0 -0
- {pygent-0.1.0.dist-info → pygent-0.1.1.dist-info}/top_level.txt +0 -0
pygent/agent.py
CHANGED
@@ -55,8 +55,8 @@ class Agent:
|
|
55
55
|
console.print(assistant_msg.content)
|
56
56
|
|
57
57
|
|
58
|
-
def run_interactive() -> None: # pragma: no cover
|
59
|
-
agent = Agent()
|
58
|
+
def run_interactive(use_docker: bool | None = None) -> None: # pragma: no cover
|
59
|
+
agent = Agent(runtime=Runtime(use_docker=use_docker))
|
60
60
|
console.print("[bold green]Pygent[/] iniciado. (digite /exit para sair)")
|
61
61
|
try:
|
62
62
|
while True:
|
pygent/cli.py
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
"""Ponto de entrada da CLI do Pygent."""
|
2
|
+
import argparse
|
3
|
+
|
2
4
|
from .agent import run_interactive
|
3
5
|
|
4
6
|
def main() -> None: # pragma: no cover
|
5
|
-
|
7
|
+
parser = argparse.ArgumentParser(prog="pygent")
|
8
|
+
parser.add_argument("--docker", dest="use_docker", action="store_true", help="executar em container Docker")
|
9
|
+
parser.add_argument("--no-docker", dest="use_docker", action="store_false", help="executar localmente")
|
10
|
+
parser.set_defaults(use_docker=None)
|
11
|
+
args = parser.parse_args()
|
12
|
+
run_interactive(use_docker=args.use_docker)
|
pygent/runtime.py
CHANGED
@@ -1,43 +1,75 @@
|
|
1
|
-
"""
|
1
|
+
"""Executa comandos em um container Docker, caindo para execução local se necessário."""
|
2
2
|
from __future__ import annotations
|
3
3
|
|
4
4
|
import os
|
5
5
|
import shutil
|
6
|
-
import tempfile
|
7
6
|
import subprocess
|
7
|
+
import tempfile
|
8
8
|
import uuid
|
9
9
|
from pathlib import Path
|
10
10
|
from typing import Union
|
11
11
|
|
12
|
-
|
12
|
+
try: # Docker may not be available (e.g. Windows without Docker)
|
13
|
+
import docker # type: ignore
|
14
|
+
except Exception: # pragma: no cover - optional dependency
|
15
|
+
docker = None
|
13
16
|
|
14
17
|
|
15
18
|
class Runtime:
|
16
|
-
"""
|
19
|
+
"""Executa comandos em um container Docker ou localmente se Docker faltar."""
|
17
20
|
|
18
|
-
def __init__(self, image: str | None = None) -> None:
|
21
|
+
def __init__(self, image: str | None = None, use_docker: bool | None = None) -> None:
|
19
22
|
self.base_dir = Path(tempfile.mkdtemp(prefix="pygent_"))
|
20
23
|
self.image = image or os.getenv("PYGENT_IMAGE", "python:3.12-slim")
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
24
|
+
env_opt = os.getenv("PYGENT_USE_DOCKER")
|
25
|
+
if use_docker is None:
|
26
|
+
use_docker = (env_opt != "0") if env_opt is not None else True
|
27
|
+
self._use_docker = bool(docker) and use_docker
|
28
|
+
if self._use_docker:
|
29
|
+
try:
|
30
|
+
self.client = docker.from_env()
|
31
|
+
self.container = self.client.containers.run(
|
32
|
+
self.image,
|
33
|
+
name=f"pygent-{uuid.uuid4().hex[:8]}",
|
34
|
+
command="sleep infinity",
|
35
|
+
volumes={str(self.base_dir): {"bind": "/workspace", "mode": "rw"}},
|
36
|
+
working_dir="/workspace",
|
37
|
+
detach=True,
|
38
|
+
tty=True,
|
39
|
+
network_disabled=True,
|
40
|
+
mem_limit="512m",
|
41
|
+
pids_limit=256,
|
42
|
+
)
|
43
|
+
except Exception:
|
44
|
+
self._use_docker = False
|
45
|
+
if not self._use_docker:
|
46
|
+
self.client = None
|
47
|
+
self.container = None
|
34
48
|
|
35
49
|
# ---------------- public API ----------------
|
36
50
|
def bash(self, cmd: str, timeout: int = 30) -> str:
|
37
|
-
"""Roda comando
|
38
|
-
|
39
|
-
|
40
|
-
|
51
|
+
"""Roda comando no container ou localmente e devolve a saída."""
|
52
|
+
if self._use_docker and self.container is not None:
|
53
|
+
res = self.container.exec_run(
|
54
|
+
cmd,
|
55
|
+
workdir="/workspace",
|
56
|
+
demux=True,
|
57
|
+
tty=False,
|
58
|
+
timeout=timeout,
|
59
|
+
)
|
60
|
+
stdout, stderr = (
|
61
|
+
res.output if isinstance(res.output, tuple) else (res.output, b"")
|
62
|
+
)
|
63
|
+
return (stdout or b"").decode() + (stderr or b"").decode()
|
64
|
+
proc = subprocess.run(
|
65
|
+
cmd,
|
66
|
+
shell=True,
|
67
|
+
cwd=self.base_dir,
|
68
|
+
capture_output=True,
|
69
|
+
text=True,
|
70
|
+
timeout=timeout,
|
71
|
+
)
|
72
|
+
return proc.stdout + proc.stderr
|
41
73
|
|
42
74
|
def write_file(self, rel_path: Union[str, Path], content: str) -> str:
|
43
75
|
p = self.base_dir / rel_path
|
@@ -46,8 +78,9 @@ class Runtime:
|
|
46
78
|
return f"Wrote {p.relative_to(self.base_dir)}"
|
47
79
|
|
48
80
|
def cleanup(self) -> None:
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
81
|
+
if self._use_docker and self.container is not None:
|
82
|
+
try:
|
83
|
+
self.container.kill()
|
84
|
+
finally:
|
85
|
+
self.container.remove(force=True)
|
86
|
+
shutil.rmtree(self.base_dir, ignore_errors=True)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: pygent
|
3
|
+
Version: 0.1.1
|
4
|
+
Summary: Pygent é um assistente de código minimalista que executa comandos em contêiner Docker quando disponível, com fallback para execução local. Veja https://marianochaves.github.io/pygent para a documentação e https://github.com/marianochaves/pygent para o código-fonte.
|
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: openai>=1.0.0
|
11
|
+
Requires-Dist: rich>=13.7.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
|
+
Dynamic: license-file
|
@@ -0,0 +1,12 @@
|
|
1
|
+
pygent/__init__.py,sha256=25N0WIIaSg0e3XXoDGl_OSBN2ADl-8cHm0C0EOR_opw,359
|
2
|
+
pygent/agent.py,sha256=-cQnN5X_srm_rCo33GTpHjaieJ_ogsCbRyYVuy3HGlA,2071
|
3
|
+
pygent/cli.py,sha256=P7N9nRRzJ64oMlWY_6sGytjVA1rBA37SYBiQzq4ey4I,527
|
4
|
+
pygent/py.typed,sha256=0Wh72UpGSn4lSGW-u3xMV9kxcBHMdwE15IGUqiJTwqo,52
|
5
|
+
pygent/runtime.py,sha256=1VaYyRXaRGKc6UkMpQTZJp-XIHItwp1HLZRU79-h-l8,3170
|
6
|
+
pygent/tools.py,sha256=1mXaPHFtZwT9w8thDeneH-Ryd9CjViiWOeDE1BtRF6I,1471
|
7
|
+
pygent-0.1.1.dist-info/licenses/LICENSE,sha256=rIktBU2VR4kHzsWul64cbom2zHIgGqYmABoZwSur6T8,1071
|
8
|
+
pygent-0.1.1.dist-info/METADATA,sha256=cQlQp5YpfbF3td0GAxZxyDcNNwmPZhpt-mxA6Cwn79w,839
|
9
|
+
pygent-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
10
|
+
pygent-0.1.1.dist-info/entry_points.txt,sha256=ivw-s2f1abmFsbL4173DP1IuMS7sNxQ6gZuDLdu_jKQ,43
|
11
|
+
pygent-0.1.1.dist-info/top_level.txt,sha256=P26IYsb-ThK5IkGP_bRuGJQ0Q_Y8JCcbYqVpvULdxDw,7
|
12
|
+
pygent-0.1.1.dist-info/RECORD,,
|
pygent-0.1.0.dist-info/METADATA
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: pygent
|
3
|
-
Version: 0.1.0
|
4
|
-
Summary: A minimal agentic coding assistant that runs each task in a secure container.
|
5
|
-
Author-email: Mariano Chaves <mchaves.software@gmail.com>
|
6
|
-
Requires-Python: >=3.9
|
7
|
-
License-File: LICENSE
|
8
|
-
Requires-Dist: openai>=1.0.0
|
9
|
-
Requires-Dist: docker>=7.0.0
|
10
|
-
Requires-Dist: rich>=13.7.0
|
11
|
-
Provides-Extra: test
|
12
|
-
Requires-Dist: pytest; extra == "test"
|
13
|
-
Provides-Extra: docs
|
14
|
-
Requires-Dist: mkdocs; extra == "docs"
|
15
|
-
Dynamic: license-file
|
pygent-0.1.0.dist-info/RECORD
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
pygent/__init__.py,sha256=25N0WIIaSg0e3XXoDGl_OSBN2ADl-8cHm0C0EOR_opw,359
|
2
|
-
pygent/agent.py,sha256=vOV0Zx3JzeRtJb-QRdBr-DzFIPVIt2bcZb8xeHlOxI0,2003
|
3
|
-
pygent/cli.py,sha256=qOuIHAtt--NFbPRl-RuGSK7mfFj-4CtU4rRr6KYPgKc,139
|
4
|
-
pygent/py.typed,sha256=0Wh72UpGSn4lSGW-u3xMV9kxcBHMdwE15IGUqiJTwqo,52
|
5
|
-
pygent/runtime.py,sha256=jaLhAT-2Wo6DxmPksFyHvVaCNOOu_c7BgrENsIuwTlI,1897
|
6
|
-
pygent/tools.py,sha256=1mXaPHFtZwT9w8thDeneH-Ryd9CjViiWOeDE1BtRF6I,1471
|
7
|
-
pygent-0.1.0.dist-info/licenses/LICENSE,sha256=rIktBU2VR4kHzsWul64cbom2zHIgGqYmABoZwSur6T8,1071
|
8
|
-
pygent-0.1.0.dist-info/METADATA,sha256=Rjva3PKq9hN83Piv8w7ppyNZpgzOnWOjGOYXh7BI7v4,468
|
9
|
-
pygent-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
10
|
-
pygent-0.1.0.dist-info/entry_points.txt,sha256=ivw-s2f1abmFsbL4173DP1IuMS7sNxQ6gZuDLdu_jKQ,43
|
11
|
-
pygent-0.1.0.dist-info/top_level.txt,sha256=P26IYsb-ThK5IkGP_bRuGJQ0Q_Y8JCcbYqVpvULdxDw,7
|
12
|
-
pygent-0.1.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|