agent-code 1.0.1__tar.gz → 1.0.3__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.
- {agent_code-1.0.1/src/agent_code.egg-info → agent_code-1.0.3}/PKG-INFO +1 -1
- {agent_code-1.0.1 → agent_code-1.0.3}/pyproject.toml +54 -54
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/__init__.py +2 -2
- agent_code-1.0.3/src/agent_code/data/skills/browser/skill.md +30 -0
- agent_code-1.0.3/src/agent_code/data/skills/browser/skill.py +165 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/skill_manager.py +50 -2
- {agent_code-1.0.1 → agent_code-1.0.3/src/agent_code.egg-info}/PKG-INFO +1 -1
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code.egg-info/SOURCES.txt +2 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/LICENSE +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/LICENSE-GPL +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/MANIFEST.in +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/README.md +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/setup.cfg +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/__main__.py +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/agent.py +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/cli.py +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/data/skills/filesystem/skill.md +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/data/skills/filesystem/skill.py +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/data/skills/public_api/skill.md +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/data/skills/public_api/skill.py +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/data/skills/temp_mail/skill.md +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/data/skills/temp_mail/skill.py +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/loader.py +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code/paths.py +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code.egg-info/dependency_links.txt +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code.egg-info/entry_points.txt +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code.egg-info/requires.txt +0 -0
- {agent_code-1.0.1 → agent_code-1.0.3}/src/agent_code.egg-info/top_level.txt +0 -0
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=77", "wheel"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "agent-code"
|
|
7
|
-
version = "1.0.
|
|
8
|
-
description = "Local AI agent with headless browser, sandboxed shell, and plug-and-play skills"
|
|
9
|
-
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.10"
|
|
11
|
-
license = "MIT"
|
|
12
|
-
license-files = ["LICENSE", "LICENSE-GPL"]
|
|
13
|
-
authors = [{ name = "minecraftbefile-maker" }]
|
|
14
|
-
keywords = ["ai", "agent", "llm", "browser", "automation", "skills", "openai"]
|
|
15
|
-
|
|
16
|
-
classifiers = [
|
|
17
|
-
"Development Status :: 4 - Beta",
|
|
18
|
-
"Environment :: Console",
|
|
19
|
-
"Intended Audience :: Developers",
|
|
20
|
-
"Operating System :: OS Independent",
|
|
21
|
-
"Programming Language :: Python :: 3",
|
|
22
|
-
"Programming Language :: Python :: 3.10",
|
|
23
|
-
"Programming Language :: Python :: 3.11",
|
|
24
|
-
"Programming Language :: Python :: 3.12",
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
dependencies = [
|
|
28
|
-
"DrissionPage>=4.0.0",
|
|
29
|
-
"openai>=1.0.0",
|
|
30
|
-
]
|
|
31
|
-
|
|
32
|
-
[project.optional-dependencies]
|
|
33
|
-
email = ["requests>=2.31.0"]
|
|
34
|
-
all = ["requests>=2.31.0"]
|
|
35
|
-
|
|
36
|
-
[project.urls]
|
|
37
|
-
Homepage = "https://agent-code.freesrv.com"
|
|
38
|
-
Repository = "https://github.com/Agent-code-dev/Agent-code"
|
|
39
|
-
Issues = "https://github.com/Agent-code-dev/Agent-code/issues"
|
|
40
|
-
Changelog = "https://github.com/Agent-code-dev/Agent-code/releases"
|
|
41
|
-
|
|
42
|
-
[project.scripts]
|
|
43
|
-
agent-code = "agent_code.cli:main"
|
|
44
|
-
|
|
45
|
-
[tool.setuptools]
|
|
46
|
-
package-dir = { "" = "src" }
|
|
47
|
-
|
|
48
|
-
[tool.setuptools.packages.find]
|
|
49
|
-
where = ["src"]
|
|
50
|
-
|
|
51
|
-
[tool.setuptools.package-data]
|
|
52
|
-
agent_code = [
|
|
53
|
-
"data/skills/*/*.py",
|
|
54
|
-
"data/skills/*/*.md",
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agent-code"
|
|
7
|
+
version = "1.0.3"
|
|
8
|
+
description = "Local AI agent with headless browser, sandboxed shell, and plug-and-play skills"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE", "LICENSE-GPL"]
|
|
13
|
+
authors = [{ name = "minecraftbefile-maker" }]
|
|
14
|
+
keywords = ["ai", "agent", "llm", "browser", "automation", "skills", "openai"]
|
|
15
|
+
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
dependencies = [
|
|
28
|
+
"DrissionPage>=4.0.0",
|
|
29
|
+
"openai>=1.0.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
email = ["requests>=2.31.0"]
|
|
34
|
+
all = ["requests>=2.31.0"]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://agent-code.freesrv.com"
|
|
38
|
+
Repository = "https://github.com/Agent-code-dev/Agent-code"
|
|
39
|
+
Issues = "https://github.com/Agent-code-dev/Agent-code/issues"
|
|
40
|
+
Changelog = "https://github.com/Agent-code-dev/Agent-code/releases"
|
|
41
|
+
|
|
42
|
+
[project.scripts]
|
|
43
|
+
agent-code = "agent_code.cli:main"
|
|
44
|
+
|
|
45
|
+
[tool.setuptools]
|
|
46
|
+
package-dir = { "" = "src" }
|
|
47
|
+
|
|
48
|
+
[tool.setuptools.packages.find]
|
|
49
|
+
where = ["src"]
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.package-data]
|
|
52
|
+
agent_code = [
|
|
53
|
+
"data/skills/*/*.py",
|
|
54
|
+
"data/skills/*/*.md",
|
|
55
55
|
]
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"""Agent + Skill Store — local AI agent with headless browser and skills."""
|
|
2
|
-
__version__ = "1.0.
|
|
1
|
+
"""Agent + Skill Store — local AI agent with headless browser and skills."""
|
|
2
|
+
__version__ = "1.0.2"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: browser
|
|
3
|
+
description: Headless Chromium via DrissionPage: navigate, read, click, type, scroll.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: agent-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# browser
|
|
9
|
+
|
|
10
|
+
Headless Chromium wrapped as a skill. Cookies and history survive between
|
|
11
|
+
calls in the same agent session.
|
|
12
|
+
|
|
13
|
+
## Tools
|
|
14
|
+
|
|
15
|
+
| Tool | Arguments | What it does |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `browser_navigate` | `url` | Open a URL. `https://` added if missing. |
|
|
18
|
+
| `browser_snapshot` | `max_chars` (default 6000) | Return visible body text. |
|
|
19
|
+
| `browser_click` | `selector` | Click an element by CSS selector. |
|
|
20
|
+
| `browser_type` | `selector`, `text` | Clear and type into an input. |
|
|
21
|
+
| `browser_links` | `limit` (default 30) | List anchor text and hrefs. |
|
|
22
|
+
| `browser_scroll` | `pixels` (default 800) | Scroll down. |
|
|
23
|
+
|
|
24
|
+
## Slash command
|
|
25
|
+
|
|
26
|
+
- `/browser-close` - shut down the headless Chromium process.
|
|
27
|
+
|
|
28
|
+
## Requirements
|
|
29
|
+
|
|
30
|
+
pip install DrissionPage
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Headless Chromium browser skill via DrissionPage."""
|
|
2
|
+
from DrissionPage import ChromiumPage, ChromiumOptions
|
|
3
|
+
|
|
4
|
+
_page = None
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _get_page():
|
|
8
|
+
global _page
|
|
9
|
+
if _page is None:
|
|
10
|
+
opts = (ChromiumOptions()
|
|
11
|
+
.headless(True)
|
|
12
|
+
.set_argument("--no-sandbox")
|
|
13
|
+
.set_argument("--disable-dev-shm-usage")
|
|
14
|
+
.set_argument("--disable-blink-features=AutomationControlled"))
|
|
15
|
+
_page = ChromiumPage(opts)
|
|
16
|
+
return _page
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def navigate(url):
|
|
20
|
+
if not isinstance(url, str) or not url.strip():
|
|
21
|
+
return "ERROR: url required"
|
|
22
|
+
if not url.startswith(("http://", "https://")):
|
|
23
|
+
url = "https://" + url
|
|
24
|
+
try:
|
|
25
|
+
page = _get_page()
|
|
26
|
+
page.get(url, timeout=30)
|
|
27
|
+
return "OK title={!r} url={}".format(page.title, page.url)
|
|
28
|
+
except Exception as e:
|
|
29
|
+
return "ERROR: " + str(e)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def snapshot(max_chars=6000):
|
|
33
|
+
try:
|
|
34
|
+
page = _get_page()
|
|
35
|
+
body = page.ele("tag:body", timeout=5)
|
|
36
|
+
text = body.text if body else page.html
|
|
37
|
+
return (text or "(empty)")[:int(max_chars)]
|
|
38
|
+
except Exception as e:
|
|
39
|
+
return "ERROR: " + str(e)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def click(selector):
|
|
43
|
+
try:
|
|
44
|
+
page = _get_page()
|
|
45
|
+
ele = page.ele(selector, timeout=5)
|
|
46
|
+
if not ele:
|
|
47
|
+
return "NOT_FOUND: " + str(selector)
|
|
48
|
+
ele.click()
|
|
49
|
+
return "OK"
|
|
50
|
+
except Exception as e:
|
|
51
|
+
return "ERROR: " + str(e)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def type_text(selector, text):
|
|
55
|
+
try:
|
|
56
|
+
page = _get_page()
|
|
57
|
+
ele = page.ele(selector, timeout=5)
|
|
58
|
+
if not ele:
|
|
59
|
+
return "NOT_FOUND: " + str(selector)
|
|
60
|
+
try:
|
|
61
|
+
ele.clear()
|
|
62
|
+
except Exception:
|
|
63
|
+
pass
|
|
64
|
+
ele.input(str(text))
|
|
65
|
+
return "OK"
|
|
66
|
+
except Exception as e:
|
|
67
|
+
return "ERROR: " + str(e)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def links(limit=30):
|
|
71
|
+
try:
|
|
72
|
+
page = _get_page()
|
|
73
|
+
out = []
|
|
74
|
+
for a in page.eles("tag:a")[:int(limit)]:
|
|
75
|
+
t = (a.text or "").strip()[:80]
|
|
76
|
+
h = a.attr("href") or ""
|
|
77
|
+
if t and h:
|
|
78
|
+
out.append("{} -> {}".format(t, h))
|
|
79
|
+
return "\n".join(out) or "(no links)"
|
|
80
|
+
except Exception as e:
|
|
81
|
+
return "ERROR: " + str(e)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def scroll(pixels=800):
|
|
85
|
+
try:
|
|
86
|
+
page = _get_page()
|
|
87
|
+
page.scroll.down(int(pixels))
|
|
88
|
+
return "OK scrolled {}px".format(pixels)
|
|
89
|
+
except Exception as e:
|
|
90
|
+
return "ERROR: " + str(e)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def close():
|
|
94
|
+
global _page
|
|
95
|
+
try:
|
|
96
|
+
if _page is not None:
|
|
97
|
+
_page.quit()
|
|
98
|
+
except Exception:
|
|
99
|
+
pass
|
|
100
|
+
_page = None
|
|
101
|
+
return "OK"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
SKILL = {
|
|
105
|
+
"name": "browser",
|
|
106
|
+
"description": "Headless Chromium via DrissionPage: navigate, read, click, type, scroll.",
|
|
107
|
+
"version": "1.0.0",
|
|
108
|
+
"author": "agent-code",
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
TOOL_SCHEMAS = [
|
|
112
|
+
{"type": "function", "function": {
|
|
113
|
+
"name": "browser_navigate",
|
|
114
|
+
"description": "Open a URL in the headless browser.",
|
|
115
|
+
"parameters": {"type": "object",
|
|
116
|
+
"properties": {"url": {"type": "string"}},
|
|
117
|
+
"required": ["url"]}}},
|
|
118
|
+
{"type": "function", "function": {
|
|
119
|
+
"name": "browser_snapshot",
|
|
120
|
+
"description": "Return visible text of the current page.",
|
|
121
|
+
"parameters": {"type": "object",
|
|
122
|
+
"properties": {"max_chars": {"type": "integer"}}}}},
|
|
123
|
+
{"type": "function", "function": {
|
|
124
|
+
"name": "browser_click",
|
|
125
|
+
"description": "Click an element by CSS selector.",
|
|
126
|
+
"parameters": {"type": "object",
|
|
127
|
+
"properties": {"selector": {"type": "string"}},
|
|
128
|
+
"required": ["selector"]}}},
|
|
129
|
+
{"type": "function", "function": {
|
|
130
|
+
"name": "browser_type",
|
|
131
|
+
"description": "Type text into an input identified by CSS selector.",
|
|
132
|
+
"parameters": {"type": "object",
|
|
133
|
+
"properties": {"selector": {"type": "string"},
|
|
134
|
+
"text": {"type": "string"}},
|
|
135
|
+
"required": ["selector", "text"]}}},
|
|
136
|
+
{"type": "function", "function": {
|
|
137
|
+
"name": "browser_links",
|
|
138
|
+
"description": "List clickable links on the current page.",
|
|
139
|
+
"parameters": {"type": "object",
|
|
140
|
+
"properties": {"limit": {"type": "integer"}}}}},
|
|
141
|
+
{"type": "function", "function": {
|
|
142
|
+
"name": "browser_scroll",
|
|
143
|
+
"description": "Scroll the page down by N pixels.",
|
|
144
|
+
"parameters": {"type": "object",
|
|
145
|
+
"properties": {"pixels": {"type": "integer"}}}}},
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
TOOL_CALLABLES = {
|
|
149
|
+
"browser_navigate": navigate,
|
|
150
|
+
"browser_snapshot": snapshot,
|
|
151
|
+
"browser_click": click,
|
|
152
|
+
"browser_type": type_text,
|
|
153
|
+
"browser_links": links,
|
|
154
|
+
"browser_scroll": scroll,
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _cmd_close(args, log):
|
|
159
|
+
log(close(), "dim")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
COMMANDS = {
|
|
163
|
+
"browser-close": {"handler": _cmd_close,
|
|
164
|
+
"description": "Close the headless browser."},
|
|
165
|
+
}
|
|
@@ -799,8 +799,56 @@ class SkillStore(tk.Tk):
|
|
|
799
799
|
right_frame.pack(side="right", fill="y", padx=(12, 0))
|
|
800
800
|
right_frame.pack_propagate(False)
|
|
801
801
|
|
|
802
|
-
|
|
803
|
-
|
|
802
|
+
# --- NEW SCROLLABLE SETUP ---
|
|
803
|
+
canvas = tk.Canvas(right_frame, bg=BG_CARD, highlightthickness=0)
|
|
804
|
+
scrollbar = ttk.Scrollbar(right_frame, orient="vertical", command=canvas.yview)
|
|
805
|
+
canvas.configure(yscrollcommand=scrollbar.set)
|
|
806
|
+
|
|
807
|
+
scrollbar.pack(side="right", fill="y")
|
|
808
|
+
canvas.pack(side="left", fill="both", expand=True)
|
|
809
|
+
|
|
810
|
+
# Create a frame to hold the content inside the canvas
|
|
811
|
+
detail = tk.Frame(canvas, bg=BG_CARD)
|
|
812
|
+
canvas_window = canvas.create_window((0, 0), window=detail, anchor="nw")
|
|
813
|
+
|
|
814
|
+
# Add padding to the inner frame (replaces the old padx/pady)
|
|
815
|
+
pad_frame = tk.Frame(detail, bg=BG_CARD)
|
|
816
|
+
pad_frame.pack(fill="both", expand=True, padx=18, pady=18)
|
|
817
|
+
|
|
818
|
+
# Use pad_frame instead of detail for all child widgets
|
|
819
|
+
detail = pad_frame
|
|
820
|
+
|
|
821
|
+
# Update scrollregion when the size of the inner frame changes
|
|
822
|
+
def _configure_detail(event):
|
|
823
|
+
canvas.configure(scrollregion=canvas.bbox("all"))
|
|
824
|
+
detail.bind("<Configure>", _configure_detail)
|
|
825
|
+
|
|
826
|
+
# Make the inner frame stretch to the width of the canvas
|
|
827
|
+
def _configure_canvas(event):
|
|
828
|
+
canvas.itemconfig(canvas_window, width=event.width)
|
|
829
|
+
canvas.bind("<Configure>", _configure_canvas)
|
|
830
|
+
|
|
831
|
+
# Mousewheel scrolling support (Linux, Windows, macOS)
|
|
832
|
+
def _on_mousewheel(event):
|
|
833
|
+
if event.num == 5 or event.delta < 0:
|
|
834
|
+
canvas.yview_scroll(1, "units")
|
|
835
|
+
elif event.num == 4 or event.delta > 0:
|
|
836
|
+
canvas.yview_scroll(-1, "units")
|
|
837
|
+
|
|
838
|
+
# Bind mousewheel only when hovering over the detail panel
|
|
839
|
+
def _bind_mousewheel(event):
|
|
840
|
+
canvas.bind_all("<MouseWheel>", _on_mousewheel)
|
|
841
|
+
canvas.bind_all("<Button-4>", _on_mousewheel)
|
|
842
|
+
canvas.bind_all("<Button-5>", _on_mousewheel)
|
|
843
|
+
def _unbind_mousewheel(event):
|
|
844
|
+
canvas.unbind_all("<MouseWheel>")
|
|
845
|
+
canvas.unbind_all("<Button-4>")
|
|
846
|
+
canvas.unbind_all("<Button-5>")
|
|
847
|
+
|
|
848
|
+
canvas.bind("<Enter>", _bind_mousewheel)
|
|
849
|
+
canvas.bind("<Leave>", _unbind_mousewheel)
|
|
850
|
+
# --- END SCROLLABLE SETUP ---
|
|
851
|
+
|
|
804
852
|
self._detail_frame = detail
|
|
805
853
|
|
|
806
854
|
self.d_name = tk.Label(detail, text="Select a skill",
|
|
@@ -16,6 +16,8 @@ src/agent_code.egg-info/dependency_links.txt
|
|
|
16
16
|
src/agent_code.egg-info/entry_points.txt
|
|
17
17
|
src/agent_code.egg-info/requires.txt
|
|
18
18
|
src/agent_code.egg-info/top_level.txt
|
|
19
|
+
src/agent_code/data/skills/browser/skill.md
|
|
20
|
+
src/agent_code/data/skills/browser/skill.py
|
|
19
21
|
src/agent_code/data/skills/filesystem/skill.md
|
|
20
22
|
src/agent_code/data/skills/filesystem/skill.py
|
|
21
23
|
src/agent_code/data/skills/public_api/skill.md
|
|
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
|