autosh 0.0.0__py3-none-any.whl → 0.0.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.
- autosh/config.py +78 -0
- autosh/main.py +164 -0
- autosh/md.py +394 -0
- autosh/plugins/__init__.py +87 -0
- autosh/plugins/calc.py +22 -0
- autosh/plugins/cli.py +222 -0
- autosh/plugins/clock.py +20 -0
- autosh/plugins/code.py +68 -0
- autosh/plugins/search.py +90 -0
- autosh/plugins/web.py +73 -0
- autosh/session.py +193 -0
- autosh-0.0.1.dist-info/METADATA +77 -0
- autosh-0.0.1.dist-info/RECORD +17 -0
- {autosh-0.0.0.dist-info → autosh-0.0.1.dist-info}/WHEEL +1 -1
- autosh-0.0.1.dist-info/entry_points.txt +3 -0
- {autosh-0.0.0.dist-info → autosh-0.0.1.dist-info/licenses}/LICENSE +1 -1
- autosh-0.0.0.dist-info/METADATA +0 -16
- autosh-0.0.0.dist-info/RECORD +0 -5
- {reserved → autosh}/__init__.py +0 -0
autosh/session.py
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
import sys
|
3
|
+
from agentia import Agent
|
4
|
+
from agentia.chat_completion import MessageStream
|
5
|
+
from agentia.message import UserMessage
|
6
|
+
from agentia.plugins import PluginInitError
|
7
|
+
|
8
|
+
from autosh.config import CLI_OPTIONS, CONFIG
|
9
|
+
from autosh.md import stream_md
|
10
|
+
from .plugins import create_plugins
|
11
|
+
import rich
|
12
|
+
import platform
|
13
|
+
|
14
|
+
|
15
|
+
INSTRUCTIONS = f"""
|
16
|
+
You are now acting as a AI-powered terminal shell, operating on the user's real computer.
|
17
|
+
|
18
|
+
The user will send you questions, prompts, or descriptions of the tasks.
|
19
|
+
You should take the prompts, and either answer the user's questions, or fullfill the tasks.
|
20
|
+
When necessary, generate the system commands, and execute them to fullfill the tasks.
|
21
|
+
|
22
|
+
Don't do anything else that the user doesn't ask for, or not relevant to the tasks.
|
23
|
+
The system command output are displayed to the user directly, so don't repeat the output in your response.
|
24
|
+
Just respond with the text if you want to simply print something to the terminal, no need to use `echo` or `print`.
|
25
|
+
|
26
|
+
If the prompt mentions it requires some arguments/options/flags, look for then in the command line arguments list and use them to complete the tasks.
|
27
|
+
|
28
|
+
You may use markdown to format your responses.
|
29
|
+
|
30
|
+
YOUR HOST OS INFO: {platform.platform()}
|
31
|
+
"""
|
32
|
+
|
33
|
+
|
34
|
+
class Session:
|
35
|
+
def __init__(self):
|
36
|
+
self.agent = Agent(
|
37
|
+
model=CONFIG.model if not CLI_OPTIONS.think else CONFIG.think_model,
|
38
|
+
api_key=CONFIG.api_key,
|
39
|
+
instructions=INSTRUCTIONS,
|
40
|
+
tools=create_plugins(),
|
41
|
+
)
|
42
|
+
|
43
|
+
async def init(self):
|
44
|
+
try:
|
45
|
+
await self.agent.init()
|
46
|
+
except PluginInitError as e:
|
47
|
+
rich.print(
|
48
|
+
f"[bold red]Error:[/bold red] [red]Plugin [bold italic]{e.plugin}[/bold italic] failed to initialize: {str(e.original)}[/red]"
|
49
|
+
)
|
50
|
+
sys.exit(1)
|
51
|
+
|
52
|
+
def _exit_with_error(self, msg: str):
|
53
|
+
rich.print(f"[bold red]Error:[/bold red] [red]{msg}")
|
54
|
+
sys.exit(1)
|
55
|
+
|
56
|
+
async def _print_help_and_exit(self, prompt: str):
|
57
|
+
agent = Agent(
|
58
|
+
model="openai/gpt-4o-mini",
|
59
|
+
api_key=CONFIG.api_key,
|
60
|
+
instructions=f"""
|
61
|
+
This is a CLI program logic written in natural language.
|
62
|
+
Please help me to generate the CLI --help message for this CLI app.
|
63
|
+
Just output the help message, no need to add any other text.
|
64
|
+
|
65
|
+
RESPONSE FORMAT:
|
66
|
+
|
67
|
+
**Usage:** ...
|
68
|
+
|
69
|
+
The description of the program.
|
70
|
+
|
71
|
+
**Options:**
|
72
|
+
|
73
|
+
* -f, --foo Description of foo
|
74
|
+
* -b, --bar Description of bar
|
75
|
+
* --baz Description of baz
|
76
|
+
...
|
77
|
+
* -h, --help Show this message and exit.
|
78
|
+
""",
|
79
|
+
)
|
80
|
+
agent.history.add(self._get_argv_message())
|
81
|
+
completion = agent.chat_completion(prompt, stream=True)
|
82
|
+
async for stream in completion:
|
83
|
+
await self.__render_streamed_markdown(stream)
|
84
|
+
sys.exit(0)
|
85
|
+
|
86
|
+
def _get_argv_message(self):
|
87
|
+
args = str(CLI_OPTIONS.args)
|
88
|
+
if not CLI_OPTIONS.script:
|
89
|
+
cmd = "PROMPT"
|
90
|
+
else:
|
91
|
+
cmd = CLI_OPTIONS.script.name
|
92
|
+
return UserMessage(
|
93
|
+
content=f"PROGRAM NAME: {cmd}\n\nCOMMAND LINE ARGS: {args}",
|
94
|
+
role="user",
|
95
|
+
)
|
96
|
+
|
97
|
+
async def exec_prompt(self, prompt: str):
|
98
|
+
# Clean up the prompt
|
99
|
+
if prompt is not None:
|
100
|
+
prompt = prompt.strip()
|
101
|
+
if not prompt:
|
102
|
+
sys.exit(0)
|
103
|
+
# skip shebang line
|
104
|
+
if prompt.startswith("#!"):
|
105
|
+
prompt = prompt.split("\n", 1)[1]
|
106
|
+
if len(CLI_OPTIONS.args) == 1 and (
|
107
|
+
CLI_OPTIONS.args[0] == "-h" or CLI_OPTIONS.args[0] == "--help"
|
108
|
+
):
|
109
|
+
await self._print_help_and_exit(prompt)
|
110
|
+
# Execute the prompt
|
111
|
+
CLI_OPTIONS.prompt = prompt
|
112
|
+
self.agent.history.add(self._get_argv_message())
|
113
|
+
if CLI_OPTIONS.stdin_has_data():
|
114
|
+
self.agent.history.add(
|
115
|
+
UserMessage(
|
116
|
+
content="IMPORTANT: The user is using piped stdin to feed additional data to you. Please use tools to read when necessary.",
|
117
|
+
role="user",
|
118
|
+
)
|
119
|
+
)
|
120
|
+
completion = self.agent.chat_completion(prompt, stream=True)
|
121
|
+
async for stream in completion:
|
122
|
+
if await self.__render_streamed_markdown(stream):
|
123
|
+
print()
|
124
|
+
|
125
|
+
async def exec_from_stdin(self):
|
126
|
+
if sys.stdin.isatty():
|
127
|
+
self._exit_with_error("No prompt is piped to stdin.")
|
128
|
+
prompt = sys.stdin.read()
|
129
|
+
if not prompt:
|
130
|
+
sys.exit(0)
|
131
|
+
CLI_OPTIONS.stdin_is_script = True
|
132
|
+
await self.exec_prompt(prompt)
|
133
|
+
|
134
|
+
async def exec_script(self, script: Path):
|
135
|
+
CLI_OPTIONS.script = script
|
136
|
+
with open(script, "r") as f:
|
137
|
+
prompt = f.read()
|
138
|
+
await self.exec_prompt(prompt)
|
139
|
+
|
140
|
+
async def run_repl(self):
|
141
|
+
console = rich.console.Console()
|
142
|
+
while True:
|
143
|
+
try:
|
144
|
+
prompt = console.input("[bold]>[/bold] ").strip()
|
145
|
+
if prompt in ["exit", "quit"]:
|
146
|
+
break
|
147
|
+
if len(prompt) == 0:
|
148
|
+
continue
|
149
|
+
completion = self.agent.chat_completion(prompt, stream=True)
|
150
|
+
async for stream in completion:
|
151
|
+
if await self.__render_streamed_markdown(stream):
|
152
|
+
print()
|
153
|
+
except KeyboardInterrupt:
|
154
|
+
break
|
155
|
+
|
156
|
+
async def __render_streamed_markdown(self, stream: MessageStream):
|
157
|
+
if sys.stdout.isatty():
|
158
|
+
# buffer first few chars so we don't need to launch glow if there is no output
|
159
|
+
chunks = aiter(stream)
|
160
|
+
buf = ""
|
161
|
+
while len(buf) < 8:
|
162
|
+
try:
|
163
|
+
buf += await anext(chunks)
|
164
|
+
except StopAsyncIteration:
|
165
|
+
if len(buf) == 0:
|
166
|
+
return False
|
167
|
+
break
|
168
|
+
|
169
|
+
content = {"v": ""}
|
170
|
+
|
171
|
+
async def gen():
|
172
|
+
content["v"] = buf
|
173
|
+
if buf:
|
174
|
+
yield buf
|
175
|
+
while True:
|
176
|
+
try:
|
177
|
+
s = await anext(chunks)
|
178
|
+
content["v"] += s
|
179
|
+
for c in s:
|
180
|
+
yield c
|
181
|
+
except StopAsyncIteration:
|
182
|
+
break
|
183
|
+
|
184
|
+
await stream_md(gen())
|
185
|
+
return True
|
186
|
+
else:
|
187
|
+
has_content = False
|
188
|
+
async for chunk in stream:
|
189
|
+
if chunk == "":
|
190
|
+
continue
|
191
|
+
has_content = True
|
192
|
+
print(chunk, end="", flush=True)
|
193
|
+
return has_content
|
@@ -0,0 +1,77 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: autosh
|
3
|
+
Version: 0.0.1
|
4
|
+
Summary: Add your description here
|
5
|
+
License-File: LICENSE
|
6
|
+
Requires-Python: >=3.13
|
7
|
+
Requires-Dist: agentia>=0.0.5
|
8
|
+
Requires-Dist: asyncio>=3.4.3
|
9
|
+
Requires-Dist: markdownify>=1.1.0
|
10
|
+
Requires-Dist: pydantic>=2.11.3
|
11
|
+
Requires-Dist: python-dotenv>=1.1.0
|
12
|
+
Requires-Dist: rich>=14.0.0
|
13
|
+
Requires-Dist: tavily-python>=0.5.4
|
14
|
+
Requires-Dist: typer>=0.12.5
|
15
|
+
Requires-Dist: tzlocal>=5.3.1
|
16
|
+
Description-Content-Type: text/markdown
|
17
|
+
|
18
|
+
# `autosh` - The AI-powered, noob-friendly interactive shell
|
19
|
+
|
20
|
+
# Getting Started
|
21
|
+
|
22
|
+
## Install
|
23
|
+
|
24
|
+
```bash
|
25
|
+
uv tool install autosh
|
26
|
+
```
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
As an interactive shell: `ash` (alternatively, `autosh`)
|
31
|
+
|
32
|
+
Execute a single prompt: `ash "list current directory"`
|
33
|
+
|
34
|
+
Process piped data: `cat README.md | ash "summarise"`
|
35
|
+
|
36
|
+
## Scripting
|
37
|
+
|
38
|
+
Write AI-powered shell scripts in Markdown using natural language!
|
39
|
+
|
40
|
+
Example script ([simple.a.md](examples/simple.a.md)):
|
41
|
+
|
42
|
+
```markdown
|
43
|
+
#!/usr/bin/env ash
|
44
|
+
|
45
|
+
# This is a simple file manipulation script
|
46
|
+
|
47
|
+
First, please display a welcome message:)
|
48
|
+
|
49
|
+
Write "Hello, world" to _test.log
|
50
|
+
```
|
51
|
+
|
52
|
+
* Run the script: `ash simple.a.md` or `chmod +x simple.a.md && simple.a.md`
|
53
|
+
* Auto generate help messages:
|
54
|
+
|
55
|
+
```console
|
56
|
+
$ ash simple.a.md -h
|
57
|
+
|
58
|
+
Usage: simple.a.md [OPTIONS]
|
59
|
+
|
60
|
+
This is a simple file manipulation script that writes "Hello, world" to a log file named _x.log.
|
61
|
+
|
62
|
+
Options:
|
63
|
+
|
64
|
+
• -h, --help Show this message and exit.
|
65
|
+
```
|
66
|
+
|
67
|
+
## Plugins
|
68
|
+
|
69
|
+
`autosh` is equipped with several plugins to expand its potential:
|
70
|
+
|
71
|
+
* `ash "Create a directory "my-news", list the latest news, for each news, put the summary in a separate markdown file in this directory"`
|
72
|
+
|
73
|
+
# TODO
|
74
|
+
|
75
|
+
- [ ] Image generation
|
76
|
+
- [ ] Image input
|
77
|
+
- [ ] RAG for non-text files
|
@@ -0,0 +1,17 @@
|
|
1
|
+
autosh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
autosh/config.py,sha256=XHVICbostoBn01kyzIT5IMvqwpyJDYNYP7awOfIljfw,2141
|
3
|
+
autosh/main.py,sha256=myRolKqfHyQEgujqmUndDSm9J0C21w3zqA9-SYNX1kY,4961
|
4
|
+
autosh/md.py,sha256=306onJ24sqYXmDpr_hLaqgo9mbQuZr18vEEDOGvqemI,13729
|
5
|
+
autosh/session.py,sha256=fDPM9addcTDmCPysaqqd_z3rEseLI2tIa_dLfn3o5Uc,6800
|
6
|
+
autosh/plugins/__init__.py,sha256=yOTobuyYFpUWl5BCowGzJG8rZX2Whlagail_QyHVlo4,2487
|
7
|
+
autosh/plugins/calc.py,sha256=qo0EajIpNPv9PtLNLygyEjVaxo1F6_S62kmoJZq5oLM,581
|
8
|
+
autosh/plugins/cli.py,sha256=joMxIIcNL0y7F9k4e9c6Pu6zmOmGb0pSsR8zFMB7J_0,7366
|
9
|
+
autosh/plugins/clock.py,sha256=GGi0HAG6f6-FP1qqGoyCcUj11q_VnkaGArumsMk0CkY,542
|
10
|
+
autosh/plugins/code.py,sha256=0JwFzq6ejgbisCqBm_RG1r1WEVNou64ue-siVIpvZqs,2291
|
11
|
+
autosh/plugins/search.py,sha256=1d3Gqq6uXu0ntTBpw44Ab_haAySvZLMj3e2MQd3DHO0,2736
|
12
|
+
autosh/plugins/web.py,sha256=lmD2JnsqVI1qKgSFrk39851jCZoPyPRaVvHeEFYXylA,2597
|
13
|
+
autosh-0.0.1.dist-info/METADATA,sha256=oXsOPAcYzBj7xKTsnpJcauOJFM2CKTFZAfTIUaJf4wU,1720
|
14
|
+
autosh-0.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
15
|
+
autosh-0.0.1.dist-info/entry_points.txt,sha256=BV7bzUnxG6Z5InEkrfajGCxjooYORC5tZDDZctOPenQ,67
|
16
|
+
autosh-0.0.1.dist-info/licenses/LICENSE,sha256=BnLDJsIJe-Dm18unR9DOoSv7QOfAz6LeIQc1yHAjxp0,1066
|
17
|
+
autosh-0.0.1.dist-info/RECORD,,
|
autosh-0.0.0.dist-info/METADATA
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: autosh
|
3
|
-
Version: 0.0.0
|
4
|
-
Summary: reserved
|
5
|
-
License: MIT
|
6
|
-
Author: Wenyu Zhao
|
7
|
-
Author-email: wenyu.zhao@anu.edu.au
|
8
|
-
Requires-Python: >=3.10
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
13
|
-
Classifier: Programming Language :: Python :: 3.12
|
14
|
-
Description-Content-Type: text/markdown
|
15
|
-
|
16
|
-
reserved
|
autosh-0.0.0.dist-info/RECORD
DELETED
@@ -1,5 +0,0 @@
|
|
1
|
-
reserved/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
autosh-0.0.0.dist-info/LICENSE,sha256=XKJuERnF3YCXg9ujPMNx1yOhChxe6bBmoHnPZBl7o2I,1068
|
3
|
-
autosh-0.0.0.dist-info/METADATA,sha256=6bD3KcuY6YsLtrAKPnA6R_i0xBeaynkq-cKR0V5nppo,462
|
4
|
-
autosh-0.0.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
5
|
-
autosh-0.0.0.dist-info/RECORD,,
|
{reserved → autosh}/__init__.py
RENAMED
File without changes
|