supyagent 0.1.0__py3-none-any.whl → 0.2.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.
@@ -0,0 +1,217 @@
1
+ # /// script
2
+ # dependencies = ["pydantic"]
3
+ # ///
4
+ """
5
+ Shell command execution tools.
6
+
7
+ Allows agents to run bash/shell commands on the system.
8
+ Use with caution - consider restricting via agent tool permissions.
9
+ """
10
+
11
+ import os
12
+ import subprocess
13
+ import shutil
14
+ from typing import Optional
15
+
16
+ from pydantic import BaseModel, Field
17
+
18
+
19
+ class RunCommandInput(BaseModel):
20
+ """Input for run_command function."""
21
+
22
+ command: str = Field(description="The shell command to execute")
23
+ working_dir: Optional[str] = Field(
24
+ default=None, description="Working directory for the command"
25
+ )
26
+ timeout: int = Field(
27
+ default=60, description="Maximum seconds to wait for command"
28
+ )
29
+
30
+
31
+ class RunCommandOutput(BaseModel):
32
+ """Output for run_command function."""
33
+
34
+ ok: bool
35
+ stdout: str
36
+ stderr: str
37
+ exit_code: int
38
+ command: str
39
+
40
+
41
+ def run_command(input: RunCommandInput) -> RunCommandOutput:
42
+ """
43
+ Execute a shell command and return the result.
44
+
45
+ Examples:
46
+ >>> run_command({"command": "ls -la"})
47
+ >>> run_command({"command": "echo 'hello' | grep hello"})
48
+ >>> run_command({"command": "pwd", "working_dir": "/tmp"})
49
+ """
50
+ try:
51
+ working_dir = input.working_dir
52
+ if working_dir:
53
+ working_dir = os.path.expanduser(working_dir)
54
+ working_dir = os.path.expandvars(working_dir)
55
+
56
+ result = subprocess.run(
57
+ input.command,
58
+ shell=True,
59
+ capture_output=True,
60
+ text=True,
61
+ timeout=input.timeout,
62
+ cwd=working_dir,
63
+ )
64
+
65
+ return RunCommandOutput(
66
+ ok=result.returncode == 0,
67
+ stdout=result.stdout,
68
+ stderr=result.stderr,
69
+ exit_code=result.returncode,
70
+ command=input.command,
71
+ )
72
+
73
+ except subprocess.TimeoutExpired:
74
+ return RunCommandOutput(
75
+ ok=False,
76
+ stdout="",
77
+ stderr=f"Command timed out after {input.timeout} seconds",
78
+ exit_code=-1,
79
+ command=input.command,
80
+ )
81
+ except Exception as e:
82
+ return RunCommandOutput(
83
+ ok=False,
84
+ stdout="",
85
+ stderr=str(e),
86
+ exit_code=-1,
87
+ command=input.command,
88
+ )
89
+
90
+
91
+ class RunScriptInput(BaseModel):
92
+ """Input for run_script function."""
93
+
94
+ script: str = Field(description="Multi-line script content")
95
+ interpreter: str = Field(
96
+ default="/bin/bash", description="Script interpreter"
97
+ )
98
+ working_dir: Optional[str] = Field(
99
+ default=None, description="Working directory"
100
+ )
101
+ timeout: int = Field(default=120, description="Max seconds to wait")
102
+
103
+
104
+ class RunScriptOutput(BaseModel):
105
+ """Output for run_script function."""
106
+
107
+ ok: bool
108
+ stdout: str
109
+ stderr: str
110
+ exit_code: int
111
+
112
+
113
+ def run_script(input: RunScriptInput) -> RunScriptOutput:
114
+ """
115
+ Execute a multi-line shell script.
116
+
117
+ Examples:
118
+ >>> run_script({"script": "cd /tmp\\necho $(pwd)\\nls"})
119
+ """
120
+ try:
121
+ working_dir = input.working_dir
122
+ if working_dir:
123
+ working_dir = os.path.expanduser(working_dir)
124
+
125
+ result = subprocess.run(
126
+ [input.interpreter],
127
+ input=input.script,
128
+ capture_output=True,
129
+ text=True,
130
+ timeout=input.timeout,
131
+ cwd=working_dir,
132
+ )
133
+
134
+ return RunScriptOutput(
135
+ ok=result.returncode == 0,
136
+ stdout=result.stdout,
137
+ stderr=result.stderr,
138
+ exit_code=result.returncode,
139
+ )
140
+
141
+ except subprocess.TimeoutExpired:
142
+ return RunScriptOutput(
143
+ ok=False,
144
+ stdout="",
145
+ stderr=f"Script timed out after {input.timeout} seconds",
146
+ exit_code=-1,
147
+ )
148
+ except Exception as e:
149
+ return RunScriptOutput(
150
+ ok=False,
151
+ stdout="",
152
+ stderr=str(e),
153
+ exit_code=-1,
154
+ )
155
+
156
+
157
+ class WhichInput(BaseModel):
158
+ """Input for which function."""
159
+
160
+ command: str = Field(description="Command name to look up")
161
+
162
+
163
+ class WhichOutput(BaseModel):
164
+ """Output for which function."""
165
+
166
+ ok: bool
167
+ path: Optional[str] = None
168
+ error: Optional[str] = None
169
+
170
+
171
+ def which(input: WhichInput) -> WhichOutput:
172
+ """
173
+ Find the path to an executable.
174
+
175
+ Examples:
176
+ >>> which({"command": "python"})
177
+ >>> which({"command": "git"})
178
+ """
179
+ path = shutil.which(input.command)
180
+ if path:
181
+ return WhichOutput(ok=True, path=path)
182
+ else:
183
+ return WhichOutput(ok=False, error=f"Command not found: {input.command}")
184
+
185
+
186
+ class GetEnvInput(BaseModel):
187
+ """Input for get_env function."""
188
+
189
+ name: str = Field(description="Environment variable name")
190
+ default: Optional[str] = Field(
191
+ default=None, description="Default if not set"
192
+ )
193
+
194
+
195
+ class GetEnvOutput(BaseModel):
196
+ """Output for get_env function."""
197
+
198
+ ok: bool
199
+ value: Optional[str] = None
200
+ error: Optional[str] = None
201
+
202
+
203
+ def get_env(input: GetEnvInput) -> GetEnvOutput:
204
+ """
205
+ Get an environment variable value.
206
+
207
+ Examples:
208
+ >>> get_env({"name": "HOME"})
209
+ >>> get_env({"name": "MY_VAR", "default": "fallback"})
210
+ """
211
+ value = os.environ.get(input.name, input.default)
212
+ if value is not None:
213
+ return GetEnvOutput(ok=True, value=value)
214
+ else:
215
+ return GetEnvOutput(
216
+ ok=False, error=f"Environment variable not set: {input.name}"
217
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: supyagent
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: LLM agents powered by supypowers - build AI agents with tool use, multi-agent orchestration, and secure credential management
5
5
  Project-URL: Homepage, https://github.com/ergodic-ai/supyagent
6
6
  Project-URL: Documentation, https://github.com/ergodic-ai/supyagent#readme
@@ -68,6 +68,12 @@ uv pip install supyagent
68
68
  ## Quick Start
69
69
 
70
70
  ```bash
71
+ # Initialize supyagent (sets up default tools)
72
+ supyagent init
73
+
74
+ # Set up your API key (stored securely)
75
+ supyagent config set ANTHROPIC_API_KEY
76
+
71
77
  # Create your first agent
72
78
  supyagent new myagent
73
79
 
@@ -133,39 +139,40 @@ supyagent plan "Build a Python library for data validation"
133
139
  # The planner will delegate to specialist agents (coder, writer, researcher)
134
140
  ```
135
141
 
136
- ## Agent Configuration
142
+ ## Configuration
137
143
 
138
- Agents are defined in YAML files in the `agents/` directory:
144
+ ### Setting Up API Keys
139
145
 
140
- ```yaml
141
- name: researcher
142
- description: An AI research assistant
143
- type: interactive # or "execution"
146
+ Supyagent securely stores your LLM API keys so you don't need to export them every time:
144
147
 
145
- model:
146
- provider: anthropic/claude-3-5-sonnet-20241022
147
- temperature: 0.7
148
- max_tokens: 4096
148
+ ```bash
149
+ # Interactive setup (recommended)
150
+ supyagent config set
151
+ # Shows a menu of common providers to choose from
149
152
 
150
- system_prompt: |
151
- You are a helpful research assistant...
153
+ # Set a specific key
154
+ supyagent config set ANTHROPIC_API_KEY
155
+ supyagent config set OPENAI_API_KEY
152
156
 
153
- tools:
154
- allow:
155
- - "*" # Allow all tools
156
- # or be specific:
157
- # - "web:*" # All functions in web.py
158
- # - "math:calc" # Specific function
159
- deny:
160
- - "dangerous:*" # Block specific tools
157
+ # Import from a .env file
158
+ supyagent config import .env
161
159
 
162
- # For multi-agent support
163
- delegates:
164
- - coder
165
- - writer
160
+ # Import only specific keys
161
+ supyagent config import .env --filter OPENAI
162
+
163
+ # List configured keys
164
+ supyagent config list
165
+
166
+ # Export keys to backup
167
+ supyagent config export backup.env
168
+
169
+ # Delete a key
170
+ supyagent config delete OPENAI_API_KEY
166
171
  ```
167
172
 
168
- ### LLM Providers
173
+ Keys are encrypted and stored in `~/.supyagent/config/`. They're automatically loaded when running any agent command.
174
+
175
+ ### Supported Providers
169
176
 
170
177
  Supyagent uses LiteLLM, supporting 100+ providers:
171
178
 
@@ -187,11 +194,36 @@ model:
187
194
  provider: gemini/gemini-pro
188
195
  ```
189
196
 
190
- Set API keys as environment variables:
197
+ ## Agent Configuration
191
198
 
192
- ```bash
193
- export OPENAI_API_KEY=sk-...
194
- export ANTHROPIC_API_KEY=sk-ant-...
199
+ Agents are defined in YAML files in the `agents/` directory:
200
+
201
+ ```yaml
202
+ name: researcher
203
+ description: An AI research assistant
204
+ type: interactive # or "execution"
205
+
206
+ model:
207
+ provider: anthropic/claude-3-5-sonnet-20241022
208
+ temperature: 0.7
209
+ max_tokens: 4096
210
+
211
+ system_prompt: |
212
+ You are a helpful research assistant...
213
+
214
+ tools:
215
+ allow:
216
+ - "*" # Allow all tools
217
+ # or be specific:
218
+ # - "web:*" # All functions in web.py
219
+ # - "math:calc" # Specific function
220
+ deny:
221
+ - "dangerous:*" # Block specific tools
222
+
223
+ # For multi-agent support
224
+ delegates:
225
+ - coder
226
+ - writer
195
227
  ```
196
228
 
197
229
  ## CLI Reference
@@ -200,6 +232,7 @@ export ANTHROPIC_API_KEY=sk-ant-...
200
232
 
201
233
  | Command | Description |
202
234
  |---------|-------------|
235
+ | `supyagent init` | Initialize project with default tools |
203
236
  | `supyagent new <name>` | Create a new agent |
204
237
  | `supyagent list` | List all agents |
205
238
  | `supyagent show <name>` | Show agent details |
@@ -223,6 +256,16 @@ export ANTHROPIC_API_KEY=sk-ant-...
223
256
  | `supyagent agents` | List active agent instances |
224
257
  | `supyagent cleanup` | Remove completed instances |
225
258
 
259
+ ### Config Commands
260
+
261
+ | Command | Description |
262
+ |---------|-------------|
263
+ | `supyagent config set [KEY]` | Set an API key (interactive menu if no key specified) |
264
+ | `supyagent config list` | List all configured keys |
265
+ | `supyagent config import <file>` | Import keys from .env file |
266
+ | `supyagent config export <file>` | Export keys to .env file |
267
+ | `supyagent config delete <key>` | Delete a stored key |
268
+
226
269
  ### In-Chat Commands
227
270
 
228
271
  While chatting, use these commands:
@@ -242,6 +285,25 @@ While chatting, use these commands:
242
285
  | `/clear` | Clear conversation history |
243
286
  | `/quit` | Exit the chat |
244
287
 
288
+ ## Bundled Tools
289
+
290
+ Running `supyagent init` installs these default tools:
291
+
292
+ ### Shell (`shell.py`)
293
+ - `run_command` - Execute shell commands
294
+ - `run_script` - Run multi-line bash scripts
295
+ - `which` - Find executable paths
296
+ - `get_env` - Get environment variables
297
+
298
+ ### Files (`files.py`)
299
+ - `read_file` / `write_file` - File I/O
300
+ - `list_directory` - List files with glob patterns
301
+ - `copy_file` / `move_file` / `delete_file` - File operations
302
+ - `create_directory` - Create directories
303
+ - `file_info` - Get file metadata
304
+
305
+ You can add your own tools by creating Python files in `supypowers/`.
306
+
245
307
  ## Project Structure
246
308
 
247
309
  ```
@@ -251,8 +313,9 @@ your-project/
251
313
  │ ├── planner.yaml
252
314
  │ └── researcher.yaml
253
315
  ├── supypowers/ # Tool definitions (Python)
254
- │ ├── hello.py
255
- └── web_search.py
316
+ │ ├── shell.py # Shell commands (bundled)
317
+ ├── files.py # File operations (bundled)
318
+ │ └── my_tools.py # Your custom tools
256
319
  └── .supyagent/ # Runtime data (gitignore this)
257
320
  ├── sessions/ # Conversation history
258
321
  ├── credentials/ # Encrypted secrets
@@ -1,9 +1,10 @@
1
1
  supyagent/__init__.py,sha256=JrrQbk1bmDhUb2qOqxqDGBq1V-oArwVS4f5f9Qu-VcM,77
2
2
  supyagent/__main__.py,sha256=szUvsccEIA428c2_5J_X1qzq4L44qLvDvHfuRPYoy7c,121
3
3
  supyagent/cli/__init__.py,sha256=7jb5kxHtzce4rNKd9zrAiATp3Zxj7UQvtpQsyA97BTc,32
4
- supyagent/cli/main.py,sha256=5oM_IZ85C3gyW_ypPmFi3x-khkgd7tZrbowW_kJ_JhY,31028
5
- supyagent/core/__init__.py,sha256=5GOA6Ca5UBWG_d6lhfZxYdKdDjnKE4UdVooe0lUDpe0,626
4
+ supyagent/cli/main.py,sha256=6jXcEZjLRgE_9PnPvyg-6BWGg5_yB71xZOD8_cejSno,38515
5
+ supyagent/core/__init__.py,sha256=7MI6K2-OR_Fg0wcMziC4u3gNa0YxWmzJXO0RtOCevUg,727
6
6
  supyagent/core/agent.py,sha256=mkiV6CnK6Vk0Wg-DiAMm29wAViMa52-1Yb33Y5-FvQY,12655
7
+ supyagent/core/config.py,sha256=kuTpuxy-qr-fhou7rJ-JLF82cdzdHQTu46kCZccSw1Y,10041
7
8
  supyagent/core/context.py,sha256=ywen6IjWxcudxtipeqA_PHpZKdjK52eqOb9xy7QKnTM,4565
8
9
  supyagent/core/credentials.py,sha256=35JBrzMOEDzHnn3XuyGmRjXVdSICL3tups3BLO_NCXQ,7600
9
10
  supyagent/core/delegation.py,sha256=B6OYlLjkZaRTPMQsK9nIGeXVO9JeC7RDpxXsOk652xs,9391
@@ -12,13 +13,16 @@ supyagent/core/llm.py,sha256=z16cjqjPfwRGtEpUhZe1XlzOXJdlgKHjckNdeJnEWYw,1898
12
13
  supyagent/core/registry.py,sha256=1CGCPsOcrIc_63_oJaFmHY8WwMgJEvbwsv8mnsOBWtY,7326
13
14
  supyagent/core/session_manager.py,sha256=ngqrbofR8V0wZSuOfGHTtSYE0C9U6noDrzfDsO8wi24,7389
14
15
  supyagent/core/tools.py,sha256=exIynhwulsMJTzzW5NmDqBeXepULAt4FlVhGbtrvdXE,6627
16
+ supyagent/default_tools/__init__.py,sha256=VwVjwNSPxjflmzJ-Mv_7L79Yjn9LdxyeXNUkWzu3wFo,1890
17
+ supyagent/default_tools/files.py,sha256=tUpjkP7TKbcK75lQ6jzEDpVDBSeupzTSqx_g2-rkON0,12059
18
+ supyagent/default_tools/shell.py,sha256=fYXdy693Nb0hsNLMzTFgj3zaHq0wFSQ3SxpqHbVayjM,5478
15
19
  supyagent/models/__init__.py,sha256=y7fIdzh-yD0LKAK0zfY_MZdtjJhxofwRWBqrHDU93h0,259
16
20
  supyagent/models/agent_config.py,sha256=sQ7S7zExoFs0g-IMgACsGH2SMiDRjJTnCVZwhN6DnkY,2570
17
21
  supyagent/models/session.py,sha256=_Dwuija_Uvt_KzcNp82ja8qP5ltNHHz43Llug1vq1ic,1136
18
22
  supyagent/utils/__init__.py,sha256=l4HdE3n8axphMInBex1J1dB_O1MjzbZz6ot1l8Syf0g,39
19
23
  supyagent/utils/paths.py,sha256=Xum9kX_UjRvmshifSq423QsAKynpnyAVfpWuFjlsdDQ,692
20
- supyagent-0.1.0.dist-info/METADATA,sha256=ooG14oWAy-YelwL-QC3DDZL8aFhDzM6Gs9mdjFW3xw4,8430
21
- supyagent-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
22
- supyagent-0.1.0.dist-info/entry_points.txt,sha256=7dFXWtRewhLfA5XUckV7Yu1E5_c6c9lq8Gz-7BFs6TM,53
23
- supyagent-0.1.0.dist-info/licenses/LICENSE,sha256=35fw1cvTM-IhiR3xaUohbiFBc2OBNRjI5z1b1cF7vZI,1067
24
- supyagent-0.1.0.dist-info/RECORD,,
24
+ supyagent-0.2.1.dist-info/METADATA,sha256=5sn1RwCPZ0Ja2ZGLatdfHlgg7KZnCr3v0u7zywAgpSs,10387
25
+ supyagent-0.2.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
26
+ supyagent-0.2.1.dist-info/entry_points.txt,sha256=7dFXWtRewhLfA5XUckV7Yu1E5_c6c9lq8Gz-7BFs6TM,53
27
+ supyagent-0.2.1.dist-info/licenses/LICENSE,sha256=35fw1cvTM-IhiR3xaUohbiFBc2OBNRjI5z1b1cF7vZI,1067
28
+ supyagent-0.2.1.dist-info/RECORD,,