pawnlogic 1.1__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.
- pawnlogic-1.1/LICENSE +21 -0
- pawnlogic-1.1/PKG-INFO +149 -0
- pawnlogic-1.1/README.md +115 -0
- pawnlogic-1.1/config/__init__.py +47 -0
- pawnlogic-1.1/config/paths.py +17 -0
- pawnlogic-1.1/config/phases.py +40 -0
- pawnlogic-1.1/config/providers.py +271 -0
- pawnlogic-1.1/config/sandbox.py +36 -0
- pawnlogic-1.1/config/security.py +65 -0
- pawnlogic-1.1/config/tiers.py +50 -0
- pawnlogic-1.1/core/api_client.py +842 -0
- pawnlogic-1.1/core/gsa.py +937 -0
- pawnlogic-1.1/core/logger.py +169 -0
- pawnlogic-1.1/core/mcp_client_manager.py +422 -0
- pawnlogic-1.1/core/memory.py +1056 -0
- pawnlogic-1.1/core/naming.py +216 -0
- pawnlogic-1.1/core/persistence.py +405 -0
- pawnlogic-1.1/core/provider_tui.py +1000 -0
- pawnlogic-1.1/core/session.py +2666 -0
- pawnlogic-1.1/core/skill_manager.py +385 -0
- pawnlogic-1.1/core/state.py +35 -0
- pawnlogic-1.1/core/workspace_cleanup.py +479 -0
- pawnlogic-1.1/main.py +3180 -0
- pawnlogic-1.1/pawnlogic.egg-info/PKG-INFO +149 -0
- pawnlogic-1.1/pawnlogic.egg-info/SOURCES.txt +74 -0
- pawnlogic-1.1/pawnlogic.egg-info/dependency_links.txt +1 -0
- pawnlogic-1.1/pawnlogic.egg-info/entry_points.txt +2 -0
- pawnlogic-1.1/pawnlogic.egg-info/requires.txt +10 -0
- pawnlogic-1.1/pawnlogic.egg-info/top_level.txt +6 -0
- pawnlogic-1.1/pyproject.toml +74 -0
- pawnlogic-1.1/setup.cfg +4 -0
- pawnlogic-1.1/skills/README.md +86 -0
- pawnlogic-1.1/skills/ctf_app_system/manifest.json +42 -0
- pawnlogic-1.1/skills/ctf_app_system/skill.md +2226 -0
- pawnlogic-1.1/skills/ctf_automation/manifest.json +42 -0
- pawnlogic-1.1/skills/ctf_automation/skill.md +167 -0
- pawnlogic-1.1/skills/ctf_crypto/manifest.json +42 -0
- pawnlogic-1.1/skills/ctf_crypto/skill.md +4519 -0
- pawnlogic-1.1/skills/ctf_forensics/manifest.json +42 -0
- pawnlogic-1.1/skills/ctf_forensics/skill.md +4604 -0
- pawnlogic-1.1/skills/ctf_malware/manifest.json +42 -0
- pawnlogic-1.1/skills/ctf_malware/skill.md +906 -0
- pawnlogic-1.1/skills/ctf_misc/manifest.json +42 -0
- pawnlogic-1.1/skills/ctf_misc/skill.md +3449 -0
- pawnlogic-1.1/skills/ctf_osint/manifest.json +42 -0
- pawnlogic-1.1/skills/ctf_osint/skill.md +1089 -0
- pawnlogic-1.1/skills/ctf_pwn/manifest.json +42 -0
- pawnlogic-1.1/skills/ctf_pwn/skill.md +6649 -0
- pawnlogic-1.1/skills/ctf_reverse/manifest.json +42 -0
- pawnlogic-1.1/skills/ctf_reverse/skill.md +6512 -0
- pawnlogic-1.1/skills/ctf_web/manifest.json +42 -0
- pawnlogic-1.1/skills/ctf_web/skill.md +5001 -0
- pawnlogic-1.1/skills/demo_stack_overflow/guide.md +85 -0
- pawnlogic-1.1/skills/demo_stack_overflow/manifest.json +17 -0
- pawnlogic-1.1/skills/heap_exploit/manifest.json +8 -0
- pawnlogic-1.1/skills/heap_exploit/skill.md +27 -0
- pawnlogic-1.1/skills/solve_challenge/manifest.json +42 -0
- pawnlogic-1.1/skills/solve_challenge/skill.md +152 -0
- pawnlogic-1.1/tests/test_api_empty_response.py +247 -0
- pawnlogic-1.1/tests/test_config.py +86 -0
- pawnlogic-1.1/tests/test_naming.py +147 -0
- pawnlogic-1.1/tests/test_providers.py +174 -0
- pawnlogic-1.1/tests/test_security.py +115 -0
- pawnlogic-1.1/tests/test_session_utils.py +420 -0
- pawnlogic-1.1/tools/browser_ops.py +507 -0
- pawnlogic-1.1/tools/delegate_tool.py +331 -0
- pawnlogic-1.1/tools/docker_sandbox.py +829 -0
- pawnlogic-1.1/tools/file_ops.py +871 -0
- pawnlogic-1.1/tools/lsp_lite.py +330 -0
- pawnlogic-1.1/tools/merge_ctf_skills.py +137 -0
- pawnlogic-1.1/tools/pwn_chain.py +809 -0
- pawnlogic-1.1/tools/recon_ops.py +258 -0
- pawnlogic-1.1/tools/sandbox.py +388 -0
- pawnlogic-1.1/tools/vision.py +184 -0
- pawnlogic-1.1/tools/web_ops.py +403 -0
- pawnlogic-1.1/utils/ansi.py +118 -0
pawnlogic-1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PawnLogic Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pawnlogic-1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pawnlogic
|
|
3
|
+
Version: 1.1
|
|
4
|
+
Summary: A fully autonomous terminal AI agent — multi-model routing, persistent memory, real tool execution
|
|
5
|
+
Author-email: john0123412 <junjohn05@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/john0123412/PawnLogic
|
|
8
|
+
Project-URL: Repository, https://github.com/john0123412/PawnLogic
|
|
9
|
+
Project-URL: Issues, https://github.com/john0123412/PawnLogic/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/john0123412/PawnLogic/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: ai-agent,llm,ctf,cli,autonomous,multi-model,security,pwn
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Environment :: Console
|
|
18
|
+
Classifier: Topic :: Security
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Intended Audience :: Developers
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: python-dotenv>=1.0
|
|
25
|
+
Requires-Dist: rich>=13.0
|
|
26
|
+
Requires-Dist: prompt_toolkit>=3.0
|
|
27
|
+
Requires-Dist: loguru>=0.7
|
|
28
|
+
Requires-Dist: anthropic>=0.40
|
|
29
|
+
Requires-Dist: httpx>=0.27
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# 🤖 PawnLogic
|
|
36
|
+
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
[](config/paths.py)
|
|
39
|
+
[](https://www.python.org/)
|
|
40
|
+
[]()
|
|
41
|
+
|
|
42
|
+
> **A fully autonomous terminal AI agent** — multi-model routing, persistent memory, real tool execution, and session management. Built for developers and security researchers.
|
|
43
|
+
|
|
44
|
+
## ⚡ Quick Start
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
git clone https://github.com/john0123412/PawnLogic.git && cd PawnLogic
|
|
48
|
+
python3 -m venv venv && source venv/bin/activate
|
|
49
|
+
pip install -r requirements.txt
|
|
50
|
+
python main.py # first run launches the API configuration wizard
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Global `pawn` command:
|
|
54
|
+
```bash
|
|
55
|
+
chmod +x pawn.sh && ln -sf "$(pwd)/pawn.sh" ~/.local/bin/pawn
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Key Capabilities
|
|
59
|
+
|
|
60
|
+
| Capability | Description |
|
|
61
|
+
|-----------|-------------|
|
|
62
|
+
| 🔀 **Dynamic Provider System** | Built-in DeepSeek / OpenAI / Anthropic + add any OpenAI-compatible API via `/provider` |
|
|
63
|
+
| 🧠 **Persistent Memory** | SQLite session history, RAG knowledge base, cross-session full-text search |
|
|
64
|
+
| 🛠️ **Real Tool Execution** | Shell, code sandbox (8 languages), web fetch, file ops, Docker containers |
|
|
65
|
+
| 👁️ **Vision** | Feed screenshots to `gpt-4o` or `claude-sonnet` for analysis |
|
|
66
|
+
| 📋 **Spec-Driven Planning** | Agent outputs `<plan>` XML before every action — no blind execution |
|
|
67
|
+
| 💬 **Session Management** | Tag, search, link, and export conversations with `/chat` commands |
|
|
68
|
+
| 🔐 **CTF / Pwn Toolchain** | GDB automation, ROP chain building, libc leak resolution, Docker isolation |
|
|
69
|
+
|
|
70
|
+
## Supported Models
|
|
71
|
+
|
|
72
|
+
| Provider | Aliases | Best For |
|
|
73
|
+
|----------|---------|----------|
|
|
74
|
+
| DeepSeek | `ds-v4-flash` `ds-v4-pro` | Fast default, flagship reasoning |
|
|
75
|
+
| OpenAI | `gpt-4o` `gpt-4.1` `o3` | Vision, code, complex reasoning |
|
|
76
|
+
| Anthropic | `claude-sonnet` `claude-haiku` | Balanced, fast low-cost |
|
|
77
|
+
|
|
78
|
+
Custom providers added via `/provider fetch` appear automatically in `/model` and Tab completion.
|
|
79
|
+
|
|
80
|
+
## Provider Management
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
/provider # open interactive TUI panel
|
|
84
|
+
/provider add <name> <base_url> <ENV_KEY> [anthropic]
|
|
85
|
+
/provider fetch <name> # auto-discover models with interactive multi-select
|
|
86
|
+
/provider list # show all providers and key status
|
|
87
|
+
/provider test <model> # test connectivity
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
All keys are stored in `~/.pawnlogic/.env`. Provider configs (no keys) go to `~/.pawnlogic/custom_providers.json`.
|
|
91
|
+
|
|
92
|
+
## Quick Command Reference
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
/model [alias] # switch model
|
|
96
|
+
/mode # toggle USER / DEV output mode
|
|
97
|
+
/chat find <keyword> # full-text search across all sessions
|
|
98
|
+
/think <prompt> # single deep-reasoning turn
|
|
99
|
+
/compact # summarize + clear context
|
|
100
|
+
/undo [n] # roll back last n turns
|
|
101
|
+
/deep # switch to deep mode (32k tokens, 50 iter)
|
|
102
|
+
/init_project # initialize GSD engineering pipeline
|
|
103
|
+
/pwnenv # check CTF toolchain integrity
|
|
104
|
+
/keys # show API key status for all providers
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## MCP Tool Integration
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
cp mcp_configs.example.json ~/.pawnlogic/mcp_configs.json
|
|
111
|
+
# edit mcp_configs.json, add TAVILY_API_KEY= etc. to ~/.pawnlogic/.env
|
|
112
|
+
python main.py # MCP servers load automatically
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Supported MCP servers: **Tavily** (search), **Playwright** (browser automation), **Filesystem** (file bridge).
|
|
116
|
+
|
|
117
|
+
## Data Layout
|
|
118
|
+
|
|
119
|
+
All runtime data and API keys are stored in `~/.pawnlogic/` — **never in the project directory**.
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
~/.pawnlogic/
|
|
123
|
+
├── .env # ALL API keys (LLM providers + MCP tools)
|
|
124
|
+
├── custom_providers.json # user-added provider configs (no keys)
|
|
125
|
+
├── mcp_configs.json # MCP server declarations
|
|
126
|
+
├── pawn.db # sessions, messages, knowledge base
|
|
127
|
+
├── global_skills.md # GSA skill archive
|
|
128
|
+
├── workspace/ # per-session working directories
|
|
129
|
+
└── logs/ # audit logs
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The project directory contains no secrets and is safe to commit or share.
|
|
133
|
+
|
|
134
|
+
## Documentation
|
|
135
|
+
|
|
136
|
+
| Document | Description |
|
|
137
|
+
|----------|-------------|
|
|
138
|
+
| **README.md** | This page |
|
|
139
|
+
| **README_CN.md** | 中文版 |
|
|
140
|
+
| **GUIDE_EN.md** | Full reference — commands, architecture, FAQ |
|
|
141
|
+
| **GUIDE_CN.md** | 完整参考手册 — 命令、架构、常见问题 |
|
|
142
|
+
| **CHANGELOG.md** | Version history and release notes |
|
|
143
|
+
| **CONTRIBUTING.md** | How to contribute, add providers, run tests |
|
|
144
|
+
| **SECURITY.md** | Vulnerability reporting policy |
|
|
145
|
+
|
|
146
|
+
## Support
|
|
147
|
+
|
|
148
|
+
- **GitHub**: [github.com/john0123412/PawnLogic](https://github.com/john0123412/PawnLogic)
|
|
149
|
+
- **Issues**: GitHub Issues for bugs and feature requests
|
pawnlogic-1.1/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# 🤖 PawnLogic
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](config/paths.py)
|
|
5
|
+
[](https://www.python.org/)
|
|
6
|
+
[]()
|
|
7
|
+
|
|
8
|
+
> **A fully autonomous terminal AI agent** — multi-model routing, persistent memory, real tool execution, and session management. Built for developers and security researchers.
|
|
9
|
+
|
|
10
|
+
## ⚡ Quick Start
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
git clone https://github.com/john0123412/PawnLogic.git && cd PawnLogic
|
|
14
|
+
python3 -m venv venv && source venv/bin/activate
|
|
15
|
+
pip install -r requirements.txt
|
|
16
|
+
python main.py # first run launches the API configuration wizard
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Global `pawn` command:
|
|
20
|
+
```bash
|
|
21
|
+
chmod +x pawn.sh && ln -sf "$(pwd)/pawn.sh" ~/.local/bin/pawn
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Key Capabilities
|
|
25
|
+
|
|
26
|
+
| Capability | Description |
|
|
27
|
+
|-----------|-------------|
|
|
28
|
+
| 🔀 **Dynamic Provider System** | Built-in DeepSeek / OpenAI / Anthropic + add any OpenAI-compatible API via `/provider` |
|
|
29
|
+
| 🧠 **Persistent Memory** | SQLite session history, RAG knowledge base, cross-session full-text search |
|
|
30
|
+
| 🛠️ **Real Tool Execution** | Shell, code sandbox (8 languages), web fetch, file ops, Docker containers |
|
|
31
|
+
| 👁️ **Vision** | Feed screenshots to `gpt-4o` or `claude-sonnet` for analysis |
|
|
32
|
+
| 📋 **Spec-Driven Planning** | Agent outputs `<plan>` XML before every action — no blind execution |
|
|
33
|
+
| 💬 **Session Management** | Tag, search, link, and export conversations with `/chat` commands |
|
|
34
|
+
| 🔐 **CTF / Pwn Toolchain** | GDB automation, ROP chain building, libc leak resolution, Docker isolation |
|
|
35
|
+
|
|
36
|
+
## Supported Models
|
|
37
|
+
|
|
38
|
+
| Provider | Aliases | Best For |
|
|
39
|
+
|----------|---------|----------|
|
|
40
|
+
| DeepSeek | `ds-v4-flash` `ds-v4-pro` | Fast default, flagship reasoning |
|
|
41
|
+
| OpenAI | `gpt-4o` `gpt-4.1` `o3` | Vision, code, complex reasoning |
|
|
42
|
+
| Anthropic | `claude-sonnet` `claude-haiku` | Balanced, fast low-cost |
|
|
43
|
+
|
|
44
|
+
Custom providers added via `/provider fetch` appear automatically in `/model` and Tab completion.
|
|
45
|
+
|
|
46
|
+
## Provider Management
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
/provider # open interactive TUI panel
|
|
50
|
+
/provider add <name> <base_url> <ENV_KEY> [anthropic]
|
|
51
|
+
/provider fetch <name> # auto-discover models with interactive multi-select
|
|
52
|
+
/provider list # show all providers and key status
|
|
53
|
+
/provider test <model> # test connectivity
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
All keys are stored in `~/.pawnlogic/.env`. Provider configs (no keys) go to `~/.pawnlogic/custom_providers.json`.
|
|
57
|
+
|
|
58
|
+
## Quick Command Reference
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
/model [alias] # switch model
|
|
62
|
+
/mode # toggle USER / DEV output mode
|
|
63
|
+
/chat find <keyword> # full-text search across all sessions
|
|
64
|
+
/think <prompt> # single deep-reasoning turn
|
|
65
|
+
/compact # summarize + clear context
|
|
66
|
+
/undo [n] # roll back last n turns
|
|
67
|
+
/deep # switch to deep mode (32k tokens, 50 iter)
|
|
68
|
+
/init_project # initialize GSD engineering pipeline
|
|
69
|
+
/pwnenv # check CTF toolchain integrity
|
|
70
|
+
/keys # show API key status for all providers
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## MCP Tool Integration
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cp mcp_configs.example.json ~/.pawnlogic/mcp_configs.json
|
|
77
|
+
# edit mcp_configs.json, add TAVILY_API_KEY= etc. to ~/.pawnlogic/.env
|
|
78
|
+
python main.py # MCP servers load automatically
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Supported MCP servers: **Tavily** (search), **Playwright** (browser automation), **Filesystem** (file bridge).
|
|
82
|
+
|
|
83
|
+
## Data Layout
|
|
84
|
+
|
|
85
|
+
All runtime data and API keys are stored in `~/.pawnlogic/` — **never in the project directory**.
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
~/.pawnlogic/
|
|
89
|
+
├── .env # ALL API keys (LLM providers + MCP tools)
|
|
90
|
+
├── custom_providers.json # user-added provider configs (no keys)
|
|
91
|
+
├── mcp_configs.json # MCP server declarations
|
|
92
|
+
├── pawn.db # sessions, messages, knowledge base
|
|
93
|
+
├── global_skills.md # GSA skill archive
|
|
94
|
+
├── workspace/ # per-session working directories
|
|
95
|
+
└── logs/ # audit logs
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The project directory contains no secrets and is safe to commit or share.
|
|
99
|
+
|
|
100
|
+
## Documentation
|
|
101
|
+
|
|
102
|
+
| Document | Description |
|
|
103
|
+
|----------|-------------|
|
|
104
|
+
| **README.md** | This page |
|
|
105
|
+
| **README_CN.md** | 中文版 |
|
|
106
|
+
| **GUIDE_EN.md** | Full reference — commands, architecture, FAQ |
|
|
107
|
+
| **GUIDE_CN.md** | 完整参考手册 — 命令、架构、常见问题 |
|
|
108
|
+
| **CHANGELOG.md** | Version history and release notes |
|
|
109
|
+
| **CONTRIBUTING.md** | How to contribute, add providers, run tests |
|
|
110
|
+
| **SECURITY.md** | Vulnerability reporting policy |
|
|
111
|
+
|
|
112
|
+
## Support
|
|
113
|
+
|
|
114
|
+
- **GitHub**: [github.com/john0123412/PawnLogic](https://github.com/john0123412/PawnLogic)
|
|
115
|
+
- **Issues**: GitHub Issues for bugs and feature requests
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""
|
|
2
|
+
config/__init__.py — 向后兼容入口
|
|
3
|
+
|
|
4
|
+
外部代码 `from config import X` 或 `import config; config.X` 无需任何修改。
|
|
5
|
+
"""
|
|
6
|
+
from .providers import (
|
|
7
|
+
PROVIDERS, MODELS, DEFAULT_MODEL, VISION_PRIORITY,
|
|
8
|
+
NAMING_MODEL_CHAIN, CUSTOM_PROVIDERS_PATH,
|
|
9
|
+
get_api_config, get_api_format, get_provider_config,
|
|
10
|
+
validate_api_key, list_configured_models,
|
|
11
|
+
get_best_vision_model, list_vision_models,
|
|
12
|
+
load_custom_providers, save_custom_provider, remove_custom_provider,
|
|
13
|
+
is_fast_model, find_fast_peer,
|
|
14
|
+
)
|
|
15
|
+
from .tiers import TIER_LOW, TIER_MID, TIER_DEEP, TIER_MAX
|
|
16
|
+
from .security import (
|
|
17
|
+
READ_BLACKLIST, WRITE_BLACKLIST, DANGEROUS_PATTERNS,
|
|
18
|
+
smart_truncate, user_friendly_error,
|
|
19
|
+
)
|
|
20
|
+
from .sandbox import SANDBOX_LANGS, DOCKER_IMAGES, BROWSER_CONFIG, USER_AGENTS
|
|
21
|
+
from .phases import AGENT_PHASES
|
|
22
|
+
from .paths import (
|
|
23
|
+
VERSION, SESSIONS_DIR, DB_PATH, GLOBAL_SKILLS_PATH,
|
|
24
|
+
SKILLS_DIR, LOG_DIR, WORKSPACE_DIR, WORKSPACE_ROOT,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# ── 向后兼容:DYNAMIC_CONFIG / NORMAL_CONFIG ──────────────
|
|
28
|
+
# 这两个可变 dict 由 main.py 在运行时修改(/mid /deep /low 等命令)。
|
|
29
|
+
# 保留在此处以兼容所有 `from config import DYNAMIC_CONFIG` 的调用。
|
|
30
|
+
DYNAMIC_CONFIG: dict = dict(TIER_MID)
|
|
31
|
+
NORMAL_CONFIG: dict = dict(TIER_MID)
|
|
32
|
+
|
|
33
|
+
# ── 向后兼容:WEB_STRATEGY ────────────────────────────────
|
|
34
|
+
WEB_STRATEGY = {
|
|
35
|
+
"jina_base": "https://r.jina.ai/",
|
|
36
|
+
"use_pandoc": True,
|
|
37
|
+
"timeout": 20,
|
|
38
|
+
"max_html_read": 600_000,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# ── 向后兼容:USER_MODE / QUIET_MODE ─────────────────────
|
|
42
|
+
# 这两个标志现在由 core.state 管理。
|
|
43
|
+
# 保留模块级变量以兼容 `import config; config.QUIET_MODE = True` 的写法。
|
|
44
|
+
# 注意:直接赋值此处的变量不会影响 core.state.state,
|
|
45
|
+
# 推荐新代码使用 `from core.state import state`。
|
|
46
|
+
USER_MODE: bool = False
|
|
47
|
+
QUIET_MODE: bool = False
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""config/paths.py — 路径与版本常量
|
|
2
|
+
|
|
3
|
+
版本号唯一定义处。全局通过 `from config import VERSION` 读取。
|
|
4
|
+
升级时只需修改此处。
|
|
5
|
+
"""
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
# ── 唯一版本号定义 ──────────────────────────────────────
|
|
9
|
+
VERSION = "1.1"
|
|
10
|
+
|
|
11
|
+
SESSIONS_DIR = Path.home() / ".pawnlogic" / "sessions"
|
|
12
|
+
DB_PATH = Path.home() / ".pawnlogic" / "pawn.db"
|
|
13
|
+
GLOBAL_SKILLS_PATH = Path.home() / ".pawnlogic" / "global_skills.md"
|
|
14
|
+
SKILLS_DIR = Path(__file__).resolve().parent.parent / "skills"
|
|
15
|
+
LOG_DIR = Path.home() / ".pawnlogic" / "logs"
|
|
16
|
+
WORKSPACE_DIR = str(Path.home() / ".pawnlogic" / "workspace")
|
|
17
|
+
WORKSPACE_ROOT = str(Path.home() / ".pawnlogic")
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""config/phases.py — MoE 动态工具裁剪专家路由表"""
|
|
2
|
+
|
|
3
|
+
AGENT_PHASES: dict[str, list[str]] = {
|
|
4
|
+
"RECON": [
|
|
5
|
+
"pwn_env", "list_dir", "find_files", "read_file", "inspect_binary",
|
|
6
|
+
"pwn_timed_debug",
|
|
7
|
+
"search_skills",
|
|
8
|
+
"check_service",
|
|
9
|
+
],
|
|
10
|
+
"VULN_DEV": [
|
|
11
|
+
"pwn_cyclic", "pwn_disasm", "pwn_rop", "pwn_libc", "pwn_one_gadget", "run_shell",
|
|
12
|
+
"pwn_timed_debug",
|
|
13
|
+
],
|
|
14
|
+
"EXPLOIT": [
|
|
15
|
+
"write_file", "patch_file", "run_code", "pwn_debug", "pwn_timed_debug",
|
|
16
|
+
"run_interactive", "run_shell",
|
|
17
|
+
"run_code_docker", "pwn_container",
|
|
18
|
+
"tool_install_package",
|
|
19
|
+
"docker_prune_resources",
|
|
20
|
+
],
|
|
21
|
+
"GENERAL": [
|
|
22
|
+
"read_file", "write_file", "patch_file", "run_shell", "web_search", "fetch_url",
|
|
23
|
+
"pwn_timed_debug",
|
|
24
|
+
"run_code_docker", "pwn_container",
|
|
25
|
+
"tool_install_package",
|
|
26
|
+
"docker_prune_resources",
|
|
27
|
+
"bump_skill",
|
|
28
|
+
"search_skills",
|
|
29
|
+
"check_service",
|
|
30
|
+
],
|
|
31
|
+
"WEB_PEN": [
|
|
32
|
+
"web_fetch", "web_click", "web_screenshot", "web_select", "web_type", "web_navigate",
|
|
33
|
+
"web_search", "fetch_url",
|
|
34
|
+
"read_file", "write_file",
|
|
35
|
+
"run_shell",
|
|
36
|
+
"bump_skill",
|
|
37
|
+
"search_skills",
|
|
38
|
+
"check_service",
|
|
39
|
+
],
|
|
40
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"""
|
|
2
|
+
config/providers.py — API Provider 与模型注册表
|
|
3
|
+
|
|
4
|
+
所有 API Key 通过环境变量注入,代码中无任何硬编码凭证。
|
|
5
|
+
"""
|
|
6
|
+
import os
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
PROVIDERS: dict[str, dict] = {
|
|
11
|
+
"deepseek": {
|
|
12
|
+
"base_url": "https://api.deepseek.com/v1/chat/completions",
|
|
13
|
+
"api_key_env": "DEEPSEEK_API_KEY",
|
|
14
|
+
"label": "DeepSeek",
|
|
15
|
+
"api_format": "openai",
|
|
16
|
+
},
|
|
17
|
+
"openai": {
|
|
18
|
+
"base_url": "https://api.openai.com/v1/chat/completions",
|
|
19
|
+
"api_key_env": "OPENAI_API_KEY",
|
|
20
|
+
"label": "OpenAI",
|
|
21
|
+
"api_format": "openai",
|
|
22
|
+
},
|
|
23
|
+
"anthropic": {
|
|
24
|
+
"base_url": "https://api.anthropic.com/v1/messages",
|
|
25
|
+
"api_key_env": "ANTHROPIC_API_KEY",
|
|
26
|
+
"label": "Anthropic (Claude)",
|
|
27
|
+
"api_format": "anthropic",
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
MODELS: dict[str, dict] = {
|
|
32
|
+
"ds-v4-flash": {
|
|
33
|
+
"id": "deepseek-v4-flash",
|
|
34
|
+
"provider": "deepseek",
|
|
35
|
+
"desc": "DeepSeek V4 Flash — 默认主力,快速低成本",
|
|
36
|
+
"color": "\033[32m",
|
|
37
|
+
"vision": False,
|
|
38
|
+
"reasoning": True, # 返回 reasoning_content,必须回传
|
|
39
|
+
},
|
|
40
|
+
"ds-v4-pro": {
|
|
41
|
+
"id": "deepseek-v4-pro",
|
|
42
|
+
"provider": "deepseek",
|
|
43
|
+
"desc": "DeepSeek V4 Pro — 旗舰推理",
|
|
44
|
+
"color": "\033[92m",
|
|
45
|
+
"vision": False,
|
|
46
|
+
"reasoning": True,
|
|
47
|
+
},
|
|
48
|
+
"gpt-4o": {
|
|
49
|
+
"id": "gpt-4o",
|
|
50
|
+
"provider": "openai",
|
|
51
|
+
"desc": "OpenAI GPT-4o — 视觉+多模态",
|
|
52
|
+
"color": "\033[97m",
|
|
53
|
+
"vision": True,
|
|
54
|
+
"reasoning": False,
|
|
55
|
+
},
|
|
56
|
+
"gpt-4.1": {
|
|
57
|
+
"id": "gpt-4.1",
|
|
58
|
+
"provider": "openai",
|
|
59
|
+
"desc": "OpenAI GPT-4.1 — 代码与指令跟随",
|
|
60
|
+
"color": "\033[37m",
|
|
61
|
+
"vision": False,
|
|
62
|
+
"reasoning": False,
|
|
63
|
+
},
|
|
64
|
+
"o3": {
|
|
65
|
+
"id": "o3",
|
|
66
|
+
"provider": "openai",
|
|
67
|
+
"desc": "OpenAI o3 — 复杂推理",
|
|
68
|
+
"color": "\033[96m",
|
|
69
|
+
"vision": False,
|
|
70
|
+
"reasoning": False, # OpenAI o系列推理内部化,不暴露 reasoning_content 字段
|
|
71
|
+
},
|
|
72
|
+
"claude-sonnet": {
|
|
73
|
+
"id": "claude-sonnet-4-6",
|
|
74
|
+
"provider": "anthropic",
|
|
75
|
+
"desc": "Claude Sonnet 4.6 — 均衡主力",
|
|
76
|
+
"color": "\033[95m",
|
|
77
|
+
"vision": True,
|
|
78
|
+
"reasoning": False, # Anthropic 格式走独立路径,不经过 sanitizer
|
|
79
|
+
},
|
|
80
|
+
"claude-haiku": {
|
|
81
|
+
"id": "claude-haiku-4-5-20251001",
|
|
82
|
+
"provider": "anthropic",
|
|
83
|
+
"desc": "Claude Haiku 4.5 — 快速低成本",
|
|
84
|
+
"color": "\033[35m",
|
|
85
|
+
"vision": True,
|
|
86
|
+
"reasoning": False,
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
DEFAULT_MODEL = "ds-v4-flash"
|
|
91
|
+
|
|
92
|
+
NAMING_MODEL_CHAIN: list = [
|
|
93
|
+
"claude-haiku",
|
|
94
|
+
"ds-v4-flash",
|
|
95
|
+
"gpt-4.1",
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
VISION_PRIORITY = ["gpt-4o", "claude-sonnet"]
|
|
99
|
+
|
|
100
|
+
CUSTOM_PROVIDERS_PATH = Path.home() / ".pawnlogic" / "custom_providers.json"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _normalize_url(raw: str, api_format: str = "openai") -> str:
|
|
104
|
+
"""Ensure base_url ends with the correct chat endpoint path."""
|
|
105
|
+
raw = raw.rstrip("/")
|
|
106
|
+
if raw.endswith("/chat/completions") or raw.endswith("/messages"):
|
|
107
|
+
return raw
|
|
108
|
+
suffix = "/messages" if api_format == "anthropic" else "/chat/completions"
|
|
109
|
+
if raw.endswith("/v1"):
|
|
110
|
+
return raw + suffix
|
|
111
|
+
return raw + "/v1" + suffix
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
_FAST_KEYWORDS = {"flash", "haiku", "mini", "turbo", "lite"}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def is_fast_model(model_alias: str) -> bool:
|
|
118
|
+
"""Return True if the model id contains a fast-tier keyword."""
|
|
119
|
+
mid = MODELS.get(model_alias, {}).get("id", model_alias).lower()
|
|
120
|
+
return any(k in mid for k in _FAST_KEYWORDS)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def find_fast_peer(model_alias: str) -> str | None:
|
|
124
|
+
"""
|
|
125
|
+
Given a pro-tier model alias, return the alias of a fast-tier model
|
|
126
|
+
from the same provider that has a valid API key.
|
|
127
|
+
Returns None if no fast peer is found.
|
|
128
|
+
"""
|
|
129
|
+
m = MODELS.get(model_alias)
|
|
130
|
+
if not m:
|
|
131
|
+
return None
|
|
132
|
+
provider = m.get("provider", "")
|
|
133
|
+
for alias, cfg in MODELS.items():
|
|
134
|
+
if cfg.get("provider") != provider:
|
|
135
|
+
continue
|
|
136
|
+
if not is_fast_model(alias):
|
|
137
|
+
continue
|
|
138
|
+
ok, _ = validate_api_key(alias)
|
|
139
|
+
if ok:
|
|
140
|
+
return alias
|
|
141
|
+
return None
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def get_api_config(model_alias: str) -> tuple[str, str]:
|
|
145
|
+
"""返回 (base_url, api_key)。Key 从环境变量读取,永不硬编码。"""
|
|
146
|
+
m = MODELS.get(model_alias, MODELS[DEFAULT_MODEL])
|
|
147
|
+
prov = PROVIDERS.get(m["provider"], list(PROVIDERS.values())[0])
|
|
148
|
+
key = os.getenv(prov["api_key_env"], "")
|
|
149
|
+
fmt = prov.get("api_format", "openai")
|
|
150
|
+
return _normalize_url(prov["base_url"], fmt), key
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def get_api_format(model_alias: str) -> str:
|
|
154
|
+
"""返回 'openai' 或 'anthropic'。"""
|
|
155
|
+
m = MODELS.get(model_alias, MODELS[DEFAULT_MODEL])
|
|
156
|
+
prov = PROVIDERS.get(m["provider"], {})
|
|
157
|
+
return prov.get("api_format", "openai")
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def get_provider_config(model_alias: str) -> dict:
|
|
161
|
+
"""返回完整 provider 配置字典。"""
|
|
162
|
+
m = MODELS.get(model_alias, MODELS[DEFAULT_MODEL])
|
|
163
|
+
prov = PROVIDERS.get(m["provider"], list(PROVIDERS.values())[0])
|
|
164
|
+
key = os.getenv(prov["api_key_env"], "")
|
|
165
|
+
fmt = prov.get("api_format", "openai")
|
|
166
|
+
return {
|
|
167
|
+
"base_url": _normalize_url(prov["base_url"], fmt),
|
|
168
|
+
"api_key": key,
|
|
169
|
+
"api_format": fmt,
|
|
170
|
+
"label": prov.get("label", ""),
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def validate_api_key(model_alias: str) -> tuple[bool, str]:
|
|
175
|
+
"""检查指定模型的 Key 是否已正确配置。返回 (ok, missing_env_var)。"""
|
|
176
|
+
_, key = get_api_config(model_alias)
|
|
177
|
+
if not key:
|
|
178
|
+
m = MODELS.get(model_alias, MODELS[DEFAULT_MODEL])
|
|
179
|
+
prov = PROVIDERS.get(m["provider"], {})
|
|
180
|
+
return False, prov.get("api_key_env", "")
|
|
181
|
+
return True, ""
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def list_configured_models() -> list[str]:
|
|
185
|
+
"""返回所有已配置 Key 的模型别名列表。"""
|
|
186
|
+
return [alias for alias in MODELS if validate_api_key(alias)[0]]
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def get_best_vision_model() -> tuple[str | None, str | None, str | None]:
|
|
190
|
+
"""按优先级找到第一个已配置 Key 的视觉模型。"""
|
|
191
|
+
for alias in VISION_PRIORITY:
|
|
192
|
+
m = MODELS.get(alias)
|
|
193
|
+
if not m or not m.get("vision"):
|
|
194
|
+
continue
|
|
195
|
+
url, key = get_api_config(alias)
|
|
196
|
+
if key:
|
|
197
|
+
return alias, url, key
|
|
198
|
+
return None, None, None
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def list_vision_models() -> list[str]:
|
|
202
|
+
"""返回所有标记了 vision=True 的模型别名。"""
|
|
203
|
+
return [alias for alias, m in MODELS.items() if m.get("vision")]
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def load_custom_providers() -> None:
|
|
207
|
+
"""从 custom_providers.json 加载用户自定义 provider,合并进 PROVIDERS/MODELS。"""
|
|
208
|
+
# Reload .env so keys added after startup (e.g. via wizard) are available
|
|
209
|
+
try:
|
|
210
|
+
from dotenv import load_dotenv
|
|
211
|
+
_env = Path.home() / ".pawnlogic" / ".env"
|
|
212
|
+
if _env.exists():
|
|
213
|
+
load_dotenv(_env, override=True)
|
|
214
|
+
except ImportError:
|
|
215
|
+
pass
|
|
216
|
+
if not CUSTOM_PROVIDERS_PATH.exists():
|
|
217
|
+
return
|
|
218
|
+
try:
|
|
219
|
+
data = json.loads(CUSTOM_PROVIDERS_PATH.read_text(encoding="utf-8"))
|
|
220
|
+
except Exception:
|
|
221
|
+
return
|
|
222
|
+
for name, prov in data.get("providers", {}).items():
|
|
223
|
+
if name not in PROVIDERS:
|
|
224
|
+
prov.setdefault("api_format", "openai")
|
|
225
|
+
PROVIDERS[name] = prov
|
|
226
|
+
for alias, model in data.get("models", {}).items():
|
|
227
|
+
if alias not in MODELS:
|
|
228
|
+
model.setdefault("color", "\033[37m")
|
|
229
|
+
model.setdefault("vision", False)
|
|
230
|
+
MODELS[alias] = model
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def save_custom_provider(name: str, prov_cfg: dict, models_cfg: dict) -> None:
|
|
234
|
+
"""将自定义 provider 持久化到 custom_providers.json(不含 Key)。"""
|
|
235
|
+
CUSTOM_PROVIDERS_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
236
|
+
data: dict = {"providers": {}, "models": {}}
|
|
237
|
+
if CUSTOM_PROVIDERS_PATH.exists():
|
|
238
|
+
try:
|
|
239
|
+
data = json.loads(CUSTOM_PROVIDERS_PATH.read_text(encoding="utf-8"))
|
|
240
|
+
except Exception:
|
|
241
|
+
pass
|
|
242
|
+
data["providers"][name] = prov_cfg
|
|
243
|
+
data["models"].update(models_cfg)
|
|
244
|
+
CUSTOM_PROVIDERS_PATH.write_text(
|
|
245
|
+
json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8"
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def remove_custom_provider(name: str) -> bool:
|
|
250
|
+
"""从 JSON 文件删除自定义 provider。返回是否成功。"""
|
|
251
|
+
if not CUSTOM_PROVIDERS_PATH.exists():
|
|
252
|
+
return False
|
|
253
|
+
try:
|
|
254
|
+
data = json.loads(CUSTOM_PROVIDERS_PATH.read_text(encoding="utf-8"))
|
|
255
|
+
except Exception:
|
|
256
|
+
return False
|
|
257
|
+
if name not in data.get("providers", {}):
|
|
258
|
+
return False
|
|
259
|
+
del data["providers"][name]
|
|
260
|
+
to_remove = [a for a, m in data.get("models", {}).items()
|
|
261
|
+
if m.get("provider") == name]
|
|
262
|
+
for a in to_remove:
|
|
263
|
+
del data["models"][a]
|
|
264
|
+
CUSTOM_PROVIDERS_PATH.write_text(
|
|
265
|
+
json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8"
|
|
266
|
+
)
|
|
267
|
+
return True
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
# 模块加载时自动读取自定义 provider
|
|
271
|
+
load_custom_providers()
|