├── wut
├── __init__.py
├── __main__.py
├── prompts.py
├── wut.py
└── utils.py
├── demo.gif
├── Pipfile
├── LICENSE
├── setup.py
├── README.md
├── .gitignore
└── Pipfile.lock
/wut/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shobrook/wut/HEAD/demo.gif
--------------------------------------------------------------------------------
/wut/__main__.py:
--------------------------------------------------------------------------------
1 | # Local
2 | from wut import main
3 |
4 | if __name__ == "__main__":
5 | main()
6 |
--------------------------------------------------------------------------------
/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | url = "https://pypi.org/simple"
3 | verify_ssl = true
4 | name = "pypi"
5 |
6 | [packages]
7 | psutil = "*"
8 | tiktoken = "*"
9 | openai = "*"
10 | rich = "*"
11 | anthropic = "*"
12 | ollama = "*"
13 |
14 | [dev-packages]
15 |
16 | [requires]
17 | python_version = "3.13"
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Jonathan Shobrook
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.
22 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | try:
4 | from setuptools import setup, find_packages
5 | except ImportError:
6 | from distutils.core import setup
7 |
8 | if sys.version_info[:3] < (3, 0, 0):
9 | print("Requires Python 3 to run.")
10 | sys.exit(1)
11 |
12 | setup(
13 | name="wut-cli",
14 | version="1.0.8",
15 | description="CLI that explains the output of your last command",
16 | url="https://github.com/shobrook/wut",
17 | author="shobrook",
18 | author_email="shobrookj@gmail.com",
19 | classifiers=[
20 | "Environment :: Console",
21 | "Intended Audience :: Developers",
22 | "Topic :: Software Development",
23 | "Topic :: Software Development :: Debuggers",
24 | "Natural Language :: English",
25 | "License :: OSI Approved :: MIT License",
26 | "Programming Language :: Python",
27 | ],
28 | keywords="openai claude cli commandline error stack-trace explain assistant terminal",
29 | include_package_data=True,
30 | packages=find_packages(),
31 | entry_points={"console_scripts": ["wut = wut.wut:main"]},
32 | install_requires=["openai", "anthropic", "ollama", "rich", "psutil"],
33 | requires=["openai", "anthropic", "ollama", "rich", "psutil"],
34 | python_requires=">=3",
35 | license="MIT",
36 | )
37 |
--------------------------------------------------------------------------------
/wut/prompts.py:
--------------------------------------------------------------------------------
1 | EXPLAIN_PROMPT = """
2 | You are a command-line assistant whose job is to explain the output of the most recently executed command in the terminal.
3 | Your goal is to help users understand (and potentially fix) things like stack traces, error messages, logs, or any other confusing output from the terminal.
4 |
5 |
6 |
7 | - Receive the last command in the terminal history and the previous commands before it as context.
8 | - Explain the output of the last command.
9 | - Use a clear, concise, and informative tone.
10 | - If the output is an error or warning, e.g. a stack trace or incorrect command, identify the root cause and suggest a fix.
11 | - Otherwise, if the output is something else, e.g. logs or a web response, summarize the key points.
12 |
13 |
14 |
15 | - Use Markdown to format your response.
16 | - Commands (both single and multi-line) should be placed in fenced markdown blocks.
17 | - Code snippets should be placed in fenced markdown blocks.
18 | - Only use bold for warnings or key takeaways.
19 | - Break down your response into digestible parts.
20 | - Keep your response as short as possible. No more than 5 sentences, unless the issue is complex.
21 | """
22 |
23 | ANSWER_PROMPT = """
24 | You are a command-line assistant whose job is to answer the user's question about the most recently executed command in the terminal.
25 |
26 |
27 |
28 | - Receive the last command in the terminal history and the previous commands before it as context.
29 | - Use a clear, concise, and informative tone.
30 |
31 |
32 |
33 | - Use Markdown to format your response.
34 | - Commands (both single and multi-line) should be placed in fenced markdown blocks.
35 | - Code snippets should be placed in fenced markdown blocks.
36 | - Only use bold for warnings or key takeaways.
37 | - Break down your response into digestible parts.
38 | - Keep your response as short as possible. No more than 5 sentences, unless the issue is complex.
39 | """
40 |
--------------------------------------------------------------------------------
/wut/wut.py:
--------------------------------------------------------------------------------
1 | # Standard library
2 | import os
3 | import argparse
4 |
5 | # Third party
6 | from rich.console import Console
7 |
8 | # Local
9 | from wut.utils import (
10 | get_shell,
11 | get_terminal_context,
12 | explain,
13 | )
14 |
15 | # from utils import (
16 | # get_shell,
17 | # get_terminal_context,
18 | # explain,
19 | # )
20 |
21 |
22 | def main():
23 | parser = argparse.ArgumentParser(
24 | description="Understand the output of your latest terminal command."
25 | )
26 | parser.add_argument(
27 | "--query",
28 | type=str,
29 | required=False,
30 | default="",
31 | help="A specific question about what's on your terminal.",
32 | )
33 | parser.add_argument(
34 | "--debug",
35 | action="store_true",
36 | help="Print debug information.",
37 | )
38 | args = parser.parse_args()
39 | console = Console()
40 | debug = lambda text: console.print(f"wut | {text}") if args.debug else None
41 |
42 | with console.status("[bold green]Trying my best..."):
43 | # Ensure environment is set up correctly
44 | if not os.environ.get("TMUX") and not os.environ.get("STY"):
45 | console.print(
46 | "[bold red]wut must be run inside a tmux or screen session.[/bold red]"
47 | )
48 | return
49 | if (
50 | not os.environ.get("OPENAI_API_KEY", None)
51 | and not os.environ.get("ANTHROPIC_API_KEY", None)
52 | and not os.environ.get("OLLAMA_MODEL", None)
53 | ):
54 | console.print(
55 | "[bold red]Please set your OpenAI or Anthropic API key in your environment variables. Or, alternatively, specify an Ollama model name.[/bold red]"
56 | )
57 | return
58 |
59 | # Gather context
60 | shell = get_shell()
61 | terminal_context = get_terminal_context(shell)
62 |
63 | debug(f"Retrieved shell information:\n{shell}")
64 | debug(f"Retrieved terminal context:\n{terminal_context}")
65 | debug("Sending request to LLM...")
66 |
67 | # Get response
68 | response = explain(terminal_context, args.query)
69 |
70 | console.print(response)
71 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # wut
2 |
3 | **CLI that explains the output of your last command.**
4 |
5 | Just type `wut` and an LLM will help you understand whatever's in your terminal. You'll be surprised how useful this can be. It can help you:
6 |
7 | - Understand stack traces
8 | - Decipher error codes
9 | - Fix incorrect commands
10 | - Summarize logs
11 |
12 | 
13 |
14 | ## Installation
15 |
16 | ```bash
17 | > pipx install wut-cli
18 | ```
19 |
20 |
31 |
32 | Once installed, you can use OpenAI or Claude as your LLM provider. Just add the appropriate API key to your environment:
33 |
34 | ```bash
35 | > export OPENAI_API_KEY="..."
36 | > export ANTHROPIC_API_KEY="..."
37 | ```
38 |
39 | You can also use a local model with Ollama. Just add the model name that's being served to your environment:
40 |
41 | ```bash
42 | > export OLLAMA_MODEL="..."
43 | ```
44 |
45 | If you're using OpenAI, you can customize your model and API URL by adding the following to your environment:
46 |
47 | ```bash
48 | > export OPENAI_MODEL="..." # Default to "gpt-4o"
49 | > export OPENAI_BASE_URL="..." # Default to None
50 | ```
51 |
52 | ## Usage
53 |
54 | `wut` must be used inside a `tmux` or `screen` session to capture the last command's output. To use it, just type `wut` after running a command:
55 |
56 | ```bash
57 | > git create-pr
58 | git: 'create-pr' is not a git command.
59 | > wut
60 | ```
61 |
62 | You'll quickly get a brief explanation of the issue:
63 |
64 | ```
65 | This error occurs because Git doesn't have a built-in `create-pr` command.
66 | To create a pull request, you typically need to:
67 |
68 | 1. Push your branch to the remote repository
69 | 2. Use the GitHub web interface
70 | ```
71 |
72 | If you have a _specific question_ about your last command, you can include a query:
73 |
74 | ```bash
75 | > brew install pip
76 | ...
77 | > wut "how do i add this to my PATH variable?"
78 | ```
79 |
80 | ## Roadmap
81 |
82 | 1. [If possible,](https://stackoverflow.com/questions/24283097/reusing-output-from-last-command-in-bash/75629157#75629157) drop the requirement of being inside a tmux or screen session.
83 | 2. Add a `--fix` option to automatically execute a command suggested by `wut`.
84 | 3. Add `wut` to Homebrew.
85 | 4. Make some unit tests.
86 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # System files
2 | .DS_Store
3 |
4 | # Byte-compiled / optimized / DLL files
5 | __pycache__/
6 | *.py[cod]
7 | *$py.class
8 |
9 | # C extensions
10 | *.so
11 |
12 | # Distribution / packaging
13 | .Python
14 | build/
15 | develop-eggs/
16 | dist/
17 | downloads/
18 | eggs/
19 | .eggs/
20 | lib/
21 | lib64/
22 | parts/
23 | sdist/
24 | var/
25 | wheels/
26 | share/python-wheels/
27 | *.egg-info/
28 | .installed.cfg
29 | *.egg
30 | MANIFEST
31 |
32 | # PyInstaller
33 | # Usually these files are written by a python script from a template
34 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
35 | *.manifest
36 | *.spec
37 |
38 | # Installer logs
39 | pip-log.txt
40 | pip-delete-this-directory.txt
41 |
42 | # Unit test / coverage reports
43 | htmlcov/
44 | .tox/
45 | .nox/
46 | .coverage
47 | .coverage.*
48 | .cache
49 | nosetests.xml
50 | coverage.xml
51 | *.cover
52 | *.py,cover
53 | .hypothesis/
54 | .pytest_cache/
55 | cover/
56 |
57 | # Translations
58 | *.mo
59 | *.pot
60 |
61 | # Django stuff:
62 | *.log
63 | local_settings.py
64 | db.sqlite3
65 | db.sqlite3-journal
66 |
67 | # Flask stuff:
68 | instance/
69 | .webassets-cache
70 |
71 | # Scrapy stuff:
72 | .scrapy
73 |
74 | # Sphinx documentation
75 | docs/_build/
76 |
77 | # PyBuilder
78 | .pybuilder/
79 | target/
80 |
81 | # Jupyter Notebook
82 | .ipynb_checkpoints
83 |
84 | # IPython
85 | profile_default/
86 | ipython_config.py
87 |
88 | # pyenv
89 | # For a library or package, you might want to ignore these files since the code is
90 | # intended to run in multiple environments; otherwise, check them in:
91 | # .python-version
92 |
93 | # pipenv
94 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
95 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
96 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
97 | # install all needed dependencies.
98 | #Pipfile.lock
99 |
100 | # poetry
101 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
102 | # This is especially recommended for binary packages to ensure reproducibility, and is more
103 | # commonly ignored for libraries.
104 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
105 | #poetry.lock
106 |
107 | # pdm
108 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
109 | #pdm.lock
110 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
111 | # in version control.
112 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
113 | .pdm.toml
114 | .pdm-python
115 | .pdm-build/
116 |
117 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
118 | __pypackages__/
119 |
120 | # Celery stuff
121 | celerybeat-schedule
122 | celerybeat.pid
123 |
124 | # SageMath parsed files
125 | *.sage.py
126 |
127 | # Environments
128 | .env
129 | .venv
130 | env/
131 | venv/
132 | ENV/
133 | env.bak/
134 | venv.bak/
135 |
136 | # Spyder project settings
137 | .spyderproject
138 | .spyproject
139 |
140 | # Rope project settings
141 | .ropeproject
142 |
143 | # mkdocs documentation
144 | /site
145 |
146 | # mypy
147 | .mypy_cache/
148 | .dmypy.json
149 | dmypy.json
150 |
151 | # Pyre type checker
152 | .pyre/
153 |
154 | # pytype static type analyzer
155 | .pytype/
156 |
157 | # Cython debug symbols
158 | cython_debug/
159 |
160 | # PyCharm
161 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
162 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
163 | # and can be added to the global gitignore or merged into this file. For a more nuclear
164 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
165 | #.idea/
166 |
--------------------------------------------------------------------------------
/wut/utils.py:
--------------------------------------------------------------------------------
1 | # Standard library
2 | import os
3 | import tempfile
4 | from collections import namedtuple
5 | from subprocess import check_output, run, CalledProcessError, DEVNULL
6 | from typing import List, Optional, Tuple
7 |
8 | # Third party
9 | from ollama import chat
10 | from psutil import Process
11 | from openai import OpenAI
12 | from anthropic import Anthropic
13 | from rich.markdown import Markdown
14 |
15 | # Local
16 | from wut.prompts import EXPLAIN_PROMPT, ANSWER_PROMPT
17 |
18 | # from prompts import EXPLAIN_PROMPT, ANSWER_PROMPT
19 |
20 | MAX_CHARS = 10000
21 | MAX_COMMANDS = 3
22 | SHELLS = ["bash", "fish", "zsh", "csh", "tcsh", "powershell", "pwsh"]
23 |
24 | Shell = namedtuple("Shell", ["path", "name", "prompt"])
25 | Command = namedtuple("Command", ["text", "output"])
26 |
27 |
28 | #########
29 | # HELPERS
30 | #########
31 |
32 |
33 | def count_chars(text: str) -> int:
34 | return len(text)
35 |
36 |
37 | def truncate_chars(text: str, reverse: bool = False) -> str:
38 | return text[-MAX_CHARS:] if reverse else text[:MAX_CHARS]
39 |
40 |
41 | def get_shell_name(shell_path: Optional[str] = None) -> Optional[str]:
42 | if not shell_path:
43 | return None
44 |
45 | if os.path.splitext(shell_path)[-1].lower() in SHELLS:
46 | return os.path.splitext(shell_path)[-1].lower()
47 |
48 | if os.path.splitext(shell_path)[0].lower() in SHELLS:
49 | return os.path.splitext(shell_path)[0].lower()
50 |
51 | if shell_path.lower() in SHELLS:
52 | return shell_path.lower()
53 |
54 | return None
55 |
56 |
57 | def get_shell_name_and_path() -> Tuple[Optional[str], Optional[str]]:
58 | path = os.environ.get("SHELL", None) or os.environ.get("TF_SHELL", None)
59 | if shell_name := get_shell_name(path):
60 | return shell_name, path
61 |
62 | proc = Process(os.getpid())
63 | while proc is not None and proc.pid > 0:
64 | try:
65 | _path = proc.name()
66 | except TypeError:
67 | _path = proc.name
68 |
69 | if shell_name := get_shell_name(_path):
70 | return shell_name, _path
71 |
72 | try:
73 | proc = proc.parent()
74 | except TypeError:
75 | proc = proc.parent
76 |
77 | return None, path
78 |
79 |
80 | def get_shell_prompt(shell_name: str, shell_path: str) -> Optional[str]:
81 | shell_prompt = None
82 | try:
83 | if shell_name == "zsh":
84 | cmd = [
85 | shell_path,
86 | # "-i",
87 | "-c",
88 | "print -P $PS1",
89 | ]
90 | shell_prompt = check_output(cmd, text=True, stderr=DEVNULL)
91 | elif shell_name == "bash":
92 | # Uses parameter transformation; only supported in Bash 4.4+
93 | cmd = [
94 | # shell_path,
95 | "echo",
96 | '"${PS1@P}"',
97 | ]
98 | shell_prompt = check_output(cmd, text=True, stderr=DEVNULL)
99 | if shell_prompt.strip() == '"${PS1@P}"':
100 | return None
101 | elif shell_name == "fish":
102 | cmd = [shell_path, "fish_prompt"]
103 | shell_prompt = check_output(cmd, text=True, stderr=DEVNULL)
104 | elif shell_name in ["csh", "tcsh"]:
105 | cmd = [shell_path, "-c", "echo $prompt"]
106 | shell_prompt = check_output(cmd, text=True, stderr=DEVNULL)
107 | elif shell_name in ["pwsh", "powershell"]:
108 | cmd = [shell_path, "-c", "Write-Host $prompt"]
109 | shell_prompt = check_output(cmd, text=True, stderr=DEVNULL)
110 | except:
111 | shell_prompt = None
112 |
113 | return shell_prompt.strip() if shell_prompt else None
114 |
115 |
116 | def get_pane_output() -> str:
117 | output_file = None
118 | output = ""
119 | try:
120 | with tempfile.NamedTemporaryFile(delete=False) as temp_file:
121 | output_file = temp_file.name
122 |
123 | if os.getenv("TMUX"): # tmux session
124 | cmd = [
125 | "tmux",
126 | "capture-pane",
127 | "-p",
128 | "-S",
129 | # f"-{MAX_HISTORY_LINES}",
130 | "-",
131 | ]
132 | with open(output_file, "w") as f:
133 | run(cmd, stdout=f, text=True)
134 | elif os.getenv("STY"): # screen session
135 | cmd = ["screen", "-X", "hardcopy", "-h", output_file]
136 | check_output(cmd, text=True)
137 | else:
138 | return ""
139 |
140 | with open(output_file, "r", encoding="utf-8", errors="replace") as f:
141 | output = f.read()
142 | except CalledProcessError as e:
143 | pass
144 |
145 | if output_file:
146 | os.remove(output_file)
147 |
148 | return output
149 |
150 |
151 | def get_commands(pane_output: str, shell: Shell) -> List[Command]:
152 | # TODO: Handle edge cases. E.g. if you change the shell prompt in the middle of a session,
153 | # only the latest prompt will be used to split the pane output into `Command` objects.
154 |
155 | commands = [] # Order: newest to oldest
156 | buffer = []
157 | for line in reversed(pane_output.splitlines()):
158 | if not line.strip():
159 | continue
160 |
161 | if shell.prompt.lower() in line.lower():
162 | command_text = line.split(shell.prompt, 1)[1].strip()
163 | command = Command(command_text, "\n".join(reversed(buffer)).strip())
164 | commands.append(command)
165 | buffer = []
166 | continue
167 |
168 | buffer.append(line)
169 |
170 | return commands[1:] # Exclude the wut command itself
171 |
172 |
173 | def truncate_commands(commands: List[Command]) -> List[Command]:
174 | num_chars = 0
175 | truncated_commands = []
176 | for command in commands:
177 | command_chars = count_chars(command.text)
178 | if command_chars + num_chars > MAX_CHARS:
179 | break
180 | num_chars += command_chars
181 |
182 | output = []
183 | for line in reversed(command.output.splitlines()):
184 | line_chars = count_chars(line)
185 | if line_chars + num_chars > MAX_CHARS:
186 | break
187 |
188 | output.append(line)
189 | num_chars += line_chars
190 |
191 | output = "\n".join(reversed(output))
192 | command = Command(command.text, output)
193 | truncated_commands.append(command)
194 |
195 | return truncated_commands
196 |
197 |
198 | def truncate_pane_output(output: str) -> str:
199 | hit_non_empty_line = False
200 | lines = [] # Order: newest to oldest
201 | for line in reversed(output.splitlines()):
202 | if line and line.strip():
203 | hit_non_empty_line = True
204 |
205 | if hit_non_empty_line:
206 | lines.append(line)
207 |
208 | lines = lines[1:] # Remove wut command
209 | output = "\n".join(reversed(lines))
210 | output = truncate_chars(output, reverse=True)
211 | output = output.strip()
212 |
213 | return output
214 |
215 |
216 | def command_to_string(command: Command, shell_prompt: Optional[str] = None) -> str:
217 | shell_prompt = shell_prompt if shell_prompt else "$"
218 | command_str = f"{shell_prompt} {command.text}"
219 | command_str += f"\n{command.output}" if command.output.strip() else ""
220 | return command_str
221 |
222 |
223 | def format_output(output: str) -> str:
224 | return Markdown(
225 | output,
226 | code_theme="monokai",
227 | inline_code_lexer="python",
228 | inline_code_theme="monokai",
229 | )
230 |
231 |
232 | def run_anthropic(system_message: str, user_message: str) -> str:
233 | anthropic = Anthropic()
234 | response = anthropic.messages.create(
235 | model="claude-3-5-sonnet-20241022",
236 | max_tokens=1024,
237 | system=system_message,
238 | messages=[{"role": "user", "content": user_message}],
239 | )
240 | return response.content[0].text
241 |
242 |
243 | def run_openai(system_message: str, user_message: str) -> str:
244 | openai = OpenAI(base_url=os.getenv("OPENAI_BASE_URL", None))
245 | response = openai.chat.completions.create(
246 | messages=[
247 | {"role": "system", "content": system_message},
248 | {"role": "user", "content": user_message},
249 | ],
250 | model=os.getenv("OPENAI_MODEL", None) or "gpt-4o",
251 | temperature=0.7,
252 | )
253 | return response.choices[0].message.content
254 |
255 |
256 | def run_ollama(system_message: str, user_message: str) -> str:
257 | response = chat(
258 | model=os.getenv("OLLAMA_MODEL", None),
259 | messages=[
260 | {"role": "system", "content": system_message},
261 | {"role": "user", "content": user_message},
262 | ],
263 | )
264 | return response.message.content
265 |
266 |
267 | def get_llm_provider() -> str:
268 | if os.getenv("OPENAI_API_KEY", None): # Default
269 | return "openai"
270 |
271 | if os.getenv("ANTHROPIC_API_KEY", None):
272 | return "anthropic"
273 |
274 | if os.getenv("OLLAMA_MODEL", None):
275 | return "ollama"
276 |
277 | raise ValueError("No API key found for OpenAI or Anthropic.")
278 |
279 |
280 | ######
281 | # MAIN
282 | ######
283 |
284 |
285 | def get_shell() -> Shell:
286 | name, path = get_shell_name_and_path()
287 | prompt = get_shell_prompt(name, path)
288 | return Shell(path, name, prompt) # NOTE: Could all be null values
289 |
290 |
291 | def get_terminal_context(shell: Shell) -> str:
292 | pane_output = get_pane_output()
293 | if not pane_output:
294 | return "No terminal output found."
295 |
296 | if not shell.prompt:
297 | # W/o the prompt, we can't reliably separate commands in terminal output
298 | pane_output = truncate_pane_output(pane_output)
299 | context = f"\n{pane_output}\n"
300 | else:
301 | commands = get_commands(pane_output, shell)
302 | commands = truncate_commands(commands[:MAX_COMMANDS])
303 | commands = list(reversed(commands)) # Order: Oldest to newest
304 |
305 | previous_commands = commands[:-1]
306 | last_command = commands[-1]
307 |
308 | context = "\n"
309 | context += "\n"
310 | context += "\n".join(
311 | command_to_string(c, shell.prompt) for c in previous_commands
312 | )
313 | context += "\n\n"
314 | context += "\n\n"
315 | context += command_to_string(last_command, shell.prompt)
316 | context += "\n"
317 | context += "\n"
318 |
319 | return context
320 |
321 |
322 | def build_query(context: str, query: Optional[str] = None) -> str:
323 | if not (query and query.strip()):
324 | query = "Explain the last command's output. Use the previous commands as context, if relevant, but focus on the last command."
325 |
326 | return f"{context}\n\n{query}"
327 |
328 |
329 | def explain(context: str, query: Optional[str] = None) -> str:
330 | system_message = EXPLAIN_PROMPT if not query else ANSWER_PROMPT
331 | user_message = build_query(context, query)
332 | provider = get_llm_provider()
333 |
334 | call_llm = run_openai
335 | if provider == "anthropic":
336 | call_llm = run_anthropic
337 | elif provider == "ollama":
338 | call_llm = run_ollama
339 |
340 | output = call_llm(system_message, user_message)
341 | return format_output(output)
342 |
--------------------------------------------------------------------------------
/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "afdb5b9a26c34169f3ed914da5b01f9c9c81dc43307675f6e351acf741b9ff1e"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {
8 | "python_version": "3.13"
9 | },
10 | "sources": [
11 | {
12 | "name": "pypi",
13 | "url": "https://pypi.org/simple",
14 | "verify_ssl": true
15 | }
16 | ]
17 | },
18 | "default": {
19 | "annotated-types": {
20 | "hashes": [
21 | "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53",
22 | "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"
23 | ],
24 | "markers": "python_version >= '3.8'",
25 | "version": "==0.7.0"
26 | },
27 | "anthropic": {
28 | "hashes": [
29 | "sha256:46775f65b723c078a2ac9e9de44a46db5c6a4fabeacfd165e5ea78e6817f4eff",
30 | "sha256:bf8b0ed8c8cb2c2118038f29c58099d2f99f7847296cafdaa853910bfff4edf4"
31 | ],
32 | "index": "pypi",
33 | "markers": "python_version >= '3.8'",
34 | "version": "==0.42.0"
35 | },
36 | "anyio": {
37 | "hashes": [
38 | "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48",
39 | "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352"
40 | ],
41 | "markers": "python_version >= '3.9'",
42 | "version": "==4.7.0"
43 | },
44 | "certifi": {
45 | "hashes": [
46 | "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56",
47 | "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"
48 | ],
49 | "markers": "python_version >= '3.6'",
50 | "version": "==2024.12.14"
51 | },
52 | "charset-normalizer": {
53 | "hashes": [
54 | "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621",
55 | "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6",
56 | "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8",
57 | "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912",
58 | "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c",
59 | "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b",
60 | "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d",
61 | "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d",
62 | "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95",
63 | "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e",
64 | "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565",
65 | "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64",
66 | "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab",
67 | "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be",
68 | "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e",
69 | "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907",
70 | "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0",
71 | "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2",
72 | "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62",
73 | "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62",
74 | "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23",
75 | "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc",
76 | "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284",
77 | "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca",
78 | "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455",
79 | "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858",
80 | "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b",
81 | "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594",
82 | "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc",
83 | "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db",
84 | "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b",
85 | "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea",
86 | "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6",
87 | "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920",
88 | "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749",
89 | "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7",
90 | "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd",
91 | "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99",
92 | "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242",
93 | "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee",
94 | "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129",
95 | "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2",
96 | "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51",
97 | "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee",
98 | "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8",
99 | "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b",
100 | "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613",
101 | "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742",
102 | "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe",
103 | "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3",
104 | "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5",
105 | "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631",
106 | "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7",
107 | "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15",
108 | "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c",
109 | "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea",
110 | "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417",
111 | "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250",
112 | "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88",
113 | "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca",
114 | "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa",
115 | "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99",
116 | "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149",
117 | "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41",
118 | "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574",
119 | "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0",
120 | "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f",
121 | "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d",
122 | "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654",
123 | "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3",
124 | "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19",
125 | "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90",
126 | "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578",
127 | "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9",
128 | "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1",
129 | "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51",
130 | "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719",
131 | "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236",
132 | "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a",
133 | "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c",
134 | "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade",
135 | "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944",
136 | "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc",
137 | "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6",
138 | "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6",
139 | "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27",
140 | "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6",
141 | "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2",
142 | "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12",
143 | "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf",
144 | "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114",
145 | "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7",
146 | "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf",
147 | "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d",
148 | "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b",
149 | "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed",
150 | "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03",
151 | "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4",
152 | "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67",
153 | "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365",
154 | "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a",
155 | "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748",
156 | "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b",
157 | "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079",
158 | "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"
159 | ],
160 | "markers": "python_full_version >= '3.7.0'",
161 | "version": "==3.4.0"
162 | },
163 | "distro": {
164 | "hashes": [
165 | "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed",
166 | "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"
167 | ],
168 | "markers": "python_version >= '3.6'",
169 | "version": "==1.9.0"
170 | },
171 | "h11": {
172 | "hashes": [
173 | "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d",
174 | "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"
175 | ],
176 | "markers": "python_version >= '3.7'",
177 | "version": "==0.14.0"
178 | },
179 | "httpcore": {
180 | "hashes": [
181 | "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c",
182 | "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"
183 | ],
184 | "markers": "python_version >= '3.8'",
185 | "version": "==1.0.7"
186 | },
187 | "httpx": {
188 | "hashes": [
189 | "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0",
190 | "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"
191 | ],
192 | "markers": "python_version >= '3.8'",
193 | "version": "==0.27.2"
194 | },
195 | "idna": {
196 | "hashes": [
197 | "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9",
198 | "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"
199 | ],
200 | "markers": "python_version >= '3.6'",
201 | "version": "==3.10"
202 | },
203 | "jiter": {
204 | "hashes": [
205 | "sha256:025337859077b41548bdcbabe38698bcd93cfe10b06ff66617a48ff92c9aec60",
206 | "sha256:03c9df035d4f8d647f8c210ddc2ae0728387275340668fb30d2421e17d9a0841",
207 | "sha256:08d4c92bf480e19fc3f2717c9ce2aa31dceaa9163839a311424b6862252c943e",
208 | "sha256:0cf5dfa9956d96ff2efb0f8e9c7d055904012c952539a774305aaaf3abdf3d6c",
209 | "sha256:14601dcac4889e0a1c75ccf6a0e4baf70dbc75041e51bcf8d0e9274519df6887",
210 | "sha256:180a8aea058f7535d1c84183c0362c710f4750bef66630c05f40c93c2b152a0f",
211 | "sha256:1c0dfbd1be3cbefc7510102370d86e35d1d53e5a93d48519688b1bf0f761160a",
212 | "sha256:2dd61c5afc88a4fda7d8b2cf03ae5947c6ac7516d32b7a15bf4b49569a5c076b",
213 | "sha256:317b25e98a35ffec5c67efe56a4e9970852632c810d35b34ecdd70cc0e47b3b6",
214 | "sha256:32475a42b2ea7b344069dc1e81445cfc00b9d0e3ca837f0523072432332e9f74",
215 | "sha256:37b2998606d6dadbb5ccda959a33d6a5e853252d921fec1792fc902351bb4e2c",
216 | "sha256:3ac9f578c46f22405ff7f8b1f5848fb753cc4b8377fbec8470a7dc3997ca7566",
217 | "sha256:3b94a33a241bee9e34b8481cdcaa3d5c2116f575e0226e421bed3f7a6ea71cff",
218 | "sha256:4a9220497ca0cb1fe94e3f334f65b9b5102a0b8147646118f020d8ce1de70105",
219 | "sha256:4ab9a87f3784eb0e098f84a32670cfe4a79cb6512fd8f42ae3d0709f06405d18",
220 | "sha256:5127dc1abd809431172bc3fbe8168d6b90556a30bb10acd5ded41c3cfd6f43b6",
221 | "sha256:5672a86d55416ccd214c778efccf3266b84f87b89063b582167d803246354be4",
222 | "sha256:580ccf358539153db147e40751a0b41688a5ceb275e6f3e93d91c9467f42b2e3",
223 | "sha256:58dc9bc9767a1101f4e5e22db1b652161a225874d66f0e5cb8e2c7d1c438b587",
224 | "sha256:5a90a923338531b7970abb063cfc087eebae6ef8ec8139762007188f6bc69a9f",
225 | "sha256:653cf462db4e8c41995e33d865965e79641ef45369d8a11f54cd30888b7e6ff1",
226 | "sha256:66227a2c7b575720c1871c8800d3a0122bb8ee94edb43a5685aa9aceb2782d44",
227 | "sha256:6e5337bf454abddd91bd048ce0dca5134056fc99ca0205258766db35d0a2ea43",
228 | "sha256:70bf4c43652cc294040dbb62256c83c8718370c8b93dd93d934b9a7bf6c4f53c",
229 | "sha256:711e408732d4e9a0208008e5892c2966b485c783cd2d9a681f3eb147cf36c7ef",
230 | "sha256:76e324da7b5da060287c54f2fabd3db5f76468006c811831f051942bf68c9d44",
231 | "sha256:789361ed945d8d42850f919342a8665d2dc79e7e44ca1c97cc786966a21f627a",
232 | "sha256:79aec8172b9e3c6d05fd4b219d5de1ac616bd8da934107325a6c0d0e866a21b6",
233 | "sha256:7efe4853ecd3d6110301665a5178b9856be7e2a9485f49d91aa4d737ad2ae49e",
234 | "sha256:7f22b16b35d5c1df9dfd58843ab2cd25e6bf15191f5a236bed177afade507bfc",
235 | "sha256:83c0efd80b29695058d0fd2fa8a556490dbce9804eac3e281f373bbc99045f6c",
236 | "sha256:859e8eb3507894093d01929e12e267f83b1d5f6221099d3ec976f0c995cb6bd9",
237 | "sha256:8b9931fd36ee513c26b5bf08c940b0ac875de175341cbdd4fa3be109f0492586",
238 | "sha256:8bd2a824d08d8977bb2794ea2682f898ad3d8837932e3a74937e93d62ecbb637",
239 | "sha256:8f2d5ed877f089862f4c7aacf3a542627c1496f972a34d0474ce85ee7d939c27",
240 | "sha256:8ffc86ae5e3e6a93765d49d1ab47b6075a9c978a2b3b80f0f32628f39caa0c88",
241 | "sha256:92249669925bc1c54fcd2ec73f70f2c1d6a817928480ee1c65af5f6b81cdf12d",
242 | "sha256:99d9a1eded738299ba8e106c6779ce5c3893cffa0e32e4485d680588adae6db8",
243 | "sha256:9c63eaef32b7bebac8ebebf4dabebdbc6769a09c127294db6babee38e9f405b9",
244 | "sha256:9e1fa156ee9454642adb7e7234a383884452532bc9d53d5af2d18d98ada1d79c",
245 | "sha256:a2ecaa3c23e7a7cf86d00eda3390c232f4d533cd9ddea4b04f5d0644faf642c5",
246 | "sha256:a6c710d657c8d1d2adbbb5c0b0c6bfcec28fd35bd6b5f016395f9ac43e878a15",
247 | "sha256:a9584de0cd306072635fe4b89742bf26feae858a0683b399ad0c2509011b9dc0",
248 | "sha256:ab7f43235d71e03b941c1630f4b6e3055d46b6cb8728a17663eaac9d8e83a865",
249 | "sha256:af102d3372e917cffce49b521e4c32c497515119dc7bd8a75665e90a718bbf08",
250 | "sha256:b25bd626bde7fb51534190c7e3cb97cee89ee76b76d7585580e22f34f5e3f393",
251 | "sha256:b2dd880785088ff2ad21ffee205e58a8c1ddabc63612444ae41e5e4b321b39c0",
252 | "sha256:b426f72cd77da3fec300ed3bc990895e2dd6b49e3bfe6c438592a3ba660e41ca",
253 | "sha256:ba5bdf56969cad2019d4e8ffd3f879b5fdc792624129741d3d83fc832fef8c7d",
254 | "sha256:bf55846c7b7a680eebaf9c3c48d630e1bf51bdf76c68a5f654b8524335b0ad29",
255 | "sha256:ca1f08b8e43dc3bd0594c992fb1fd2f7ce87f7bf0d44358198d6da8034afdf84",
256 | "sha256:ca29b6371ebc40e496995c94b988a101b9fbbed48a51190a4461fcb0a68b4a36",
257 | "sha256:ca8577f6a413abe29b079bc30f907894d7eb07a865c4df69475e868d73e71c7b",
258 | "sha256:cadcc978f82397d515bb2683fc0d50103acff2a180552654bb92d6045dec2c49",
259 | "sha256:cd646c827b4f85ef4a78e4e58f4f5854fae0caf3db91b59f0d73731448a970c6",
260 | "sha256:cd73d3e740666d0e639f678adb176fad25c1bcbdae88d8d7b857e1783bb4212d",
261 | "sha256:cde031d8413842a1e7501e9129b8e676e62a657f8ec8166e18a70d94d4682855",
262 | "sha256:ce0820f4a3a59ddced7fce696d86a096d5cc48d32a4183483a17671a61edfddc",
263 | "sha256:d20be8b7f606df096e08b0b1b4a3c6f0515e8dac296881fe7461dfa0fb5ec817",
264 | "sha256:d21974d246ed0181558087cd9f76e84e8321091ebfb3a93d4c341479a736f099",
265 | "sha256:d33f94615fcaf872f7fd8cd98ac3b429e435c77619777e8a449d9d27e01134d1",
266 | "sha256:d35c864c2dff13dfd79fb070fc4fc6235d7b9b359efe340e1261deb21b9fcb66",
267 | "sha256:d5c826a221851a8dc028eb6d7d6429ba03184fa3c7e83ae01cd6d3bd1d4bd17d",
268 | "sha256:e41e75344acef3fc59ba4765df29f107f309ca9e8eace5baacabd9217e52a5ee",
269 | "sha256:e52bf98c7e727dd44f7c4acb980cb988448faeafed8433c867888268899b298b",
270 | "sha256:e6ec2be506e7d6f9527dae9ff4b7f54e68ea44a0ef6b098256ddf895218a2f8f",
271 | "sha256:e725edd0929fa79f8349ab4ec7f81c714df51dc4e991539a578e5018fa4a7152",
272 | "sha256:eaa58399c01db555346647a907b4ef6d4f584b123943be6ed5588c3f2359c9f4",
273 | "sha256:eb21aaa9a200d0a80dacc7a81038d2e476ffe473ffdd9c91eb745d623561de05",
274 | "sha256:ecff0dc14f409599bbcafa7e470c00b80f17abc14d1405d38ab02e4b42e55b57",
275 | "sha256:f557c55bc2b7676e74d39d19bcb8775ca295c7a028246175d6a8b431e70835e5",
276 | "sha256:f7200b8f7619d36aa51c803fd52020a2dfbea36ffec1b5e22cab11fd34d95a6d",
277 | "sha256:f9d471356dc16f84ed48768b8ee79f29514295c7295cb41e1133ec0b2b8d637d",
278 | "sha256:fc5adda618205bd4678b146612ce44c3cbfdee9697951f2c0ffdef1f26d72b63",
279 | "sha256:fc9043259ee430ecd71d178fccabd8c332a3bf1e81e50cae43cc2b28d19e4cb7",
280 | "sha256:ffd9fee7d0775ebaba131f7ca2e2d83839a62ad65e8e02fe2bd8fc975cedeb9e"
281 | ],
282 | "markers": "python_version >= '3.8'",
283 | "version": "==0.8.2"
284 | },
285 | "markdown-it-py": {
286 | "hashes": [
287 | "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1",
288 | "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"
289 | ],
290 | "markers": "python_version >= '3.8'",
291 | "version": "==3.0.0"
292 | },
293 | "mdurl": {
294 | "hashes": [
295 | "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8",
296 | "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"
297 | ],
298 | "markers": "python_version >= '3.7'",
299 | "version": "==0.1.2"
300 | },
301 | "ollama": {
302 | "hashes": [
303 | "sha256:0f466e845e2205a1cbf5a2fef4640027b90beaa3b06c574426d8b6b17fd6e139",
304 | "sha256:e1db064273c739babc2dde9ea84029c4a43415354741b6c50939ddd3dd0f7ffb"
305 | ],
306 | "index": "pypi",
307 | "markers": "python_version >= '3.8' and python_version < '4.0'",
308 | "version": "==0.4.4"
309 | },
310 | "openai": {
311 | "hashes": [
312 | "sha256:e2910b1170a6b7f88ef491ac3a42c387f08bd3db533411f7ee391d166571d63c",
313 | "sha256:f5a035fd01e141fc743f4b0e02c41ca49be8fab0866d3b67f5f29b4f4d3c0973"
314 | ],
315 | "index": "pypi",
316 | "markers": "python_version >= '3.8'",
317 | "version": "==1.58.1"
318 | },
319 | "psutil": {
320 | "hashes": [
321 | "sha256:018aeae2af92d943fdf1da6b58665124897cfc94faa2ca92098838f83e1b1bca",
322 | "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377",
323 | "sha256:1924e659d6c19c647e763e78670a05dbb7feaf44a0e9c94bf9e14dfc6ba50468",
324 | "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3",
325 | "sha256:384636b1a64b47814437d1173be1427a7c83681b17a450bfc309a1953e329603",
326 | "sha256:6d4281f5bbca041e2292be3380ec56a9413b790579b8e593b1784499d0005dac",
327 | "sha256:8be07491f6ebe1a693f17d4f11e69d0dc1811fa082736500f649f79df7735303",
328 | "sha256:8df0178ba8a9e5bc84fed9cfa61d54601b371fbec5c8eebad27575f1e105c0d4",
329 | "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160",
330 | "sha256:9ccc4316f24409159897799b83004cb1e24f9819b0dcf9c0b68bdcb6cefee6a8",
331 | "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003",
332 | "sha256:c777eb75bb33c47377c9af68f30e9f11bc78e0f07fbf907be4a5d70b2fe5f030",
333 | "sha256:ca9609c77ea3b8481ab005da74ed894035936223422dc591d6772b147421f777",
334 | "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5",
335 | "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53",
336 | "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649",
337 | "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8"
338 | ],
339 | "index": "pypi",
340 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
341 | "version": "==6.1.1"
342 | },
343 | "pydantic": {
344 | "hashes": [
345 | "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d",
346 | "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06"
347 | ],
348 | "markers": "python_version >= '3.8'",
349 | "version": "==2.10.4"
350 | },
351 | "pydantic-core": {
352 | "hashes": [
353 | "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278",
354 | "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50",
355 | "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9",
356 | "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f",
357 | "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6",
358 | "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc",
359 | "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54",
360 | "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630",
361 | "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9",
362 | "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236",
363 | "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7",
364 | "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee",
365 | "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b",
366 | "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048",
367 | "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc",
368 | "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130",
369 | "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4",
370 | "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd",
371 | "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4",
372 | "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7",
373 | "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7",
374 | "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4",
375 | "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e",
376 | "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa",
377 | "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6",
378 | "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962",
379 | "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b",
380 | "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f",
381 | "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474",
382 | "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5",
383 | "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459",
384 | "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf",
385 | "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a",
386 | "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c",
387 | "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76",
388 | "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362",
389 | "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4",
390 | "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934",
391 | "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320",
392 | "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118",
393 | "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96",
394 | "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306",
395 | "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046",
396 | "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3",
397 | "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2",
398 | "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af",
399 | "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9",
400 | "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67",
401 | "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a",
402 | "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27",
403 | "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35",
404 | "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b",
405 | "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151",
406 | "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b",
407 | "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154",
408 | "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133",
409 | "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef",
410 | "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145",
411 | "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15",
412 | "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4",
413 | "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc",
414 | "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee",
415 | "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c",
416 | "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0",
417 | "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5",
418 | "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57",
419 | "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b",
420 | "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8",
421 | "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1",
422 | "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da",
423 | "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e",
424 | "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc",
425 | "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993",
426 | "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656",
427 | "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4",
428 | "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c",
429 | "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb",
430 | "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d",
431 | "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9",
432 | "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e",
433 | "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1",
434 | "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc",
435 | "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a",
436 | "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9",
437 | "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506",
438 | "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b",
439 | "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1",
440 | "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d",
441 | "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99",
442 | "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3",
443 | "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31",
444 | "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c",
445 | "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39",
446 | "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a",
447 | "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308",
448 | "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2",
449 | "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228",
450 | "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b",
451 | "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9",
452 | "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"
453 | ],
454 | "markers": "python_version >= '3.8'",
455 | "version": "==2.27.2"
456 | },
457 | "pygments": {
458 | "hashes": [
459 | "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199",
460 | "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"
461 | ],
462 | "markers": "python_version >= '3.8'",
463 | "version": "==2.18.0"
464 | },
465 | "regex": {
466 | "hashes": [
467 | "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0",
468 | "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519",
469 | "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"
470 | ],
471 | "markers": "python_version >= '3.8'",
472 | "version": "==2024.11.6"
473 | },
474 | "requests": {
475 | "hashes": [
476 | "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760",
477 | "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"
478 | ],
479 | "markers": "python_version >= '3.8'",
480 | "version": "==2.32.3"
481 | },
482 | "rich": {
483 | "hashes": [
484 | "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098",
485 | "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"
486 | ],
487 | "index": "pypi",
488 | "markers": "python_full_version >= '3.8.0'",
489 | "version": "==13.9.4"
490 | },
491 | "sniffio": {
492 | "hashes": [
493 | "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2",
494 | "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"
495 | ],
496 | "markers": "python_version >= '3.7'",
497 | "version": "==1.3.1"
498 | },
499 | "tiktoken": {
500 | "hashes": [
501 | "sha256:02be1666096aff7da6cbd7cdaa8e7917bfed3467cd64b38b1f112e96d3b06a24",
502 | "sha256:1473cfe584252dc3fa62adceb5b1c763c1874e04511b197da4e6de51d6ce5a02",
503 | "sha256:18228d624807d66c87acd8f25fc135665617cab220671eb65b50f5d70fa51f69",
504 | "sha256:25e13f37bc4ef2d012731e93e0fef21dc3b7aea5bb9009618de9a4026844e560",
505 | "sha256:294440d21a2a51e12d4238e68a5972095534fe9878be57d905c476017bff99fc",
506 | "sha256:2efaf6199717b4485031b4d6edb94075e4d79177a172f38dd934d911b588d54a",
507 | "sha256:326624128590def898775b722ccc327e90b073714227175ea8febbc920ac0a99",
508 | "sha256:4177faa809bd55f699e88c96d9bb4635d22e3f59d635ba6fd9ffedf7150b9953",
509 | "sha256:5376b6f8dc4753cd81ead935c5f518fa0fbe7e133d9e25f648d8c4dabdd4bad7",
510 | "sha256:5637e425ce1fc49cf716d88df3092048359a4b3bbb7da762840426e937ada06d",
511 | "sha256:56edfefe896c8f10aba372ab5706b9e3558e78db39dd497c940b47bf228bc419",
512 | "sha256:6adc8323016d7758d6de7313527f755b0fc6c72985b7d9291be5d96d73ecd1e1",
513 | "sha256:6b231f5e8982c245ee3065cd84a4712d64692348bc609d84467c57b4b72dcbc5",
514 | "sha256:6b2ddbc79a22621ce8b1166afa9f9a888a664a579350dc7c09346a3b5de837d9",
515 | "sha256:7e17807445f0cf1f25771c9d86496bd8b5c376f7419912519699f3cc4dc5c12e",
516 | "sha256:845287b9798e476b4d762c3ebda5102be87ca26e5d2c9854002825d60cdb815d",
517 | "sha256:881839cfeae051b3628d9823b2e56b5cc93a9e2efb435f4cf15f17dc45f21586",
518 | "sha256:886f80bd339578bbdba6ed6d0567a0d5c6cfe198d9e587ba6c447654c65b8edc",
519 | "sha256:9269348cb650726f44dd3bbb3f9110ac19a8dcc8f54949ad3ef652ca22a38e21",
520 | "sha256:9a58deb7075d5b69237a3ff4bb51a726670419db6ea62bdcd8bd80c78497d7ab",
521 | "sha256:9ccbb2740f24542534369c5635cfd9b2b3c2490754a78ac8831d99f89f94eeb2",
522 | "sha256:9fb0e352d1dbe15aba082883058b3cce9e48d33101bdaac1eccf66424feb5b47",
523 | "sha256:b07e33283463089c81ef1467180e3e00ab00d46c2c4bbcef0acab5f771d6695e",
524 | "sha256:b591fb2b30d6a72121a80be24ec7a0e9eb51c5500ddc7e4c2496516dd5e3816b",
525 | "sha256:c94ff53c5c74b535b2cbf431d907fc13c678bbd009ee633a2aca269a04389f9a",
526 | "sha256:d2908c0d043a7d03ebd80347266b0e58440bdef5564f84f4d29fb235b5df3b04",
527 | "sha256:d622d8011e6d6f239297efa42a2657043aaed06c4f68833550cac9e9bc723ef1",
528 | "sha256:d8c2d0e5ba6453a290b86cd65fc51fedf247e1ba170191715b049dac1f628005",
529 | "sha256:d8f3192733ac4d77977432947d563d7e1b310b96497acd3c196c9bddb36ed9db",
530 | "sha256:f13d13c981511331eac0d01a59b5df7c0d4060a8be1e378672822213da51e0a2",
531 | "sha256:fe9399bdc3f29d428f16a2f86c3c8ec20be3eac5f53693ce4980371c3245729b"
532 | ],
533 | "index": "pypi",
534 | "markers": "python_version >= '3.9'",
535 | "version": "==0.8.0"
536 | },
537 | "tqdm": {
538 | "hashes": [
539 | "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2",
540 | "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"
541 | ],
542 | "markers": "python_version >= '3.7'",
543 | "version": "==4.67.1"
544 | },
545 | "typing-extensions": {
546 | "hashes": [
547 | "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d",
548 | "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"
549 | ],
550 | "markers": "python_version >= '3.8'",
551 | "version": "==4.12.2"
552 | },
553 | "urllib3": {
554 | "hashes": [
555 | "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac",
556 | "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"
557 | ],
558 | "markers": "python_version >= '3.8'",
559 | "version": "==2.2.3"
560 | }
561 | },
562 | "develop": {}
563 | }
564 |
--------------------------------------------------------------------------------